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/
//*****************************************************************************
//
// prototype.c
//
// generic prototype datastructure for anything that can be generated with a
// python script (e.g. object, room, character). Supports inheritance from
// other prototypes.
//
//*****************************************************************************
#include "mud.h"
#include "utils.h"
#include "prototype.h"
#include "storage.h"
#include "room.h"
#include "character.h"
#include "object.h"
#include "world.h"
#include "zone.h"
#include "handler.h"



//*****************************************************************************
// mandatory modules
//*****************************************************************************
#include "scripts/scripts.h"
#include "scripts/pyplugs.h"
#include "scripts/pychar.h"
#include "scripts/pyroom.h"
#include "scripts/pyobj.h"



//*****************************************************************************
// local datastructures, functions, and variables
//*****************************************************************************
struct prototype_data {
  char       *key;
  char   *parents;
  bool   abstract;
  BUFFER  *script;
  PyObject  *code;
};



//*****************************************************************************
// implementation of prototype.h
//*****************************************************************************
PROTO_DATA *newProto(void) {
  PROTO_DATA *data = malloc(sizeof(PROTO_DATA));
  data->key      = strdup("");
  data->parents  = strdup("");
  data->abstract = TRUE;
  data->script   = newBuffer(1);
  data->code     = NULL;
  return data;
}

void deleteProto(PROTO_DATA *data) {
  if(data->key)     free(data->key);
  if(data->parents) free(data->parents);
  if(data->script)  deleteBuffer(data->script);
  Py_XDECREF(data->code);
  free(data);
}

void protoCopyTo(PROTO_DATA *from, PROTO_DATA *to) {
  protoSetKey(to,      protoGetKey(from));
  protoSetParents(to,  protoGetParents(from));
  protoSetScript(to,   protoGetScript(from));
  protoSetAbstract(to, protoIsAbstract(from));
  Py_XDECREF(to->code);
  Py_XINCREF(from->code);
  to->code = from->code;
}

PROTO_DATA *protoCopy(PROTO_DATA *data) {
  PROTO_DATA *newproto = newProto();
  protoCopyTo(data, newproto);
  return newproto;
}

STORAGE_SET   *protoStore(PROTO_DATA *data) {
  STORAGE_SET *set = new_storage_set();
  store_string(set, "parents",  data->parents);
  store_bool  (set, "abstract", data->abstract);
  store_string(set, "script",   bufferString(data->script));
  return set;
}

PROTO_DATA *protoRead(STORAGE_SET *set) {
  PROTO_DATA *data = newProto();
  protoSetParents(data,  read_string(set, "parents"));
  protoSetAbstract(data, read_bool  (set, "abstract"));
  protoSetScript(data,   read_string(set, "script"));
  return data;
}

void protoSetKey(PROTO_DATA *data, const char *key) {
  if(data->key) free(data->key);
  data->key = strdupsafe(key);
}

void  protoSetParents(PROTO_DATA *data, const char *parents) {
  if(data->parents) free(data->parents);
  data->parents = strdupsafe(parents);
}

void   protoSetScript(PROTO_DATA *data, const char *script) {
  bufferClear(data->script);
  bufferCat(data->script, script);
  Py_XDECREF(data->code);
  data->code = NULL;
}

void protoSetAbstract(PROTO_DATA *data, bool abstract) {
  data->abstract = abstract;
}

const char *protoGetKey(PROTO_DATA *data) {
  return data->key;
}

const char  *protoGetParents(PROTO_DATA *data) {
  return data->parents;
}

bool protoIsAbstract(PROTO_DATA *data) {
  return data->abstract;
}

const char   *protoGetScript(PROTO_DATA *data) {
  return bufferString(data->script);
}

BUFFER *protoGetScriptBuffer(PROTO_DATA *data) {
  return data->script;
}

bool protoRun(PROTO_DATA *proto, const char *type, void *pynewfunc, 
	      void *protoaddfunc, void *protoclassfunc, void *me) {
  // parse and run all of our parents
  LIST           *parents = parse_keywords(proto->parents);
  LIST_ITERATOR *parent_i = newListIterator(parents);
  char        *one_parent = NULL;
  bool         parents_ok = TRUE;

  // try to run each parent
  ITERATE_LIST(one_parent, parent_i) {
    PROTO_DATA *parent = NULL;
    // does our parent have a locale? If so, find it. If not, use ours
    int separator_pos = next_letter_in(one_parent, '@');
    if(separator_pos == -1)
      parent = worldGetType(gameworld, type, 
			    get_fullkey(one_parent,get_key_locale(proto->key)));
    else
      parent = worldGetType(gameworld, type, one_parent);
    
    if(parent == NULL) {
      log_string("ERROR: could not find parent %s for %s %s.", one_parent,
		 type, protoGetKey(proto));
      parents_ok = FALSE;
    }
    else if(!protoRun(parent, type, pynewfunc, protoaddfunc, protoclassfunc,me))
      parents_ok = FALSE;

    // if we had a problem running the proto, report it
    if(parents_ok == FALSE)
      break;
  } deleteListIterator(parent_i);

  // do garbage collection for our parent list
  deleteListWith(parents, free);

  // did we encounter a problem w/ our parents?
  if(parents_ok == FALSE)
    return FALSE;

  // now, do us
  PyObject *dict = restricted_script_dict();
  PyObject *pyme = ((PyObject *(*)(void *))pynewfunc)(me);
  if(protoaddfunc)
    ((void (*)(void *, const char *))protoaddfunc)(me, protoGetKey(proto));
  if(protoclassfunc)
    ((void (*)(void *, const char *))protoclassfunc)(me, protoGetKey(proto));

  PyDict_SetItemString(dict, "me", pyme);

  // do we have our own code already, or do we need to compile from source?
  if(proto->code == NULL) {
    proto->code = run_script_forcode(dict, bufferString(proto->script),
				     get_key_locale(protoGetKey(proto)));
  }
  // we already have a code object. Evaluate it.
  else {
    run_code(proto->code, dict, get_key_locale(protoGetKey(proto)));
    
    if(!last_script_ok()) {
      char *tb = getPythonTraceback();
      log_string("Prototype %s terminated with an error:\r\n%s\r\n"
		 "\r\nTraceback is:\r\n%s\r\n", 
		 proto->key, bufferString(proto->script), tb);
      free(tb);
    }
  }

  Py_DECREF(dict);
  Py_DECREF(pyme);
  return last_script_ok();
}

CHAR_DATA *protoMobRun(PROTO_DATA *proto) {
  if(protoIsAbstract(proto))
    return NULL;
  CHAR_DATA *ch = newMobile();
  char_exist(ch);
  if(protoRun(proto, "mproto", charGetPyForm, charAddPrototype, charSetClass, ch))
    char_to_game(ch);
  else {
    extract_mobile(ch);
    ch = NULL;
  }

  return ch;
}

OBJ_DATA *protoObjRun(PROTO_DATA *proto) {
  if(protoIsAbstract(proto))
    return NULL;
  OBJ_DATA *obj = newObj();
  obj_exist(obj);
  if(protoRun(proto, "oproto", newPyObj, objAddPrototype, objSetClass, obj))
    obj_to_game(obj);
  else {
    extract_obj(obj);
    obj = NULL;
  }

  return obj;
}

ROOM_DATA *protoRoomRun(PROTO_DATA *proto) {
  if(protoIsAbstract(proto))
    return NULL;
  ROOM_DATA *room = newRoom();
  room_exist(room);
  if(protoRun(proto, "rproto", newPyRoom, roomAddPrototype,roomSetClass,room))
    room_to_game(room);
  else {
    extract_room(room);
    room = NULL;
  }

  return room;
}