server-1.12/server/timers.c

169 lines
4.7 KiB
C

/*
CrossFire, A Multiplayer game for X-windows
Copyright (C) 2001-2007 Yann Chachkoff & Crossfire Development Team
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., 675 Mass Ave, Cambridge, MA 02139, USA.
The authors can be reached via e-mail at crossfire-devel@real-time.com
*/
/**
* @file
* This handles custom timers. See @ref page_timers.
*
* @page page_timers Custom timers
*
* It is possible, through the functions in the @ref timers.c file, to create
* custom timers that get activated after some specified time.
*
* A timer is associated to a specific ::object, and is given a delay, either
* in server ticks or in seconds. When the delay expires, and if the item still
* is valid, an ::EVENT_TIMER is generated for the specific object. Actual handling
* is thus delegated to plugins.
*
* Note that timers are one shot only, they reset after they activate.
*/
#include <timers.h>
#ifndef __CEXTRACT__
#include <sproto.h>
#endif
/* Extern in header. */
cftimer timers_table[MAX_TIMERS];
static void cftimer_process_event(tag_t ob_tag);
/**
* Processes all timers.
*/
void cftimer_process_timers(void) {
int i;
for (i = 0; i < MAX_TIMERS; i++) {
if (timers_table[i].mode == TIMER_MODE_CYCLES) {
timers_table[i].delay--;
if (timers_table[i].delay == 0) {
/* Call object timer event */
timers_table[i].mode = TIMER_MODE_DEAD;
cftimer_process_event(timers_table[i].ob_tag);
}
} else if (timers_table[i].mode == TIMER_MODE_SECONDS) {
if (timers_table[i].delay <= seconds()) {
/* Call object timer event */
timers_table[i].mode = TIMER_MODE_DEAD;
cftimer_process_event(timers_table[i].ob_tag);
}
}
}
}
/**
* Triggers the ::EVENT_TIMER of the given object.
*
* @param ob_tag
* object tag to use.
*/
static void cftimer_process_event(tag_t ob_tag) {
object *ob = find_object(ob_tag);
if (ob)
execute_event(ob, EVENT_TIMER, NULL, NULL, NULL, SCRIPT_FIX_ALL);
}
/**
* Creates a new timer.
* @param id
* desired timer identifier.
* @param delay
* desired timer delay.
* @param ob
* object that will be linked to this timer. Should have an ::EVENT_TIMER handler.
* @param mode
* unit for delay, should be ::TIMER_MODE_SECONDS or ::TIMER_MODE_CYCLES. See timers.h.
* @retval ::TIMER_ERR_NONE
* timer was successfully created.
* @retval ::TIMER_ERR_ID
* invalid ID.
* @retval ::TIMER_ERR_MODE
* invalid mode.
* @retval ::TIMER_ERR_OBJ
* ob is NULL or has no ::EVENT_TIMER handler.
*/
int cftimer_create(int id, long delay, object *ob, int mode) {
if (id >= MAX_TIMERS)
return TIMER_ERR_ID;
if (id < 0)
return TIMER_ERR_ID;
if (timers_table[id].mode != TIMER_MODE_DEAD)
return TIMER_ERR_ID;
if ((mode != TIMER_MODE_SECONDS) && (mode != TIMER_MODE_CYCLES))
return TIMER_ERR_MODE;
if (ob == NULL)
return TIMER_ERR_OBJ;
if (find_obj_by_type_subtype(ob, EVENT_CONNECTOR, EVENT_TIMER) == NULL)
return TIMER_ERR_OBJ;
timers_table[id].mode = mode;
timers_table[id].ob_tag = ob->count;
if (mode == TIMER_MODE_CYCLES)
timers_table[id].delay = delay;
else
timers_table[id].delay = seconds()+delay;
return TIMER_ERR_NONE;
}
/**
* Destroys an existing timer.
* @param id
* identifier of the timer to destroy.
* @retval ::TIMER_ERR_NONE
* no problem encountered.
* @retval ::TIMER_ERR_ID
* unknown id - timer not found or invalid.
*/
int cftimer_destroy(int id) {
if (id >= MAX_TIMERS)
return TIMER_ERR_ID;
if (id < 0)
return TIMER_ERR_ID;
timers_table[id].mode = TIMER_MODE_DEAD;
return TIMER_ERR_NONE;
}
/**
* Finds a free ID for a new timer.
* @retval ::TIMER_ERR_ID
* no free ID available.
* @retval >0
* an available ID.
*/
int cftimer_find_free_id(void) {
int i;
for (i = 0; i < MAX_TIMERS; i++) {
if (timers_table[i].mode == TIMER_MODE_DEAD)
return i;
}
return TIMER_ERR_ID;
}
/**
* Initialize timers.
*/
void cftimer_init(void) {
memset(&timers_table[0], 0, sizeof(cftimer)*MAX_TIMERS);
}