Well, worst case scenario i can just write a program to convert vanilla HL maps to the new format. The existing interfaces aren't that complex, and the lack of more powerful entities means you'll usually have a 1:1 mapping of features. For example, making all monsters hostile by default would require the keyvalue "Is Player Ally" to be set to true. For scientists, Barneys and Op4 grunts that's easy enough to do.
I'd use component based design for reusable code. As the principle goes, prefer composition over inheritance. Schedules and tasks could be components as well. You'd have an interface like this:
class CSchedule
{
public:
CSchedule( const char* const pszName )
: m_pszName( pszName ) //Could be ALLOC_STRING'd here if dynamic creation is needed (e.g. Angelscript)
{
}
const char* GetName() const { return m_pszName; }
virtual int InterruptMask( CBaseMonster& monster ) const = 0;
virtual int GetSoundMask( CBaseMonster& monster ) const = 0;
virtual size_t GetNumTasks() const = 0;
virtual void StartTask( CBaseMonster& monster ) = 0;
virtual void RunTask( CBaseMonster& monster ) = 0;
private:
const char* m_pszName;
};
Obviously just a quick concept, but it would allow a given schedule to be defined entirely in 1 place. Monster specific schedules can cast their monster type to a specific one, providing identical power to the current version.
By providing the monster for the interrupt and sound masks, the results can be decided based on current conditions. That's potentially very powerful (e.g. stealth mechanics where the monster can't see the player -> don't interrupt).
You'd then only have to put these schedules into an array or hash map to use them. Name lookups or special schedule ID assignments could mimic current GetScheduleOfType behavior. It would also reduce the size of the monster classes themselves, and if specific properties are made components as well (e.g. Alien Slave beams), you could make entire attack modes into components as well. You'd almost have Lego block like monster building potential.
The only issue i see with this is memory usage. The engine doesn't like to share access to its memory allocator so you're stuck with the default heap. That's a few dozen megabytes you can't make use of. Add to that the 34 or so megabytes that are wasted for both the client and server secure library code (which is obsolete), assuming it's compiled into the libraries, and you've easily lost ~100 MB worth of space you could be using for this. Then again, considering some modern game engines use component based design, it might be just fine.