//***************************************************************************** // // command.c // // A structure that holds all of the data tied to player commands. // Specifically, the function that is executed and all of the restrictions on // its execution. // //***************************************************************************** #include <Python.h> #include <structmember.h> #include "mud.h" #include "utils.h" #include "action.h" #include "character.h" //***************************************************************************** // mandatory modules //***************************************************************************** #include "scripts/scripts.h" #include "scripts/pyplugs.h" #include "scripts/pychar.h" //***************************************************************************** // local structs, defines, and functions //***************************************************************************** struct cmd_data { char *name; CMD_PTR(func); PyObject *pyfunc; char *user_group; bool interrupts; LIST *checks; }; typedef struct cmd_check_data { CMD_CHK_PTR(func); PyObject *pyfunc; } CMD_CHK_DATA; //***************************************************************************** // functions for manipulating CMD_CHK_DATA //***************************************************************************** CMD_CHK_DATA *newCmdCheck(CMD_CHK(func)) { CMD_CHK_DATA *data = malloc(sizeof(CMD_CHK_DATA)); data->func = func; data->pyfunc = NULL; return data; } CMD_CHK_DATA *newPyCmdCheck(PyObject *pyfunc) { CMD_CHK_DATA *data = malloc(sizeof(CMD_CHK_DATA)); data->func = NULL; data->pyfunc = pyfunc; Py_XINCREF(data->pyfunc); return data; } void deleteCmdCheck(CMD_CHK_DATA *data) { if(data->pyfunc) { Py_XDECREF(data->pyfunc); } free(data); } CMD_CHK_DATA *cmdCheckCopy(CMD_CHK_DATA *data) { if(data->func) return newCmdCheck(data->func); else return newPyCmdCheck(data->pyfunc); } void cmdCheckCopyTo(CMD_CHK_DATA *from, CMD_CHK_DATA *to) { Py_XDECREF(to->pyfunc); Py_XINCREF(from->pyfunc); *to = *from; } //***************************************************************************** // implementation of command.h //***************************************************************************** CMD_DATA *newCmd(const char *name, COMMAND(func), const char *user_group, bool interrupts) { CMD_DATA *cmd = malloc(sizeof(CMD_DATA)); cmd->name = strdupsafe(name); cmd->func = func; cmd->user_group = strdupsafe(user_group); cmd->interrupts = interrupts; cmd->checks = newList(); cmd->pyfunc = NULL; return cmd; } CMD_DATA *newPyCmd(const char *name, void *pyfunc, const char *user_group, bool interrupts) { CMD_DATA *cmd = malloc(sizeof(CMD_DATA)); cmd->name = strdupsafe(name); cmd->func = NULL; cmd->user_group = strdupsafe(user_group); cmd->interrupts = interrupts; cmd->checks = newList(); cmd->pyfunc = pyfunc; Py_INCREF(cmd->pyfunc); return cmd; } void deleteCmd(CMD_DATA *cmd) { if(cmd->name) free(cmd->name); if(cmd->user_group) free(cmd->user_group); if(cmd->pyfunc) { Py_DECREF(cmd->pyfunc); } if(cmd->checks) deleteListWith(cmd->checks, deleteCmdCheck); free(cmd); } CMD_DATA *cmdCopy(CMD_DATA *cmd) { CMD_DATA *newcmd = NULL; if(cmd->func) newcmd = newCmd(cmd->name, cmd->func, cmd->user_group, cmd->interrupts); else newcmd = newPyCmd(cmd->name, cmd->pyfunc, cmd->user_group, cmd->interrupts); // copy over the checks deleteList(newcmd->checks); newcmd->checks = listCopyWith(cmd->checks, cmdCheckCopy); return newcmd; } void cmdCopyTo(CMD_DATA *from, CMD_DATA *to) { if(to->name) free(to->name); if(to->user_group) free(to->user_group); if(to->pyfunc) { Py_DECREF(to->pyfunc); } to->name = strdup(from->name); to->user_group = strdup(from->user_group); if(from->pyfunc) { Py_INCREF(from->pyfunc); } to->func = from->func; to->interrupts = from->interrupts; } const char *cmdGetName(CMD_DATA *cmd) { return cmd->name; } const char *cmdGetUserGroup(CMD_DATA *cmd) { return cmd->user_group; } bool cmdGetInterrupts(CMD_DATA *cmd) { return cmd->interrupts; } LIST *cmdGetChecks(CMD_DATA *cmd) { return cmd->checks; } void cmdAddCheck(CMD_DATA *cmd, CMD_CHK(func)) { listPut(cmdGetChecks(cmd), newCmdCheck(func)); } void cmdAddPyCheck(CMD_DATA *cmd, void *pyfunc) { listPut(cmdGetChecks(cmd), newPyCmdCheck(pyfunc)); } // // make sure the character is in a position where this can be performed bool min_pos_ok(CHAR_DATA *ch, int minpos) { if(poscmp(charGetPos(ch), minpos) >= 0) return TRUE; else { switch(charGetPos(ch)) { case POS_UNCONSCIOUS: send_to_char(ch, "You cannot do that while unconscious!\r\n"); break; case POS_SLEEPING: send_to_char(ch, "Not while sleeping, you won't!\r\n"); break; case POS_SITTING: send_to_char(ch, "You cannot do that while sitting!\r\n"); break; case POS_STANDING: // flying is the highest position... we can deduce this message send_to_char(ch, "You must be flying to try that.\r\n"); break; case POS_FLYING: send_to_char(ch, "That is not possible in any position you can think of.\r\n"); break; default: send_to_char(ch, "Your position is all wrong!\r\n"); log_string("Character, %s, has invalid position, %d.", charGetName(ch), charGetPos(ch)); break; } return FALSE; } } // // make sure the character is in a position where this can be performed bool max_pos_ok(CHAR_DATA *ch, int minpos) { if(poscmp(charGetPos(ch), minpos) <= 0) return TRUE; else { switch(charGetPos(ch)) { case POS_UNCONSCIOUS: send_to_char(ch, "You're still too alive to try that!\r\n"); break; case POS_SLEEPING: send_to_char(ch, "Not while sleeping, you won't!\r\n"); break; case POS_SITTING: send_to_char(ch, "You cannot do that while sitting!\r\n"); break; case POS_STANDING: send_to_char(ch, "You cannot do that while standing.\r\n"); break; case POS_FLYING: send_to_char(ch, "You must land first.\r\n"); break; default: send_to_char(ch, "Your position is all wrong!\r\n"); log_string("Character, %s, has invalid position, %d.", charGetName(ch), charGetPos(ch)); break; } return FALSE; } } bool cmdTryChecks(CHAR_DATA *ch, CMD_DATA *cmd) { bool cmd_ok = TRUE; if(listSize(cmd->checks) > 0) { LIST_ITERATOR *chk_i = newListIterator(cmd->checks); CMD_CHK_DATA *chk = NULL; ITERATE_LIST(chk, chk_i) { if(chk->func) cmd_ok = (chk->func)(ch, cmd->name); else { PyObject *arglist = Py_BuildValue("Os", charGetPyFormBorrowed(ch), cmd->name); PyObject *retval = PyEval_CallObject(chk->pyfunc, arglist); // check for an error: if(retval == NULL) { char *tb = getPythonTraceback(); if(tb != NULL) { log_string("Error running python command check, %s:\r\n%s\r\n", cmd->name, tb); free(tb); } } else if(retval == Py_False) cmd_ok = FALSE; // garbage collection Py_XDECREF(retval); Py_XDECREF(arglist); } if(cmd_ok == FALSE) break; } deleteListIterator(chk_i); } return cmd_ok; } bool charTryCmd(CHAR_DATA *ch, CMD_DATA *cmd, char *arg) { // first, go through all of our checks if(!cmdTryChecks(ch, cmd)) return FALSE; /* if(!min_pos_ok(ch, cmd->min_pos) || !max_pos_ok(ch,cmd->max_pos) || (charIsNPC(ch) && !cmd->mob_ok)) return FALSE; */ else { if(cmd->interrupts) { #ifdef MODULE_FACULTY interrupt_action(ch, FACULTY_ALL); #else interrupt_action(ch, 1); #endif } if(cmd->func) (cmd->func)(ch, cmd->name, arg); else { PyObject *arglist = Py_BuildValue("Oss", charGetPyFormBorrowed(ch), cmd->name, arg); PyObject *retval = PyEval_CallObject(cmd->pyfunc, arglist); // check for an error: if(retval == NULL) { char *tb = getPythonTraceback(); if(tb != NULL) { log_string("Error running python command, %s:\r\n%s\r\n", cmd->name, tb); free(tb); } } // garbage collection Py_XDECREF(retval); Py_XDECREF(arglist); } return TRUE; } } CMD_CHK(chk_can_move) { return min_pos_ok(ch, POS_STANDING); } CMD_CHK(chk_conscious) { return min_pos_ok(ch, POS_SITTING); } CMD_CHK(chk_grounded) { return max_pos_ok(ch, POS_STANDING); } CMD_CHK(chk_not_mob) { if(charIsNPC(ch)) send_to_char(ch, "NPCs may not use this command.\r\n"); return !charIsNPC(ch); }