123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- /* GCSx
- ** ENTITY.H
- **
- ** Entity support (instance of a script) (no edit-specific version)
- ** Includes bytecode interpreter
- */
- /*****************************************************************************
- ** Copyright (C) 2003-2006 Janson
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
- #ifndef __GCSx_ENTITY_H_
- #define __GCSx_ENTITY_H_
- // Intentionally kept as simple and fast as possible-
- // no virtual table, some inline property sets
- class Entity {
- public:
- enum {
- DEFAULT_PRIORITY = 100
- };
-
- // Scripting-accessible properties
- enum {
- // Name of entity (not required/not unique/LOWERCASE)
- PROP_NAME = 0,
- // Linked to a sprite
- PROP_SPRITE,
- // User-assigned priority- lower runs first (equal-
- // oldest ie lowest ID runs first)
- PROP_PRIORITY,
- PROP_LAST
- };
- RunData varTable[PROP_LAST];
-
- protected:
- // World pointer not included, but will add if needed
- // Numeric ID- computer-generated- unique to world- nonzero
- int id;
- // As long as positive, object must NOT delete itself
- // unless game is unloading. (variable references)
- int ref;
-
- // Active entities lock resources, etc.
- int active;
- int scriptLocked;
- void activateResource();
- void deactivateResource();
-
- friend struct ltEntity;
-
- // Script, Ptr not owned by us
- class Script* script;
-
- // Runtime details
- // Status- uninit = never ran, stopped = has run (init completed) but stopped
- // init/active/idle = can't unlock script as it's in use (init means in init stage)
- enum {
- RUN_UNINIT = 0,
- RUN_STOPPED,
- RUN_INIT,
- RUN_ACTIVE,
- RUN_IDLE,
- };
- int runStatus;
- int scriptType;
- Stack stack;
- // i = instruction pointer; NULL = stopped
- Uint32* i;
- // Position of first non-local on stack
- Uint32 endOfLocals;
-
- // Wipe entire stack, including locals
- void wipeStack();
-
- public:
- // Id must be unique; use ID of 0 if we're going to load/create anyways
- // Can also use ID of 0 for internal temporaries, etc.
- Entity(int myId = 0);
- ~Entity();
- // Active entities use resources; inactive do not (similar to locking
- // but no count is incremented- this is on or off only) Sprite is
- // specifically not affected by us, assumed handled elsewhere
- // Inactive resources that were mid-execution, however, retain locks
- void setActive();
- void setInactive();
-
- // Sets
- void setName(const std::string& newName) {
- *((std::string*)varTable[PROP_NAME].p) = newName;
- toLower(*((std::string*)varTable[PROP_NAME].p));
- }
- void setSprite(class Sprite* newSprite);
- // (starts new script at beginning as soon as active)
- // Even if same script, still restarts script
- void setScript(class Script* newScript);
-
- // Accessors
- int getId() const { return id; }
- int getScriptType() const { return scriptType; }
- const std::string* getName() const { return (std::string*)varTable[PROP_NAME].p; }
- class Script* getScript() const { return script; }
-
- #ifdef INTERPRETASSERT
- // Only used when debugging is enabled
- Uint32 getEndOfLocals() const { return endOfLocals; }
- #endif
-
- // Run one "cycle" IF active
- // 100% UNSAFE for threading- uses global/static vars for speed
- void cycle();
- // Only interpreter functions that access protected fields go here
- static void op_init();
- static void op_stop();
- static void op_ret();
- static void op_retvoid();
- static void op_debug();
- static void op_idle();
- static void seRefEntity(StackEntry* s) {
- interpretAssert(s->type == STACK_ENTITY);
- if (s->data.p) ++(((Entity*)s->data.p)->ref);
- }
- static void seDerefEntity(StackEntry* s) {
- interpretAssert(s->type == STACK_ENTITY);
- if (s->data.p) --(((Entity*)s->data.p)->ref);
- }
- };
- // For ordering entities in priority queue
- // @TODO: order on scripttype also?
- // @TODO: ensure reordering done on changing priority/scripttype
- struct ltEntity {
- bool operator() (const Entity* s1, const Entity* s2) const {
- return (s1->varTable[Entity::PROP_PRIORITY].i < s2->varTable[Entity::PROP_PRIORITY].i) ||
- ((s1->varTable[Entity::PROP_PRIORITY].i == s2->varTable[Entity::PROP_PRIORITY].i) &&
- (s1->id < s2->id));
- }
- };
- // Multimap for names- 1) names are not unique 2) sorted iteration is necessary
- typedef std::multimap<const char*, Entity*, map_ltstr> EntityMap;
- // Hash for IDs- 1) as fast as possible 2) sorted iteration handled separately
- typedef hash_map<int, Entity*, hash<int> > EntityIndex;
- // List for sorted iteration- sorted by user priority, then ID
- typedef std::set<Entity*, ltEntity> EntityOrder;
- // Call at program init
- void fillInterpreterTables();
- // Call FIRST when shutting down a game (clears references, etc.)
- void interpreterCleanup();
- #endif
|