//***************************************************************************** // // portal.c // // handles all of the functioning of the portal item type. Stores data about // the destination vnums of a portal, and does all the legwork for retreiving // destinations when someone wants to interact with a portal. // //***************************************************************************** #include "../mud.h" #include "../utils.h" #include "../storage.h" #include "../character.h" #include "../object.h" #include "../socket.h" #include "../room.h" #include "../world.h" #include "../inform.h" #include "../handler.h" #include "../hooks.h" #include "items.h" #include "../olc2/olc.h" #include "iedit.h" #include "portal.h" //***************************************************************************** // mandatory modules //***************************************************************************** #include "../scripts/scripts.h" #include "../scripts/pyobj.h" #include "../scripts/pyroom.h" //***************************************************************************** // item data for portals //***************************************************************************** typedef struct portal_data { char *dest; char *leave_mssg; char *enter_mssg; } PORTAL_DATA; PORTAL_DATA *newPortalData() { PORTAL_DATA *data = malloc(sizeof(PORTAL_DATA)); data->dest = strdup(""); data->leave_mssg = strdup(""); data->enter_mssg = strdup(""); return data; } void deletePortalData(PORTAL_DATA *data) { if(data->dest) free(data->dest); if(data->leave_mssg) free(data->leave_mssg); if(data->enter_mssg) free(data->enter_mssg); free(data); } void portalDataCopyTo(PORTAL_DATA *from, PORTAL_DATA *to) { if(to->dest) free(to->dest); if(to->leave_mssg) free(to->leave_mssg); if(to->enter_mssg) free(to->enter_mssg); to->dest = strdupsafe(from->dest); to->leave_mssg = strdupsafe(from->leave_mssg); to->enter_mssg = strdupsafe(from->enter_mssg); } PORTAL_DATA *portalDataCopy(PORTAL_DATA *data) { PORTAL_DATA *new_data = newPortalData(); portalDataCopyTo(data, new_data); return new_data; } STORAGE_SET *portalDataStore(PORTAL_DATA *data) { STORAGE_SET *set = new_storage_set(); store_string(set, "dest", data->dest); store_string(set, "enter", data->enter_mssg); store_string(set, "leave", data->leave_mssg); return set; } PORTAL_DATA *portalDataRead(STORAGE_SET *set) { PORTAL_DATA *data = malloc(sizeof(PORTAL_DATA)); data->dest = strdupsafe(read_string(set, "dest")); data->enter_mssg = strdupsafe(read_string(set, "enter")); data->leave_mssg = strdupsafe(read_string(set, "leave")); return data; } //***************************************************************************** // functions for interacting with portals //***************************************************************************** const char *portalGetDest(OBJ_DATA *obj) { PORTAL_DATA *data = objGetTypeData(obj, "portal"); return data->dest; } const char *portalGetLeaveMssg(OBJ_DATA *obj) { PORTAL_DATA *data = objGetTypeData(obj, "portal"); return data->leave_mssg; } const char *portalGetEnterMssg(OBJ_DATA *obj) { PORTAL_DATA *data = objGetTypeData(obj, "portal"); return data->enter_mssg; } void portalSetDest(OBJ_DATA *obj, const char *dest) { PORTAL_DATA *data = objGetTypeData(obj, "portal"); if(data->dest) free(data->dest); data->dest = strdupsafe(dest); } void portalSetLeaveMssg(OBJ_DATA *obj, const char *mssg) { PORTAL_DATA *data = objGetTypeData(obj, "portal"); if(data->leave_mssg) free(data->leave_mssg); data->leave_mssg = strdupsafe(mssg); } void portalSetEnterMssg(OBJ_DATA *obj, const char *mssg) { PORTAL_DATA *data = objGetTypeData(obj, "portal"); if(data->enter_mssg) free(data->enter_mssg); data->enter_mssg = strdupsafe(mssg); } // // cmd_enter is used to go through portals // usage: enter <object> // // examples: // enter portal enter the thing called "portal" in your room COMMAND(cmd_enter) { void *obj = NULL; if(!parse_args(ch, TRUE, cmd, arg, "obj.room", &obj)) return; // we're trying to enter a portal if(!objIsType(obj, "portal")) send_to_char(ch, "You cannot seem to find an enterance.\r\n"); else { ROOM_DATA *dest = worldGetRoom(gameworld, portalGetDest(obj)); if(dest == NULL) send_to_char(ch, "There is nothing on the other side...\r\n"); else { if(*portalGetLeaveMssg(obj)) message(ch, NULL, obj,NULL,TRUE,TO_ROOM, portalGetLeaveMssg(obj)); else message(ch, NULL, obj, NULL, TRUE, TO_ROOM, "$n steps into $o."); // transfer our character and look char_from_room(ch); char_to_room(ch, dest); look_at_room(ch, dest); if(*portalGetEnterMssg(obj)) message(ch, NULL, obj,NULL,TRUE,TO_ROOM, portalGetEnterMssg(obj)); else message(ch, NULL, obj, NULL, TRUE, TO_ROOM, "$n arrives after travelling through $o."); } } } //***************************************************************************** // portal olc //***************************************************************************** #define IEDIT_PORTAL_DEST 1 #define IEDIT_PORTAL_ENTER 2 #define IEDIT_PORTAL_LEAVE 3 // the resedit olc needs these declared void iedit_portal_menu(SOCKET_DATA *sock, PORTAL_DATA *data) { send_to_socket(sock, "{g1) Destination : {c%s\r\n", data->dest); send_to_socket(sock, "{g2) Enter message:\r\n{c%s\r\n", data->enter_mssg); send_to_socket(sock, "{g3) Leave message:\r\n{c%s\r\n", data->leave_mssg); } int iedit_portal_chooser(SOCKET_DATA *sock, PORTAL_DATA *data, const char *option) { switch(toupper(*option)) { case '1': text_to_buffer(sock, "Enter new destination (return for none): "); return IEDIT_PORTAL_DEST; case '2': text_to_buffer(sock, "Enter message shown to room user arrives at: "); return IEDIT_PORTAL_ENTER; case '3': text_to_buffer(sock, "Enter message shown to room user leaves: "); return IEDIT_PORTAL_LEAVE; default: return MENU_CHOICE_INVALID; } } bool iedit_portal_parser (SOCKET_DATA *sock, PORTAL_DATA *data, int choice, const char *arg) { switch(choice) { case IEDIT_PORTAL_DEST: { if(data->dest) free(data->dest); data->dest = strdupsafe(arg); return TRUE; } case IEDIT_PORTAL_LEAVE: { if(data->leave_mssg) free(data->leave_mssg); data->leave_mssg = strdupsafe(arg); return TRUE; } case IEDIT_PORTAL_ENTER: { if(data->enter_mssg) free(data->enter_mssg); data->enter_mssg = strdupsafe(arg); return TRUE; } default: return FALSE; } } void portal_from_proto(PORTAL_DATA *data, BUFFER *buf) { char line[MAX_BUFFER]; const char *code = bufferString(buf); do { code = strcpyto(line, code, '\n'); char *lptr = line; if(!strncasecmp(lptr, "me.portal_dest", 14)) { while(*lptr && *lptr != '\"') lptr++; lptr++; // skip leading " lptr[next_letter_in(lptr, '\"')] = '\0'; // kill ending " if(data->dest) free(data->dest); data->dest = strdupsafe(lptr); } else if(!strncasecmp(lptr, "me.portal_enter_mssg", 20)) { while(*lptr && *lptr != '\"') lptr++; lptr++; // skip leading " lptr[next_letter_in(lptr, '\"')] = '\0'; // kill ending " if(data->enter_mssg) free(data->enter_mssg); data->enter_mssg = strdupsafe(lptr); } else if(!strncasecmp(lptr, "me.portal_leave_mssg", 20)) { while(*lptr && *lptr != '\"') lptr++; lptr++; // skip leading " lptr[next_letter_in(lptr, '\"')] = '\0'; // kill ending " if(data->leave_mssg) free(data->leave_mssg); data->leave_mssg = strdupsafe(lptr); } else; // ignore line } while(*code != '\0'); } void portal_to_proto(PORTAL_DATA *data, BUFFER *buf) { if(*data->dest) bprintf(buf, "me.portal_dest = \"%s\"\n", data->dest); if(*data->leave_mssg) bprintf(buf, "me.portal_leave_mssg = \"%s\"\n", data->leave_mssg); if(*data->enter_mssg) bprintf(buf, "me.portal_enter_mssg = \"%s\"\n", data->enter_mssg); } //***************************************************************************** // pyobj getters and setters //***************************************************************************** PyObject *PyObj_getportaldest(PyObject *self, void *closure) { OBJ_DATA *obj = PyObj_AsObj(self); if(obj == NULL) return NULL; else if(objIsType(obj, "portal")) return Py_BuildValue("s", portalGetDest(obj)); else { PyErr_Format(PyExc_TypeError, "Can only get destination for portals."); return NULL; } } PyObject *PyObj_getportalleavemssg(PyObject *self, void *closure) { OBJ_DATA *obj = PyObj_AsObj(self); if(obj == NULL) return NULL; else if(objIsType(obj, "portal")) return Py_BuildValue("s", portalGetLeaveMssg(obj)); else { PyErr_Format(PyExc_TypeError, "Can only get leave message for portals."); return NULL; } } PyObject *PyObj_getportalentermssg(PyObject *self, void *closure) { OBJ_DATA *obj = PyObj_AsObj(self); if(obj == NULL) return NULL; else if(objIsType(obj, "portal")) return Py_BuildValue("s", portalGetEnterMssg(obj)); else { PyErr_Format(PyExc_TypeError, "Can only get enter message for portals."); return NULL; } } int PyObj_setportaldest(PyObject *self, PyObject *value, void *closure) { OBJ_DATA *obj = PyObj_AsObj(self); if(obj == NULL) { PyErr_Format(PyExc_StandardError, "Tried to set destination for " "nonexistent portal, %d", PyObj_AsUid(self)); return -1; } else if(!objIsType(obj, "portal")) { PyErr_Format(PyExc_TypeError, "Tried to set destination for non-portal, %s", objGetClass(obj)); return -1; } if(PyString_Check(value)) portalSetDest(obj, PyString_AsString(value)); else if(PyRoom_Check(value)) portalSetDest(obj, roomGetClass(PyRoom_AsRoom(value))); else { PyErr_Format(PyExc_TypeError, "portal dest must be a room or string."); return -1; } return 0; } int PyObj_setportalleavemssg(PyObject *self, PyObject *value, void *closure) { OBJ_DATA *obj = PyObj_AsObj(self); if(obj == NULL) { PyErr_Format(PyExc_StandardError, "Tried to set leave message for " "nonexistent portal, %d", PyObj_AsUid(self)); return -1; } else if(!objIsType(obj, "portal")) { PyErr_Format(PyExc_TypeError, "Tried to set leave mssg for non-portal, %s", objGetClass(obj)); return -1; } if(PyString_Check(value)) portalSetLeaveMssg(obj, PyString_AsString(value)); else { PyErr_Format(PyExc_TypeError, "portal leave message must be a string."); return -1; } return 0; } int PyObj_setportalentermssg(PyObject *self, PyObject *value, void *closure) { OBJ_DATA *obj = PyObj_AsObj(self); if(obj == NULL) { PyErr_Format(PyExc_StandardError, "Tried to set enter message for " "nonexistent portal, %d", PyObj_AsUid(self)); return -1; } else if(!objIsType(obj, "portal")) { PyErr_Format(PyExc_TypeError, "Tried to set enter mssg for non-portal, %s", objGetClass(obj)); return -1; } if(PyString_Check(value)) portalSetEnterMssg(obj, PyString_AsString(value)); else { PyErr_Format(PyExc_TypeError, "portal enter message must be a string."); return -1; } return 0; } //***************************************************************************** // add our hookds //***************************************************************************** void portal_look_hook(const char *info) { OBJ_DATA *obj = NULL; CHAR_DATA *ch = NULL; hookParseInfo(info, &obj, &ch); if(objIsType(obj, "portal")) { ROOM_DATA *dest = worldGetRoom(gameworld, portalGetDest(obj)); if(dest != NULL) { send_to_char(ch, "You peer inside %s.\r\n", see_obj_as(ch, obj)); look_at_room(ch, dest); } } } //***************************************************************************** // install the portal item type //***************************************************************************** // // this will need to be called by init_items() in items/items.c void init_portal(void) { item_add_type("portal", newPortalData, deletePortalData, portalDataCopyTo, portalDataCopy, portalDataStore, portalDataRead); // set up our hooks hookAdd("look_at_obj", portal_look_hook); // set up the portal OLC too item_add_olc("portal", iedit_portal_menu, iedit_portal_chooser, iedit_portal_parser, portal_from_proto, portal_to_proto); // make it so we can set portal destinations in scripts PyObj_addGetSetter("portal_dest", PyObj_getportaldest, PyObj_setportaldest, "the database key of the room we're going to."); PyObj_addGetSetter("portal_enter_mssg", PyObj_getportalentermssg, PyObj_setportalentermssg, "The message shown when user enters a new room."); PyObj_addGetSetter("portal_leave_mssg", PyObj_getportalleavemssg, PyObj_setportalleavemssg, "The message shown when user leaves a room."); add_cmd("enter", NULL, cmd_enter, POS_STANDING, POS_FLYING, "player", TRUE, TRUE); }