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



//*****************************************************************************
// 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);
  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);
  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));
}

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);
}

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 all of our parents
  int i, num_parents = 0;
  char     **parents = parse_keywords(proto->parents, &num_parents);
  bool    parents_ok = TRUE;
  for(i = 0; i < num_parents && parents_ok; 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(parents[i], '@');
    if(separator_pos == -1)
      parent = worldGetType(gameworld, type, 
			    get_fullkey(parents[i],get_key_locale(proto->key)));
    else
      parent = worldGetType(gameworld, type, parents[i]);
    if(parent == NULL || !protoRun(parent, type, pynewfunc, protoaddfunc, 
				   protoclassfunc, me))
      parents_ok = FALSE;
    free(parents[i]);
  }

  // finish cleaning up our parent keys
  for(; i < num_parents; i++)
    free(parents[i]);
  free(parents);

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

  // now, do us
  extern PyObject *newScriptDict();
  extern void      start_script(PyObject *dict, const char *script);
  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);
  run_script(dict, bufferString(proto->script), 
	     get_key_locale(protoGetKey(proto)));
  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_to_game(ch);
  if(!protoRun(proto, "mproto", newPyChar, charAddPrototype, charSetClass, ch)){
    extract_mobile(ch);
    ch = NULL;
  }
  return ch;
}

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

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