// Cyphesis Online RPG Server and AI Engine #include // Copyright (C) 2000 Alistair Riddoch // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "Py_Thing.h" #include "Py_Map.h" #include "Py_Message.h" #include "Py_Vector3D.h" #include "Py_Point3D.h" #include "Py_Location.h" #include "Py_World.h" #include "Py_Property.h" #include "Py_Operation.h" #include "Py_Oplist.h" #include "Py_Task.h" #include "Py_WorldTime.h" #include "PythonWrapper.h" #include "BaseMind.h" #include "Character.h" #include "navigation/Steering.h" #include "common/id.h" #include "common/log.h" #include "common/Property.h" #include "common/TypeNode.h" #include "common/Inheritance.h" using Atlas::Message::Element; using Atlas::Message::MapType; static PyObject * Entity_as_entity(PyEntity * self) { #ifndef NDEBUG if (self->m_entity.l == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL entity in Entity.as_entity"); return NULL; } #endif // NDEBUG PyMessage * ret = newPyMessage(); if (ret != NULL) { ret->m_obj = new Element(MapType()); self->m_entity.l->addToMessage(ret->m_obj->asMap()); } return (PyObject *)ret; } static PyMethodDef LocatedEntity_methods[] = { {"as_entity", (PyCFunction)Entity_as_entity, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; static PyObject * Entity_send_world(PyEntity * self, PyOperation * op) { #ifndef NDEBUG if (self->m_entity.e == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL entity in Entity.send_world"); return NULL; } #endif // NDEBUG if (PyOperation_Check(op)) { self->m_entity.e->sendWorld(op->operation); } else { PyErr_SetString(PyExc_TypeError, "Entity.send_world must be an op"); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyMethodDef Entity_methods[] = { {"send_world", (PyCFunction)Entity_send_world, METH_O}, {NULL, NULL} /* sentinel */ }; static PyObject * Character_start_task(PyEntity * self, PyObject * args) { #ifndef NDEBUG if (self->m_entity.l == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL entity in Entity.start_task"); return NULL; } #endif // NDEBUG PyObject * task; PyObject * op; PyObject * res; if (!PyArg_ParseTuple(args, "OOO", &task, &op, &res)) { return NULL; } if (!PyTask_Check(task)) { PyErr_SetString(PyExc_TypeError, "Entity.start_task must be a task"); return NULL; } if (!PyOperation_Check(op)) { PyErr_SetString(PyExc_TypeError, "Entity.start_task must be an op"); return NULL; } if (!PyOplist_Check(res)) { PyErr_SetString(PyExc_TypeError, "Entity.start_task must be an oplist"); return NULL; } self->m_entity.c->startTask(((PyTask*)task)->m_task, ((PyOperation*)op)->operation, *((PyOplist*)res)->ops); Py_INCREF(Py_None); return Py_None; } static PyObject * Character_mind2body(PyEntity * self, PyOperation * op) { #ifndef NDEBUG if (self->m_entity.l == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL entity in Entity.mind2body"); return NULL; } #endif // NDEBUG if (!PyOperation_Check(op)) { PyErr_SetString(PyExc_TypeError, "Entity.mind2body must be an operation"); return NULL; } OpVector res; self->m_entity.c->mind2body(op->operation, res); if (res.empty()) { Py_INCREF(Py_None); return Py_None; } else if (res.size() == 1) { PyOperation * ret = newPyOperation(); if (ret != NULL) { ret->operation = res[0]; } return (PyObject*)ret; } else { PyOplist * ret = newPyOplist(); if (ret != NULL) { ret->ops = new OpVector(res); } return (PyObject*)ret; } } static PyObject * Mind_refreshPath(PyEntity * self) { #ifndef NDEBUG if (self->m_entity.l == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL entity in Entity.refreshPath"); return NULL; } #endif // NDEBUG AwareMind* awareMind = dynamic_cast(self->m_entity.m); if (!awareMind) { return NULL; } int result = awareMind->updatePath(); // int result = awareMind->getSteering().updatePath(awareMind->m_location.m_pos); return Py_BuildValue("i", result); } static PyObject * Mind_describeEntity(PyEntity * self) { #ifndef NDEBUG if (self->m_entity.l == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL entity in Entity.mind2body"); return NULL; } #endif // NDEBUG AwareMind* awareMind = dynamic_cast(self->m_entity.m); if (!awareMind) { return NULL; } std::string result = awareMind->describeEntity(); return PyString_FromString(result.c_str()); } static PyObject* Mind_setDestination(PyEntity* self, PyObject* args) { AwareMind* awareMind = dynamic_cast(self->m_entity.m); if (!awareMind) { return NULL; } PyObject * destination_arg; float radius; const char* entityIdString; if (!PyArg_ParseTuple(args, "Ofz", &destination_arg, &radius, &entityIdString)) { awareMind->getSteering().stopSteering(); return NULL; } if (!PyPoint3D_Check(destination_arg)) { PyErr_SetString(PyExc_TypeError, "Argument must be a Point3D"); awareMind->getSteering().stopSteering(); return NULL; } PyPoint3D * destination = (PyPoint3D *)destination_arg; if (!destination->coords.isValid()) { awareMind->getSteering().stopSteering(); return 0; } int entityId; //If no entity id was specified, the location is relative to the parent entity. if (entityIdString == nullptr) { entityId = awareMind->m_location.m_loc->getIntId(); } else { entityId = std::atoi(entityIdString); } awareMind->getSteering().setDestination(entityId, destination->coords, radius, awareMind->getCurrentServerTime()); awareMind->getSteering().startSteering(); Py_INCREF(Py_None); return Py_None; } static PyMethodDef Character_methods[] = { {"start_task", (PyCFunction)Character_start_task, METH_VARARGS}, {"mind2body", (PyCFunction)Character_mind2body, METH_O}, {NULL, NULL} /* sentinel */ }; static PyMethodDef Mind_methods[] = { {"refreshPath", (PyCFunction)Mind_refreshPath, METH_NOARGS}, {"setDestination", (PyCFunction)Mind_setDestination, METH_VARARGS}, {"describeEntity", (PyCFunction)Mind_describeEntity, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; static PyEntity * Entity_new(PyTypeObject * type, PyObject * args, PyObject * kwds) { PyEntity * self = (PyEntity *)type->tp_alloc(type, 0); if (self != NULL) { self->m_weakreflist = NULL; } return self; } static void Entity_dealloc(PyEntity *self) { if (self->m_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *) self); } self->ob_type->tp_free((PyObject*)self); } static PyObject * Entity_getattro(PyEntity *self, PyObject *oname) { #ifndef NDEBUG if (self->m_entity.e == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL entity in Entity.getattr"); return NULL; } #endif // NDEBUG char * name = PyString_AsString(oname); // If operation search gets to here, it goes no further if (strcmp(name, "type") == 0) { if (self->m_entity.e->getType() == NULL) { PyErr_SetString(PyExc_AttributeError, name); return NULL; } PyObject * list = PyList_New(0); if (list == NULL) { return NULL; } PyObject * ent = PyString_FromString(self->m_entity.e->getType()->name().c_str()); PyList_Append(list, ent); Py_DECREF(ent); return list; } if (strcmp(name, "location") == 0) { PyLocation * loc = newPyLocation(); if (loc != NULL) { loc->location = &self->m_entity.e->m_location; loc->owner = self->m_entity.e; } return (PyObject *)loc; } if (strcmp(name, "contains") == 0) { if (self->m_entity.e->m_contains == 0) { Py_INCREF(Py_None); return Py_None; } PyObject * list = PyList_New(0); if (list == NULL) { return NULL; } LocatedEntitySet::const_iterator I = self->m_entity.e->m_contains->begin(); LocatedEntitySet::const_iterator Iend = self->m_entity.e->m_contains->end(); for (; I != Iend; ++I) { LocatedEntity * child = *I; PyObject * wrapper = wrapEntity(child); if (wrapper == NULL) { Py_DECREF(list); return NULL; } PyList_Append(list, wrapper); Py_DECREF(wrapper); } return list; } if (strcmp(name, "visible") == 0) { if (self->m_entity.e->isVisible()) { Py_RETURN_TRUE; } Py_RETURN_FALSE; } Entity * entity = self->m_entity.e; PropertyBase * prop = entity->modProperty(name); if (prop != 0) { PyObject * ret = Property_asPyObject(prop, entity); if (ret != 0) { return ret; } Element attr; // If this property is not set with a value, return none. if (prop->get(attr) == 0) { return MessageElement_asPyObject(attr); } else { Py_INCREF(Py_None); return Py_None; } } return PyObject_GenericGetAttr((PyObject *)self, oname); } static int Entity_setattro(PyEntity *self, PyObject *oname, PyObject *v) { #ifndef NDEBUG if (self->m_entity.e == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL entity in Entity.setattr"); return -1; } #endif // NDEBUG char * name = PyString_AsString(oname); if (strcmp(name, "map") == 0) { PyErr_SetString(PyExc_AttributeError, "map attribute forbidden"); return -1; } Entity * entity = self->m_entity.e; //std::string attr(name); //if (v == NULL) { //entity->attributes.erase(attr); //return 0; //} if (strcmp(name, "type") == 0) { if (entity->getType() != 0) { PyErr_SetString(PyExc_RuntimeError, "Cannot mutate entity type"); return -1; } if (!PyString_CheckExact(v)) { PyErr_SetString(PyExc_TypeError, "No string type"); return -1; } const TypeNode * type = Inheritance::instance().getType(PyString_AsString(v)); if (type == 0) { PyErr_SetString(PyExc_ValueError, "Entity type unknown"); return -1; } entity->setType(type); return 0; } Element obj; if (PyObject_asMessageElement(v, obj) == 0) { PropertyBase * p = entity->setAttr(name, obj); if (p != 0) { p->setFlags(flag_unsent); } return 0; } return PyObject_GenericSetAttr((PyObject *)self, oname, v); } static int Entity_compare(PyEntity *self, PyEntity *other) { if (self->m_entity.e == NULL || other->m_entity.e == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL Entity in Entity.compare"); return -1; } return (self->m_entity.e == other->m_entity.e) ? 0 : 1; } static int LocatedEntity_init(PyEntity * self, PyObject * args, PyObject * kwds) { char * id = NULL; if (!PyArg_ParseTuple(args, "s", &id)) { return -1; } long intId = integerId(id); if (intId == -1L) { PyErr_SetString(PyExc_TypeError, "Entity() requires string/int ID"); return -1; } self->m_entity.l = new Entity(id, intId); return 0; } static int Entity_init(PyEntity * self, PyObject * args, PyObject * kwds) { PyObject * arg; if (!PyArg_ParseTuple(args, "O", &arg)) { return -1; } if (PyString_Check(arg)) { char * id = PyString_AsString(arg); long intId = integerId(id); if (intId == -1L) { PyErr_SetString(PyExc_TypeError, "Entity() requires string/int ID"); return -1; } self->m_entity.e = new Entity(id, intId); return 0; } if (PyEntity_Check(arg)) { PyEntity * character = (PyEntity *)arg; #ifndef NDEBUG if (character->m_entity.c == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL character Task.__init__"); return -1; } #endif // NDEBUG self->m_entity.c = character->m_entity.c; return 0; } PyErr_SetString(PyExc_TypeError, "Entity() requires string ID or Entity"); return -1; } static int Character_init(PyEntity * self, PyObject * args, PyObject * kwds) { PyObject * arg; if (!PyArg_ParseTuple(args, "O", &arg)) { return -1; } if (PyString_Check(arg)) { char * id = PyString_AsString(arg); long intId = integerId(id); if (intId == -1L) { PyErr_SetString(PyExc_TypeError, "Entity() requires string/int ID"); return -1; } self->m_entity.c = new Character(id, intId); return 0; } if (PyCharacter_Check(arg)) { PyEntity * character = (PyEntity *)arg; #ifndef NDEBUG if (character->m_entity.c == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL character Task.__init__"); return -1; } #endif // NDEBUG self->m_entity.c = character->m_entity.c; return 0; } PyErr_SetString(PyExc_TypeError, "Character() requires string ID or Character"); return -1; } static PyObject * Mind_getattro(PyEntity *self, PyObject *oname) { #ifndef NDEBUG if (self->m_entity.m == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL mind in Mind.getattr"); return NULL; } #endif // NDEBUG char * name = PyString_AsString(oname); if (strcmp(name, "id") == 0) { return (PyObject *)PyString_FromString(self->m_entity.m->getId().c_str()); } if (strcmp(name, "type") == 0) { if (self->m_entity.m->getType() == NULL) { PyErr_SetString(PyExc_AttributeError, name); return NULL; } PyObject * list = PyList_New(0); if (list == NULL) { return NULL; } PyObject * ent = PyString_FromString(self->m_entity.m->getType()->name().c_str()); PyList_Append(list, ent); Py_DECREF(ent); return list; } if (strcmp(name, "map") == 0) { PyMap * map = newPyMap(); if (map != NULL) { map->m_map = self->m_entity.m->getMap(); } return (PyObject *)map; } if (strcmp(name, "location") == 0) { PyLocation * loc = newPyLocation(); if (loc != NULL) { loc->location = &self->m_entity.m->m_location; loc->owner = self->m_entity.m; } return (PyObject *)loc; } if (strcmp(name, "time") == 0) { PyWorldTime * worldtime = newPyWorldTime(); if (worldtime != NULL) { worldtime->time = self->m_entity.m->getTime(); } return (PyObject *)worldtime; } if (strcmp(name, "contains") == 0) { if (self->m_entity.m->m_contains == 0) { Py_INCREF(Py_None); return Py_None; } PyObject * list = PyList_New(0); if (list == NULL) { return NULL; } LocatedEntitySet::const_iterator I = self->m_entity.m->m_contains->begin(); LocatedEntitySet::const_iterator Iend = self->m_entity.m->m_contains->end(); for (; I != Iend; ++I) { LocatedEntity * child = *I; PyObject * wrapper = wrapEntity(child); if (wrapper == NULL) { Py_DECREF(list); return NULL; } PyList_Append(list, wrapper); Py_DECREF(wrapper); } return list; } if (strcmp(name, "unawareTilesCount") == 0) { AwareMind* awareMind = dynamic_cast(self->m_entity.m); if (!awareMind) { return NULL; } size_t count = awareMind->getSteering().unawareAreaCount(); return PyInt_FromSize_t(count); } if (strcmp(name, "path") == 0) { AwareMind* awareMind = dynamic_cast(self->m_entity.m); if (!awareMind) { return NULL; } const auto& path = awareMind->getSteering().getPath(); PyObject * list = PyList_New(0); if (list == NULL) { return NULL; } for (auto& point : path) { auto py_point = newPyPoint3D(); py_point->coords = point; PyList_Append(list, (PyObject*)py_point); Py_DECREF(py_point); } return list; } if (strcmp(name, "pathResult") == 0) { AwareMind* awareMind = dynamic_cast(self->m_entity.m); if (!awareMind) { return NULL; } return PyInt_FromLong(awareMind->getSteering().getPathResult()); } LocatedEntity * mind = self->m_entity.m; Element attr; if (mind->getAttr(name, attr) == 0) { return MessageElement_asPyObject(attr); } return PyObject_GenericGetAttr((PyObject *)self, oname); } static int Mind_setattro(PyEntity *self, PyObject *oname, PyObject *v) { char * name = PyString_AsString(oname); if (strcmp(name, "mind") == 0) { if (!PyMind_Check(v)) { PyErr_SetString(PyExc_TypeError, "Mind.mind requires Mind"); return -1; } self->m_entity.m = ((PyEntity*)v)->m_entity.m; return 0; } #ifndef NDEBUG if (self->m_entity.m == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL mind in Mind.setattr"); return -1; } #endif // NDEBUG if (strcmp(name, "map") == 0) { PyErr_SetString(PyExc_AttributeError, "Setting map on mind is forbidden"); return -1; } LocatedEntity * entity = self->m_entity.m; // Should we support removal of attributes? //std::string attr(name); //if (v == NULL) { //entity->attributes.erase(attr); //return 0; //} Element obj; if (PyObject_asMessageElement(v, obj, true) == 0) { assert(!obj.isMap() && !obj.isList()); // In the Python wrapper for Entity in Py_Thing.cpp notices are issued // for some types. entity->setAttr(name, obj); return 0; } return PyObject_GenericSetAttr((PyObject *)self, oname, v); } static int Mind_compare(PyEntity *self, PyEntity *other) { if (self->m_entity.m == NULL || other->m_entity.m == NULL) { PyErr_SetString(PyExc_AssertionError, "NULL mind in Mind.compare"); return -1; } return (self->m_entity.m == other->m_entity.m) ? 0 : 1; } static int Mind_init(PyEntity * self, PyObject * args, PyObject * kwds) { char * id = NULL; if (!PyArg_ParseTuple(args, "s", &id)) { return -1; } long intId = integerId(id); if (intId == -1L) { PyErr_SetString(PyExc_TypeError, "Mind() requires string/int ID"); return -1; } self->m_entity.m = new BaseMind(id, intId); return 0; } PyTypeObject PyLocatedEntity_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "server.LocatedEntity", /*tp_name*/ sizeof(PyEntity), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)Entity_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ (cmpfunc)Entity_compare, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, // tp_call 0, // tp_str (getattrofunc)Entity_getattro, // tp_getattro (setattrofunc)Entity_setattro, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags "LocatedEntity objects", // tp_doc 0, // tp_travers 0, // tp_clear 0, // tp_richcompare offsetof(PyEntity, m_weakreflist), // tp_weaklistoffset 0, // tp_iter 0, // tp_iternext LocatedEntity_methods, // tp_methods 0, // tp_members 0, // tp_getset 0, // tp_base 0, // tp_dict 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset (initproc)LocatedEntity_init, // tp_init 0, // tp_alloc (newfunc)Entity_new, // tp_new }; PyTypeObject PyEntity_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "server.Entity", /*tp_name*/ sizeof(PyEntity), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ (cmpfunc)Entity_compare, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, // tp_call 0, // tp_str 0, // tp_getattro 0, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags "Entity objects", // tp_doc 0, // tp_travers 0, // tp_clear 0, // tp_richcompare 0, // tp_weaklistoffset 0, // tp_iter 0, // tp_iternext Entity_methods, // tp_methods 0, // tp_members 0, // tp_getset &PyLocatedEntity_Type, // tp_base 0, // tp_dict 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset (initproc)Entity_init, // tp_init 0, // tp_alloc (newfunc)Entity_new, // tp_new }; PyTypeObject PyCharacter_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "server.Character", /*tp_name*/ sizeof(PyEntity), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ (cmpfunc)Entity_compare, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, // tp_call 0, // tp_str 0, // tp_getattro 0, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags "Character objects", // tp_doc 0, // tp_travers 0, // tp_clear 0, // tp_richcompare 0, // tp_weaklistoffset 0, // tp_iter 0, // tp_iternext Character_methods, // tp_methods 0, // tp_members 0, // tp_getset &PyEntity_Type, // tp_base 0, // tp_dict 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset (initproc)Character_init, // tp_init 0, // tp_alloc (newfunc)Entity_new, // tp_new }; PyTypeObject PyMind_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, // ob_size "server.Mind", // tp_name sizeof(PyEntity), // tp_basicsize 0, // tp_itemsize // methods 0, // tp_dealloc 0, // tp_print 0, // tp_getattr 0, // tp_setattr (cmpfunc)Mind_compare, // tp_compare 0, // tp_repr 0, // tp_as_number 0, // tp_as_sequence 0, // tp_as_mapping 0, // tp_hash 0, // tp_call 0, // tp_str (getattrofunc)Mind_getattro, // tp_getattro (setattrofunc)Mind_setattro, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags "Mind objects", // tp_doc 0, // tp_travers 0, // tp_clear 0, // tp_richcompare 0, // tp_weaklistoffset 0, // tp_iter 0, // tp_iternext Mind_methods, // tp_methods 0, // tp_members 0, // tp_getset &PyLocatedEntity_Type, // tp_base 0, // tp_dict 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset (initproc)Mind_init, // tp_init 0, // tp_alloc (newfunc)Entity_new, // tp_new }; template<> PyObject * wrapPython(LocatedEntity * le) { PyEntity * pe; Entity * entity = dynamic_cast(le); if (entity != 0) { Character * ch_entity = dynamic_cast(entity); if (ch_entity != 0) { pe = newPyCharacter(); if (pe == NULL) { return NULL; } pe->m_entity.c = ch_entity; } else { pe = newPyEntity(); if (pe == NULL) { return NULL; } pe->m_entity.e = entity; } } else { pe = newPyLocatedEntity(); if (pe == NULL) { return NULL; } pe->m_entity.l = le; } return (PyObject*)pe; } template<> PyObject * wrapPython(Entity * e) { return wrapPython(e); } template<> PyObject * wrapPython(BaseMind * t) { PyEntity * pm = newPyMind(); if (pm == NULL) { return NULL; } pm->m_entity.m = t; return (PyObject*)pm; } PyObject * wrapEntity(LocatedEntity * le) { PyObject * wrapper = 0; if (le->script() == 0) { wrapper = wrapPython(le); le->setScript(new PythonWrapper(wrapper)); } else { PythonWrapper * pw = dynamic_cast(le->script()); if (pw == 0) { log(WARNING, "Entity has script of unknown type"); } else { wrapper = pw->wrapper(); assert(wrapper != NULL); Py_INCREF(wrapper); } } return wrapper; } // FIXME if this is cleaner to use the methods field of the type for methods, // one PyTypeObject for each, and just share the members. That way we lose // the need for a members entry on the object. PyEntity * newPyLocatedEntity() { return (PyEntity *)PyLocatedEntity_Type.tp_new(&PyLocatedEntity_Type, 0, 0); } PyEntity * newPyEntity() { return (PyEntity *)PyEntity_Type.tp_new(&PyEntity_Type, 0, 0); } PyEntity * newPyCharacter() { return (PyEntity *)PyCharacter_Type.tp_new(&PyCharacter_Type, 0, 0); } PyEntity * newPyMind() { return (PyEntity *)PyMind_Type.tp_new(&PyMind_Type, 0, 0); }