/* function :: heartbeat() * arguments :: none * ====================================================== * This function is called once per game pulse, and it will * check the queue, and execute any pending events, which * has been enqueued to execute at this specific time. */ void heartbeat() { EVENT_DATA *event; ITERATOR Iter; /* current_bucket should be global, it is also used in enqueue_event * to figure out what bucket to place the new event in. */ current_bucket = (current_bucket + 1) % MAX_EVENT_HASH; AttachIterator(&Iter, eventqueue[current_bucket]); while ((event = (EVENT_DATA *) NextInList(&Iter)) != NULL) { /* Here we use the event->passes integer, to keep track of * how many times we have ignored this event. */ if (event->passes-- > 0) continue; /* execute event and extract if needed. We assume that all * event functions are of the following prototype * * bool event_function ( EVENT_DATA *event ); * * Any event returning TRUE is not dequeued, it is assumed * that the event has dequeued itself. */ if (!((*event->fun)(event))) dequeue_event(event); } DetachIterator(&Iter); }
void save_id_handler( ID_HANDLER *handler ) { FILE *fp; ITERATOR Iter; I_ID *id; char location[MAX_BUFFER]; mud_printf( location, "../system/%s.handler", id_handler_names[handler->type] ); if( ( fp = fopen( location, "w" ) ) == NULL ) { bug( "%s: unable to open file to write: %s", __FUNCTION__, location ); return; } fwrite_id_handler( handler, fp ); AttachIterator( &Iter, handler->free_ids ); while( ( id = (I_ID *)NextInList(&Iter) ) != NULL ) fwrite_i_id( id, fp ); DetachIterator( &Iter ); fprintf( fp, "%s\n", FILE_TERMINATOR ); fclose( fp ); return; }
/* utility */ ID_HANDLER *get_id_handler( int type ) { ID_HANDLER *handler = NULL; ITERATOR Iter; AttachIterator( &Iter, id_handlers ); while( ( handler = (ID_HANDLER *)NextInList( &Iter ) ) != NULL ) if( handler->type == type ) break; DetachIterator( &Iter ); return handler; }
/* function :: strip_event_mobile() * arguments :: the mobile and the type of event * ====================================================== * This function will dequeue all events of a given type * from the given mobile. */ void strip_event_mobile(D_MOBILE *dMob, int type) { EVENT_DATA *event; ITERATOR Iter; AttachIterator(&Iter, dMob->events); while ((event = (EVENT_DATA *) NextInList(&Iter)) != NULL) { if (event->type == type) dequeue_event(event); } DetachIterator(&Iter); }
/* function :: strip_event_socket() * arguments :: the socket and the type of event * ====================================================== * This function will dequeue all events of a given type * from the given socket. */ void strip_event_socket(D_SOCKET *dSock, int type) { EVENT_DATA *event; ITERATOR Iter; AttachIterator(&Iter, dSock->events); while ((event = (EVENT_DATA *) NextInList(&Iter)) != NULL) { if (event->type == type) dequeue_event(event); } DetachIterator(&Iter); }
static void link_exits() { D_ROOM *r, *d; //room and destination room D_EXIT *e; //the exit we're linking in the room ITERATOR iterRoom, iterExit; //iterators for rooms and exits if( room_list == NULL ) { bug( "ERROR: Global room list does not exist. Aborting game!!" ); exit(1); } AttachIterator( &iterRoom, room_list );//iterate through all the rooms in the game while( ( r = (D_ROOM*)NextInList( &iterRoom ) ) != NULL ) { if( r->exits ) { AttachIterator( &iterExit, r->exits ); //iterate through each room's exits while( ( e = (D_EXIT*)NextInList(&iterExit ) ) != NULL ) { if( e->dest ) continue;//If it's already linked, skip it if( ( d = frbv( e->destVnum ) ) == NULL ) { bug( "Error: Attempting to link exit to room that does not exist( Room: %i Exit: %s to room %i.)", r->vnum, e->name, e->destVnum ); continue; } e->dest = d; } DetachIterator( &iterExit ); } else { bug( "Error: Room created with unallocated exit list. Correcting now..." ); r->exits = AllocList(); } } DetachIterator( &iterRoom ); return; }
I_ID *check_free( ID_HANDLER *handler ) { ITERATOR Iter; I_ID *id; if( SizeOfList( handler->free_ids ) <= 0 ) return NULL; AttachIterator( &Iter, handler->free_ids ); id = NextInList( &Iter ); DetachFromList( id, handler->free_ids ); DetachIterator( &Iter ); return id; }
/* function :: event_isset_mobile() * arguments :: the mobile and the type of event * ====================================================== * This function checks to see if a given type of event * is enqueued/attached to a given mobile, and if it is, * it will return a pointer to this event. */ EVENT_DATA *event_isset_mobile(D_MOBILE *dMob, int type) { EVENT_DATA *event; ITERATOR Iter; AttachIterator(&Iter, dMob->events); while ((event = (EVENT_DATA *) NextInList(&Iter)) != NULL) { if (event->type == type) break; } DetachIterator(&Iter); return event; }
/* function :: event_isset_socket() * arguments :: the socket and the type of event * ====================================================== * This function checks to see if a given type of event * is enqueued/attached to a given socket, and if it is, * it will return a pointer to this event. */ EVENT_DATA *event_isset_socket(D_SOCKET *dSock, int type) { EVENT_DATA *event; ITERATOR Iter; AttachIterator(&Iter, dSock->events); while ((event = (EVENT_DATA *) NextInList(&Iter)) != NULL) { if (event->type == type) break; } DetachIterator(&Iter); return event; }
/* deletion */ void free_id_handler( ID_HANDLER *handler ) { I_ID *id; ITERATOR Iter; /* no other pointers to free at the moment */ DetachFromList( handler, id_handlers ); AttachIterator( &Iter, handler->free_ids ); while ( ( id = (I_ID *)NextInList(&Iter) ) == NULL ) free_i_id( id ); DetachIterator( &Iter ); free( handler ); /*free the memory alotted for the handler*/ return; }
bool event_game_tick(EVENT_DATA *event) { ITERATOR Iter; ENTITY_INSTANCE *instance; AttachIterator(&Iter, eInstances_list); while ((instance = (ENTITY_INSTANCE *) NextInList(&Iter)) != NULL) text_to_entity( instance, "Tick! The event queue is working.\r\n" ); DetachIterator(&Iter); event = alloc_event(); event->fun = &event_game_tick; event->type = EVENT_GAME_TICK; add_event_game(event, 10 * 60 * PULSES_PER_SECOND); return FALSE; }
bool event_instance_lua_callback( EVENT_DATA *event ) { ENTITY_INSTANCE *instance = (ENTITY_INSTANCE *)event->owner; ENTITY_INSTANCE *arg_entity; void *content; ITERATOR Iter; int ret, counter = 0; prep_stack( get_frame_script_path( instance->framework ), event->argument ); if( SizeOfList( event->lua_args ) > 0 ) { AttachIterator( &Iter, event->lua_args ); while( ( content = NextInList( &Iter ) ) != NULL ) { switch( tolower( event->lua_cypher[counter++] ) ) { case 's': lua_pushstring( lua_handle, (const char *)content ); break; case 'n': lua_pushnumber( lua_handle, *((int *)content) ); break; case 'i': if( ( arg_entity = get_active_instance_by_id( *((int *)content ) ) ) == NULL ) { bug( "%s: instance with ID:%d is no longer active.", __FUNCTION__, *((int *)content ) ); lua_pushnil( lua_handle ); break; } push_instance( arg_entity, lua_handle ); break; } } DetachIterator( &Iter ); } if( ( ret = lua_pcall( lua_handle, strlen( event->lua_cypher ), LUA_MULTRET, 0 ) ) ) bug( "%s: ret %d: path: %s\r\n - error message: %s.", __FUNCTION__, ret, get_frame_script_path( instance->framework ), lua_tostring( lua_handle, -1 ) ); return FALSE; }
//The world list is just a file with a line-by-line list of all the areas //in the game. void load_world() { FILE *fp; ITERATOR iter; D_AREA *area; char buf[MAX_BUFFER]; area_loader = luaL_newstate(); luaL_openlibs( area_loader ); log_string( "Loading World" ); if( ( fp = fopen( "../areas/list.are", "r" ) ) == NULL ) { log_string( "FATAL ERROR: Area List (areas/list.are) does not exist!" ); abort(); return; } while( !feof( fp ) ) { fgets( buf, MAX_BUFFER, fp ); buf[strlen(buf)-1] = '\0'; //fgets includes the newline in the read, so we kill it here. if( !strcasecmp( buf, "END" ) ) break; load_area( buf ); } fclose( fp ); link_exits(); AttachIterator( &iter, area_list ); while( ( area = (D_AREA*)NextInList( &iter ) ) != NULL ) reset_area( area ); DetachIterator( &iter ); return; }
void reset_area( D_AREA *area ) { ITERATOR it,rIt; // it = room iterator, rIt = reset iterator D_OBJ *o; D_RESET *reset; D_MOBILE *m; D_ROOM *room; AttachIterator( &it, area->rooms ); while( ( room = (D_ROOM*)NextInList( &it ) ) != NULL ) { AttachIterator( &rIt, room->resets ); while( ( reset = (D_RESET*)NextInList(&rIt) ) != NULL ) { switch( reset->type ) { default: { bug( "Invalid reset type %c.", reset->type ); break; } case 'o': case 'O': { //if the reset has already fired once we need to see if the object //is still there, if its not, make a new one. if( reset->ptr ) { //if object is still there skip this reset if( IsInList( reset->ptr, room->objects ) ) continue; } if( ( o = clone_obj( fobv( reset->vnum ) ) ) == NULL ) { bug( "Reset calls for object vnum %i which does not exist.", reset->vnum ); continue; } AttachToList( o, room->objects ); //does the reset reference any subresets (contained objects)? if( reset->nest && SizeOfList( reset->nest ) > 0 ) { } o->reset = reset; reset->ptr = o; break; } case 'm': case 'M': { if( reset->ptr ) { if( IsInList( reset->ptr, npc_list ) ) continue; } if( ( m = clone_npc( fmbv( reset->vnum ) ) ) == NULL ) { bug( "Reset calls for NPC vnum %i which does not exist.", reset->vnum ); continue; } AttachToList( m, room->mobiles ); m->npc_data->reset = reset; reset->ptr = m; break; } } } DetachIterator( &rIt ); } DetachIterator( &it ); return; }