nakedmudv3.3/
nakedmudv3.3/lib/
nakedmudv3.3/lib/logs/
nakedmudv3.3/lib/misc/
nakedmudv3.3/lib/players/
nakedmudv3.3/lib/txt/
nakedmudv3.3/lib/world/
nakedmudv3.3/lib/world/examples/
nakedmudv3.3/lib/world/examples/mproto/
nakedmudv3.3/lib/world/examples/oproto/
nakedmudv3.3/lib/world/examples/reset/
nakedmudv3.3/lib/world/examples/rproto/
nakedmudv3.3/lib/world/examples/trigger/
nakedmudv3.3/lib/world/limbo/
nakedmudv3.3/lib/world/limbo/room/
nakedmudv3.3/lib/world/limbo/rproto/
nakedmudv3.3/src/alias/
nakedmudv3.3/src/char_vars/
nakedmudv3.3/src/editor/
nakedmudv3.3/src/example_module/
nakedmudv3.3/src/help/
nakedmudv3.3/src/set_val/
nakedmudv3.3/src/socials/
nakedmudv3.3/src/time/
//*****************************************************************************
//
// 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);
}