//***************************************************************************** // // trighooks.c // // Triggers attach on to rooms, objects, and mobiles as hooks. When a hook // event occurs, all of the triggers of the right type will run. This header is // just to allow scripts to initialize the hooks into the game. The init // function here should not be touched by anything other than scripts.c // //***************************************************************************** #include "../mud.h" #include "../utils.h" #include "../hooks.h" #include "../character.h" #include "../room.h" #include "../object.h" #include "../world.h" #include "../zone.h" #include "scripts.h" #include "pychar.h" #include "pyobj.h" #include "pyroom.h" #include "pyexit.h" //***************************************************************************** // local datastructures and defines //***************************************************************************** // values for figuring out what "me" and optional variables are in gen_do_trig #define VARTYPE_CHAR 0 #define VARTYPE_OBJ 1 #define VARTYPE_ROOM 2 // used for providing additional variables to gen_do_trig that are not standard typedef struct { char *name; void *data; int type; } OPT_VAR; OPT_VAR *newOptVar(const char *name, void *data, int type) { OPT_VAR *var = malloc(sizeof(OPT_VAR)); var->name = strdupsafe(name); var->data = data; var->type = type; return var; } void deleteOptVar(OPT_VAR *var) { if(var->name) free(var->name); free(var); } //***************************************************************************** // trigger handlers //***************************************************************************** // // generalized function for setting up a dictionary and running a trigger. The // common types of variables can be supplied in the function. Additional ones // can be added in the optional list, which must be deleted after use void gen_do_trig(TRIGGER_DATA *trig, void *me, int me_type, CHAR_DATA *ch, OBJ_DATA *obj, ROOM_DATA *room, EXIT_DATA *exit, const char *command, const char *arg, LIST *optional) { // make our basic dictionary, and fill it up with these new variables PyObject *dict = restricted_script_dict(); // now, import all of our variables if(command) { PyObject *pycmd = PyString_FromString(command); PyDict_SetItemString(dict, "cmd", pycmd); Py_DECREF(pycmd); } if(arg) { PyObject *pyarg = PyString_FromString(arg); PyDict_SetItemString(dict, "arg", pyarg); Py_DECREF(pyarg); } if(ch) { PyObject *pych = charGetPyForm(ch); PyDict_SetItemString(dict, "ch", pych); Py_DECREF(pych); } if(room) { PyObject *pyroom = roomGetPyForm(room); PyDict_SetItemString(dict, "room", pyroom); Py_DECREF(pyroom); } if(obj) { PyObject *pyobj = objGetPyForm(obj); PyDict_SetItemString(dict, "obj", pyobj); Py_DECREF(pyobj); } if(exit) { PyObject *pyexit = newPyExit(exit); PyDict_SetItemString(dict, "ex", pyexit); Py_DECREF(pyexit); } // add the thing the tirgger is attached to if(me) { PyObject *pyme = NULL; switch(me_type) { case VARTYPE_CHAR: pyme = charGetPyForm(me); break; case VARTYPE_OBJ: pyme = objGetPyForm(me); break; case VARTYPE_ROOM: pyme = roomGetPyForm(me); break; } PyDict_SetItemString(dict, "me", pyme); Py_DECREF(pyme); } // now, add any optional variables if(optional) { LIST_ITERATOR *opt_i = newListIterator(optional); OPT_VAR *opt = NULL; PyObject *pyopt = NULL; ITERATE_LIST(opt, opt_i) { pyopt = NULL; switch(opt->type) { case VARTYPE_CHAR: pyopt = charGetPyForm(opt->data); break; case VARTYPE_OBJ: pyopt = objGetPyForm(opt->data); break; case VARTYPE_ROOM: pyopt = roomGetPyForm(opt->data); break; } PyDict_SetItemString(dict, opt->name, pyopt); Py_XDECREF(pyopt); } deleteListIterator(opt_i); } // run the script, then kill our dictionary triggerRun(trig, dict); Py_DECREF(dict); } // // handles all of a character's triggers void do_char_trigs(CHAR_DATA *ch, const char *type, void *thing, void *arg) { if(listSize(charGetTriggers(ch)) > 0) { // first, build a list of all our triggers of this type LIST *trigs = newList(); LIST_ITERATOR *trig_i = newListIterator(charGetTriggers(ch)); char *key = NULL; TRIGGER_DATA *trig = NULL; ITERATE_LIST(key, trig_i) { if((trig = worldGetType(gameworld, "trigger", key)) != NULL && !strcasecmp(triggerGetType(trig), type)) listPut(trigs, trig); } deleteListIterator(trig_i); // did we find any triggers? if(listSize(trigs) > 0) { trig_i = newListIterator(trigs); ITERATE_LIST(trig, trig_i) { if(!strcasecmp(type, "speech")) gen_do_trig(trig,ch,VARTYPE_CHAR,thing,NULL,NULL,NULL,NULL,arg,NULL); else if(!strcasecmp(type, "move")) gen_do_trig(trig,ch,VARTYPE_CHAR,NULL,NULL,NULL,thing,NULL,NULL,NULL); else if(!strcasecmp(type, "enter")) gen_do_trig(trig,ch,VARTYPE_CHAR,thing,NULL,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "exit")) gen_do_trig(trig,ch,VARTYPE_CHAR,thing,NULL,NULL,arg,NULL,NULL,NULL); else if(!strcasecmp(type, "greet")) gen_do_trig(trig,ch,VARTYPE_CHAR,thing,NULL,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "give")) gen_do_trig(trig,ch,VARTYPE_CHAR,thing,arg,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "receive")) gen_do_trig(trig,ch,VARTYPE_CHAR,thing,arg,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "wear")) gen_do_trig(trig,ch,VARTYPE_CHAR,NULL,thing,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "remove")) gen_do_trig(trig,ch,VARTYPE_CHAR,NULL,thing,NULL,NULL,NULL,NULL,NULL); else { log_string("Unrecognized trigger type %s attached to %s, uid %d.\r\n", type, charGetClass(ch), charGetUID(ch)); } } deleteListIterator(trig_i); } // clean up our mess deleteList(trigs); } } // // handles all of an object's triggers void do_obj_trigs(OBJ_DATA *obj, const char *type, void *thing, void *arg) { if(listSize(objGetTriggers(obj)) > 0) { // first, build a list of all our triggers of this type LIST *trigs = newList(); LIST_ITERATOR *trig_i = newListIterator(objGetTriggers(obj)); char *key = NULL; TRIGGER_DATA *trig = NULL; ITERATE_LIST(key, trig_i) { if((trig = worldGetType(gameworld, "trigger", key)) != NULL && !strcasecmp(triggerGetType(trig), type)) listPut(trigs, trig); } deleteListIterator(trig_i); // did we find any triggers? if(listSize(trigs) > 0) { trig_i = newListIterator(trigs); ITERATE_LIST(trig, trig_i) { if(!strcasecmp(type, "give")) { // set up the optional "receiver" variable LIST *opts = newList(); listPut(opts, newOptVar("recv", arg, VARTYPE_CHAR)); gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,opts); deleteListWith(opts, deleteOptVar); } else if(!strcasecmp(type, "get")) gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "drop")) gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "wear")) gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "remove")) gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "open")) gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL); else { log_string("Unrecognized trigger type %s attached to %s, uid %d.\r\n", type, objGetClass(obj), objGetUID(obj)); } } deleteListIterator(trig_i); } // clean up our mess deleteList(trigs); } } // // handles all of a room's triggers void do_room_trigs(ROOM_DATA *rm, const char *type, void *thing, void *arg){ if(listSize(roomGetTriggers(rm)) > 0) { // first, build a list of all our triggers of this type LIST *trigs = newList(); LIST_ITERATOR *trig_i = newListIterator(roomGetTriggers(rm)); char *key = NULL; TRIGGER_DATA *trig = NULL; ITERATE_LIST(key, trig_i) { if((trig = worldGetType(gameworld, "trigger", key)) != NULL && !strcasecmp(triggerGetType(trig), type)) listPut(trigs, trig); } deleteListIterator(trig_i); // did we find any triggers? if(listSize(trigs) > 0) { trig_i = newListIterator(trigs); ITERATE_LIST(trig, trig_i) { if(!strcasecmp(type, "get")) gen_do_trig(trig,rm,VARTYPE_ROOM,thing,arg,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "drop")) gen_do_trig(trig,rm,VARTYPE_ROOM,thing,arg,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "enter")) gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "exit")) gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,arg,NULL,NULL,NULL); else if(!strcasecmp(type, "speech")) gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,NULL,NULL,arg,NULL); else if(!strcasecmp(type, "reset")) gen_do_trig(trig,rm,VARTYPE_ROOM,NULL,NULL,NULL,NULL,NULL,NULL,NULL); else if(!strcasecmp(type, "open")) gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,arg,NULL,NULL,NULL); else { log_string("Unrecognized trigger type %s attached to %s, uid %d.\r\n", type, roomGetClass(rm), roomGetUID(rm)); } } deleteListIterator(trig_i); } // clean up our mess deleteList(trigs); } } //***************************************************************************** // trighooks //***************************************************************************** void do_give_trighooks(const char *info) { CHAR_DATA *ch = NULL; CHAR_DATA *recv = NULL; OBJ_DATA *obj = NULL; hookParseInfo(info, &ch, &recv, &obj); do_char_trigs(ch, "give", recv, obj); do_char_trigs(recv, "receive", ch, obj); do_obj_trigs (obj, "give", ch, recv); } void do_get_trighooks(const char *info) { CHAR_DATA *ch = NULL; OBJ_DATA *obj = NULL; hookParseInfo(info, &ch, &obj); do_obj_trigs (obj, "get", ch, NULL); do_room_trigs(charGetRoom(ch), "get", ch, obj); } void do_drop_trighooks(const char *info) { CHAR_DATA *ch = NULL; OBJ_DATA *obj = NULL; hookParseInfo(info, &ch, &obj); do_obj_trigs (obj, "drop", ch, NULL); do_room_trigs(charGetRoom(ch), "drop", ch, obj); } void do_enter_trighooks(const char *info) { CHAR_DATA *ch = NULL; ROOM_DATA *room = NULL; hookParseInfo(info, &ch, &room); LIST_ITERATOR *mob_i = newListIterator(roomGetCharacters(room)); CHAR_DATA *mob = NULL; ITERATE_LIST(mob, mob_i) { if(ch != mob) do_char_trigs(mob, "enter", ch, NULL); } deleteListIterator(mob_i); do_room_trigs(room, "enter", ch, NULL); } void do_exit_trighooks(const char *info) { CHAR_DATA *ch = NULL; ROOM_DATA *room = NULL; EXIT_DATA *exit = NULL; hookParseInfo(info, &ch, &room, &exit); LIST_ITERATOR *mob_i = newListIterator(roomGetCharacters(room)); CHAR_DATA *mob = NULL; ITERATE_LIST(mob, mob_i) { if(ch != mob) do_char_trigs(mob, "exit", ch, exit); } deleteListIterator(mob_i); do_room_trigs(room, "exit", ch, exit); do_char_trigs(ch, "move", exit, NULL); } void do_ask_trighooks(const char *info) { CHAR_DATA *ch = NULL; CHAR_DATA *listener = NULL; char *speech = NULL; hookParseInfo(info, &ch, &listener, &speech); do_char_trigs(listener, "speech", ch, speech); if(speech) free(speech); } void do_say_trighooks(const char *info) { CHAR_DATA *ch = NULL; char *speech = NULL; hookParseInfo(info, &ch, &speech); LIST_ITERATOR *mob_i = newListIterator(roomGetCharacters(charGetRoom(ch))); CHAR_DATA *mob = NULL; ITERATE_LIST(mob, mob_i) { if(ch != mob) do_char_trigs(mob, "speech", ch, speech); } deleteListIterator(mob_i); do_room_trigs(charGetRoom(ch), "speech", ch, speech); if(speech) free(speech); } void do_greet_trighooks(const char *info) { CHAR_DATA *ch = NULL; CHAR_DATA *greeted = NULL; hookParseInfo(info, &ch, &greeted); do_char_trigs(greeted, "greet", ch, NULL); } void do_wear_trighooks(const char *info) { CHAR_DATA *ch = NULL; OBJ_DATA *obj = NULL; hookParseInfo(info, &ch, &obj); do_char_trigs(ch, "wear", obj, NULL); do_obj_trigs (obj, "wear", ch, NULL); } void do_remove_trighooks(const char *info) { CHAR_DATA *ch = NULL; OBJ_DATA *obj = NULL; hookParseInfo(info, &ch, &obj); do_char_trigs(ch, "remove", obj, NULL); do_obj_trigs (obj, "remove", ch, NULL); } void do_reset_trighooks(const char *info) { char *zone_key = NULL; hookParseInfo(info, &zone_key); ZONE_DATA *zone = worldGetZone(gameworld, zone_key); free(zone_key); LIST_ITERATOR *res_i = newListIterator(zoneGetResettable(zone)); char *name = NULL; const char *locale = zoneGetKey(zone); ROOM_DATA *room = NULL; ITERATE_LIST(name, res_i) { room = worldGetRoom(gameworld, get_fullkey(name, locale)); if(room != NULL) do_room_trigs(room, "reset", NULL, NULL); } deleteListIterator(res_i); } void do_open_door_trighooks(const char *info) { CHAR_DATA *ch = NULL; EXIT_DATA *ex = NULL; hookParseInfo(info, &ch, &ex); do_room_trigs(charGetRoom(ch), "open", ch, ex); } void do_open_obj_trighooks(const char *info) { CHAR_DATA *ch = NULL; OBJ_DATA *obj = NULL; hookParseInfo(info, &ch, &obj); do_obj_trigs(obj, "open", ch, NULL); } //***************************************************************************** // implementation of trighooks.h //***************************************************************************** void init_trighooks(void) { // add all of our hooks to the game hookAdd("give", do_give_trighooks); hookAdd("get", do_get_trighooks); hookAdd("drop", do_drop_trighooks); hookAdd("enter", do_enter_trighooks); hookAdd("exit", do_exit_trighooks); hookAdd("ask", do_ask_trighooks); hookAdd("say", do_say_trighooks); hookAdd("greet", do_greet_trighooks); hookAdd("wear", do_wear_trighooks); hookAdd("remove", do_remove_trighooks); hookAdd("reset", do_reset_trighooks); hookAdd("open_door", do_open_door_trighooks); hookAdd("open_obj", do_open_obj_trighooks); }