|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <plugin_python.h> 00031 00034 /* @cparser 00035 * @page plugin_python_map_fields Python map fields 00036 * <h2>Python map fields</h2> 00037 * List of the map fields and their meaning. */ 00038 static fields_struct fields[] = 00039 { 00040 {"next", FIELDTYPE_MAP, offsetof(mapstruct, next), FIELDFLAG_READONLY, 0}, 00041 {"previous", FIELDTYPE_MAP, offsetof(mapstruct, previous), FIELDFLAG_READONLY, 0}, 00042 00043 {"name", FIELDTYPE_CSTR, offsetof(mapstruct, name), 0, 0}, 00044 {"msg", FIELDTYPE_CSTR, offsetof(mapstruct, msg), 0, 0}, 00045 {"reset_timeout", FIELDTYPE_UINT32, offsetof(mapstruct, reset_timeout), 0, 0}, 00046 {"timeout", FIELDTYPE_SINT32, offsetof(mapstruct, timeout), 0, 0}, 00047 {"difficulty", FIELDTYPE_UINT16, offsetof(mapstruct, difficulty), 0, 0}, 00048 {"height", FIELDTYPE_UINT16, offsetof(mapstruct, height), FIELDFLAG_READONLY, 0}, 00049 {"width", FIELDTYPE_UINT16, offsetof(mapstruct, width), FIELDFLAG_READONLY, 0}, 00050 {"darkness", FIELDTYPE_UINT8, offsetof(mapstruct, darkness), 0, 0}, 00051 {"path", FIELDTYPE_SHSTR, offsetof(mapstruct, path), FIELDFLAG_READONLY, 0}, 00052 {"enter_x", FIELDTYPE_UINT8, offsetof(mapstruct, enter_x), 0, 0}, 00053 {"enter_y", FIELDTYPE_UINT8, offsetof(mapstruct, enter_y), 0, 0}, 00054 {"region", FIELDTYPE_REGION, offsetof(mapstruct, region), FIELDFLAG_READONLY, 0}, 00055 {"bg_music", FIELDTYPE_CSTR, offsetof(mapstruct, bg_music), 0, 0}, 00056 {"weather", FIELDTYPE_CSTR, offsetof(mapstruct, weather), 0, 0} 00057 }; 00058 /* @endcparser */ 00059 00064 /* @cparser MAP_FLAG_(.*) 00065 * @page plugin_python_map_flags Python map flags 00066 * <h2>Python map flags</h2> 00067 * List of the map flags and their meaning. */ 00068 static char *mapflag_names[] = 00069 { 00070 "f_outdoor", "f_unique", "f_fixed_rtime", "f_nomagic", 00071 "f_nopriest", "f_noharm", "f_nosummon", "f_fixed_login", 00072 "f_player_no_save", "f_unused2", "f_unused3", "f_pvp", 00073 "f_no_save" 00074 }; 00075 /* @endcparser */ 00076 00078 #define NUM_MAPFLAGS (sizeof(mapflag_names) / sizeof(mapflag_names[0])) 00079 00091 static PyObject *Atrinik_Map_GetFirstObject(Atrinik_Map *map, PyObject *args) 00092 { 00093 int x, y; 00094 object *val = NULL; 00095 mapstruct *m = map->map; 00096 00097 if (!PyArg_ParseTuple(args, "ii", &x, &y)) 00098 { 00099 return NULL; 00100 } 00101 00102 if ((m = hooks->get_map_from_coord(m, &x, &y))) 00103 { 00104 /* Since map objects are loaded in reverse mode, the last one in 00105 * in the list is actually the first. */ 00106 val = GET_MAP_OB_LAST(m, x, y); 00107 } 00108 00109 return wrap_object(val); 00110 } 00111 00118 static PyObject *Atrinik_Map_GetLastObject(Atrinik_Map *map, PyObject *args) 00119 { 00120 int x, y; 00121 object *val = NULL; 00122 mapstruct *m = map->map; 00123 00124 if (!PyArg_ParseTuple(args, "ii", &x, &y)) 00125 { 00126 return NULL; 00127 } 00128 00129 if ((m = hooks->get_map_from_coord(m, &x, &y))) 00130 { 00131 /* Since map objects are loaded in reverse mode, the first one in 00132 * in the list is actually the last. */ 00133 val = GET_MAP_OB(m, x, y); 00134 } 00135 00136 return wrap_object(val); 00137 } 00138 00157 static PyObject *Atrinik_Map_GetLayer(Atrinik_Map *map, PyObject *args) 00158 { 00159 int x, y; 00160 uint8 layer; 00161 mapstruct *m; 00162 PyObject *list; 00163 object *tmp; 00164 00165 if (!PyArg_ParseTuple(args, "iiB", &x, &y, &layer)) 00166 { 00167 return NULL; 00168 } 00169 00170 /* Validate the layer ID. */ 00171 if (layer > NUM_LAYERS) 00172 { 00173 PyErr_SetString(PyExc_ValueError, "map.GetLayer(): Invalid layer ID."); 00174 return NULL; 00175 } 00176 00177 if (!(m = hooks->get_map_from_coord(map->map, &x, &y))) 00178 { 00179 RAISE("map.GetLayer(): Unable to get map using get_map_from_coord()."); 00180 } 00181 00182 list = PyList_New(0); 00183 00184 /* Handle layer 0 specially: it's always at the start. */ 00185 if (layer == 0) 00186 { 00187 for (tmp = GET_MAP_OB(m, x, y); tmp && tmp->layer == layer; tmp = tmp->above) 00188 { 00189 PyList_Append(list, wrap_object(tmp)); 00190 } 00191 } 00192 else 00193 { 00194 for (tmp = GET_MAP_OB_LAYER(m, x, y, layer - 1); tmp && tmp->layer == layer; tmp = tmp->above) 00195 { 00196 PyList_Append(list, wrap_object(tmp)); 00197 } 00198 } 00199 00200 return list; 00201 } 00202 00210 static PyObject *Atrinik_Map_GetMapFromCoord(Atrinik_Map *map, PyObject *args) 00211 { 00212 int x, y; 00213 mapstruct *m; 00214 PyObject *tuple; 00215 00216 if (!PyArg_ParseTuple(args, "ii", &x, &y)) 00217 { 00218 return NULL; 00219 } 00220 00221 m = hooks->get_map_from_coord(map->map, &x, &y); 00222 tuple = PyTuple_New(3); 00223 PyTuple_SET_ITEM(tuple, 0, wrap_map(m)); 00224 PyTuple_SET_ITEM(tuple, 1, Py_BuildValue("i", x)); 00225 PyTuple_SET_ITEM(tuple, 2, Py_BuildValue("i", y)); 00226 00227 return tuple; 00228 } 00229 00239 static PyObject *Atrinik_Map_PlaySound(Atrinik_Map *map, PyObject *args, PyObject *keywds) 00240 { 00241 static char *kwlist[] = {"filename", "x", "y", "type", "loop", "volume", NULL}; 00242 const char *filename; 00243 int x, y, type = CMD_SOUND_EFFECT, loop = 0, volume = 0; 00244 00245 if (!PyArg_ParseTupleAndKeywords(args, keywds, "sii|iii", kwlist, &filename, &x, &y, &type, &loop, &volume)) 00246 { 00247 return NULL; 00248 } 00249 00250 hooks->play_sound_map(map->map, type, filename, x, y, loop, volume); 00251 00252 Py_INCREF(Py_None); 00253 return Py_None; 00254 } 00255 00267 static PyObject *Atrinik_Map_Message(Atrinik_Map *map, PyObject *args, PyObject *keywds) 00268 { 00269 static char *kwlist[] = {"x", "y", "distance", "message", "color", "flags", NULL}; 00270 int flags = 0, x, y, d; 00271 const char *message, *color = COLOR_BLUE; 00272 00273 if (!PyArg_ParseTupleAndKeywords(args, keywds, "iiis|si", kwlist, &x, &y, &d, &message, &color, &flags)) 00274 { 00275 return NULL; 00276 } 00277 00278 hooks->new_info_map(flags, color, map->map, x, y, d, message); 00279 00280 Py_INCREF(Py_None); 00281 return Py_None; 00282 } 00283 00292 static PyObject *Atrinik_Map_CreateObject(Atrinik_Map *map, PyObject *args) 00293 { 00294 const char *archname; 00295 int x, y; 00296 archetype *arch; 00297 object *newobj; 00298 00299 if (!PyArg_ParseTuple(args, "sii", &archname, &x, &y)) 00300 { 00301 return NULL; 00302 } 00303 00304 if (!(arch = hooks->find_archetype(archname)) || !(newobj = hooks->arch_to_object(arch))) 00305 { 00306 RAISE("map.CreateObject(): Invalid archetype."); 00307 return NULL; 00308 } 00309 00310 newobj->x = x; 00311 newobj->y = y; 00312 newobj = hooks->insert_ob_in_map(newobj, map->map, NULL, 0); 00313 00314 return wrap_object(newobj); 00315 } 00316 00321 static PyObject *Atrinik_Map_CountPlayers(Atrinik_Map *map, PyObject *args) 00322 { 00323 (void) args; 00324 00325 return Py_BuildValue("i", hooks->players_on_map(map->map)); 00326 } 00327 00332 static PyObject *Atrinik_Map_GetPlayers(Atrinik_Map *map, PyObject *args) 00333 { 00334 PyObject *list = PyList_New(0); 00335 object *tmp; 00336 00337 (void) args; 00338 00339 for (tmp = map->map->player_first; tmp; tmp = CONTR(tmp)->map_above) 00340 { 00341 PyList_Append(list, wrap_object(tmp)); 00342 } 00343 00344 return list; 00345 } 00346 00353 static PyObject *Atrinik_Map_Insert(Atrinik_Map *map, PyObject *args) 00354 { 00355 Atrinik_Object *obj; 00356 sint16 x, y; 00357 00358 if (!PyArg_ParseTuple(args, "O!hh", &Atrinik_ObjectType, &obj, &x, &y)) 00359 { 00360 return NULL; 00361 } 00362 00363 OBJEXISTCHECK(obj); 00364 00365 if (!QUERY_FLAG(obj->obj, FLAG_REMOVED)) 00366 { 00367 hooks->object_remove_esrv_update(obj->obj); 00368 } 00369 00370 obj->obj->x = x; 00371 obj->obj->y = y; 00372 hooks->insert_ob_in_map(obj->obj, map->map, NULL, 0); 00373 00374 Py_INCREF(Py_None); 00375 return Py_None; 00376 } 00377 00384 static PyObject *Atrinik_Map_Wall(Atrinik_Map *map, PyObject *args) 00385 { 00386 sint16 x, y; 00387 00388 if (!PyArg_ParseTuple(args, "hh", &x, &y)) 00389 { 00390 return NULL; 00391 } 00392 00393 return Py_BuildValue("i", hooks->wall(map->map, x, y)); 00394 } 00395 00410 static PyObject *Atrinik_Map_Blocked(Atrinik_Map *map, PyObject *args) 00411 { 00412 Atrinik_Object *ob; 00413 int x, y, terrain; 00414 mapstruct *m; 00415 00416 if (!PyArg_ParseTuple(args, "O!iii", &Atrinik_ObjectType, &ob, &x, &y, &terrain)) 00417 { 00418 return NULL; 00419 } 00420 00421 OBJEXISTCHECK(ob); 00422 00423 if (!(m = hooks->get_map_from_coord(map->map, &x, &y))) 00424 { 00425 RAISE("Unable to get map using get_map_from_coord()."); 00426 } 00427 00428 return Py_BuildValue("i", hooks->blocked(ob->obj, m, x, y, terrain)); 00429 } 00430 00445 static PyObject *Atrinik_Map_FreeSpot(Atrinik_Map *map, PyObject *args) 00446 { 00447 Atrinik_Object *ob; 00448 int x, y, start, stop; 00449 mapstruct *m; 00450 00451 if (!PyArg_ParseTuple(args, "O!iiii", &Atrinik_ObjectType, &ob, &x, &y, &start, &stop)) 00452 { 00453 return NULL; 00454 } 00455 00456 OBJEXISTCHECK(ob); 00457 00458 if (start < 0 || stop < 0) 00459 { 00460 PyErr_SetString(PyExc_ValueError, "map.FreeSpot(): 'start' and 'stop' cannot be negative."); 00461 return NULL; 00462 } 00463 00464 if (stop > SIZEOFFREE) 00465 { 00466 PyErr_SetString(PyExc_ValueError, "map.FreeSpot(): 'stop' cannot be higher than SIZEOFFREE."); 00467 return NULL; 00468 } 00469 00470 if (!(m = hooks->get_map_from_coord(map->map, &x, &y))) 00471 { 00472 return Py_BuildValue("i", -1); 00473 } 00474 00475 return Py_BuildValue("i", hooks->find_free_spot(ob->obj->arch, ob->obj, m, x, y, start, stop + 1)); 00476 } 00477 00481 static PyMethodDef MapMethods[] = 00482 { 00483 {"GetFirstObject", (PyCFunction) Atrinik_Map_GetFirstObject, METH_VARARGS, 0}, 00484 {"GetLastObject", (PyCFunction) Atrinik_Map_GetLastObject, METH_VARARGS, 0}, 00485 {"GetLayer", (PyCFunction) Atrinik_Map_GetLayer, METH_VARARGS, 0}, 00486 {"GetMapFromCoord", (PyCFunction) Atrinik_Map_GetMapFromCoord, METH_VARARGS, 0}, 00487 {"PlaySound", (PyCFunction) Atrinik_Map_PlaySound, METH_VARARGS | METH_KEYWORDS, 0}, 00488 {"Message", (PyCFunction) Atrinik_Map_Message, METH_VARARGS | METH_KEYWORDS, 0}, 00489 {"CreateObject", (PyCFunction) Atrinik_Map_CreateObject, METH_VARARGS, 0}, 00490 {"CountPlayers", (PyCFunction) Atrinik_Map_CountPlayers, METH_NOARGS, 0}, 00491 {"GetPlayers", (PyCFunction) Atrinik_Map_GetPlayers, METH_NOARGS, 0}, 00492 {"Insert", (PyCFunction) Atrinik_Map_Insert, METH_VARARGS, 0}, 00493 {"Wall", (PyCFunction) Atrinik_Map_Wall, METH_VARARGS, 0}, 00494 {"Blocked", (PyCFunction) Atrinik_Map_Blocked, METH_VARARGS, 0}, 00495 {"FreeSpot", (PyCFunction) Atrinik_Map_FreeSpot, METH_VARARGS, 0}, 00496 {NULL, NULL, 0, 0} 00497 }; 00498 00504 static PyObject *get_attribute(Atrinik_Map *map, void *context) 00505 { 00506 return generic_field_getter((fields_struct *) context, map->map); 00507 } 00508 00515 static int set_attribute(Atrinik_Map *map, PyObject *value, void *context) 00516 { 00517 if (generic_field_setter((fields_struct *) context, map->map, value) == -1) 00518 { 00519 return -1; 00520 } 00521 00522 if (((fields_struct *) context)->offset == offsetof(mapstruct, darkness)) 00523 { 00524 hooks->set_map_darkness(map->map, map->map->darkness); 00525 } 00526 00527 return 0; 00528 } 00529 00537 static PyObject *Map_GetFlag(Atrinik_Map *map, void *context) 00538 { 00539 size_t flagno = (size_t) context; 00540 00541 /* Should not happen. */ 00542 if (flagno >= NUM_MAPFLAGS) 00543 { 00544 PyErr_SetString(PyExc_OverflowError, "Invalid flag ID."); 00545 return NULL; 00546 } 00547 00548 Py_ReturnBoolean(map->map->map_flags & (1 << flagno)); 00549 } 00550 00557 static int Map_SetFlag(Atrinik_Map *map, PyObject *val, void *context) 00558 { 00559 size_t flagno = (size_t) context; 00560 00561 /* Should not happen. */ 00562 if (flagno >= NUM_MAPFLAGS) 00563 { 00564 PyErr_SetString(PyExc_OverflowError, "Invalid flag ID."); 00565 return -1; 00566 } 00567 00568 if (val == Py_True) 00569 { 00570 map->map->map_flags |= (1U << flagno); 00571 } 00572 else if (val == Py_False) 00573 { 00574 map->map->map_flags &= ~(1U << flagno); 00575 } 00576 else 00577 { 00578 PyErr_SetString(PyExc_TypeError, "Flag value must be either True or False."); 00579 return -1; 00580 } 00581 00582 return 0; 00583 } 00584 00591 static PyObject *Atrinik_Map_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 00592 { 00593 Atrinik_Map *self; 00594 00595 (void) args; 00596 (void) kwds; 00597 00598 self = (Atrinik_Map *) type->tp_alloc(type, 0); 00599 00600 if (self) 00601 { 00602 self->map = NULL; 00603 } 00604 00605 return (PyObject *) self; 00606 } 00607 00611 static void Atrinik_Map_dealloc(Atrinik_Map *self) 00612 { 00613 self->map = NULL; 00614 #ifndef IS_PY_LEGACY 00615 Py_TYPE(self)->tp_free((PyObject *) self); 00616 #else 00617 self->ob_type->tp_free((PyObject *) self); 00618 #endif 00619 } 00620 00625 static PyObject *Atrinik_Map_str(Atrinik_Map *self) 00626 { 00627 char buf[HUGE_BUF]; 00628 00629 snprintf(buf, sizeof(buf), "[%s \"%s\"]", self->map->path, self->map->name); 00630 return Py_BuildValue("s", buf); 00631 } 00632 00633 static int Atrinik_Map_InternalCompare(Atrinik_Map *left, Atrinik_Map *right) 00634 { 00635 return left->map < right->map ? -1 : (left->map == right->map ? 0 : 1); 00636 } 00637 00638 static PyObject *Atrinik_Map_RichCompare(Atrinik_Map *left, Atrinik_Map *right, int op) 00639 { 00640 if (!left || !right || !PyObject_TypeCheck((PyObject *) left, &Atrinik_MapType) || !PyObject_TypeCheck((PyObject *) right, &Atrinik_MapType)) 00641 { 00642 Py_INCREF(Py_NotImplemented); 00643 return Py_NotImplemented; 00644 } 00645 00646 return generic_rich_compare(op, Atrinik_Map_InternalCompare(left, right)); 00647 } 00648 00650 static PyGetSetDef getseters[NUM_FIELDS + NUM_MAPFLAGS + 1]; 00651 00653 PyTypeObject Atrinik_MapType = 00654 { 00655 #ifdef IS_PY3K 00656 PyVarObject_HEAD_INIT(NULL, 0) 00657 #else 00658 PyObject_HEAD_INIT(NULL) 00659 0, 00660 #endif 00661 "Atrinik.Map", 00662 sizeof(Atrinik_Map), 00663 0, 00664 (destructor) Atrinik_Map_dealloc, 00665 NULL, NULL, NULL, 00666 #ifdef IS_PY3K 00667 NULL, 00668 #else 00669 (cmpfunc) Atrinik_Map_InternalCompare, 00670 #endif 00671 0, 0, 0, 0, 0, 0, 00672 (reprfunc) Atrinik_Map_str, 00673 0, 0, 0, 00674 Py_TPFLAGS_DEFAULT, 00675 "Atrinik maps", 00676 NULL, NULL, 00677 (richcmpfunc) Atrinik_Map_RichCompare, 00678 0, 0, 0, 00679 MapMethods, 00680 0, 00681 getseters, 00682 0, 0, 0, 0, 0, 0, 0, 00683 Atrinik_Map_new, 00684 0, 0, 0, 0, 0, 0, 0, 0 00685 #ifndef IS_PY_LEGACY 00686 , 0 00687 #endif 00688 }; 00689 00694 int Atrinik_Map_init(PyObject *module) 00695 { 00696 size_t i, flagno; 00697 00698 /* Field getters */ 00699 for (i = 0; i < NUM_FIELDS; i++) 00700 { 00701 PyGetSetDef *def = &getseters[i]; 00702 00703 def->name = fields[i].name; 00704 def->get = (getter) get_attribute; 00705 def->set = (setter) set_attribute; 00706 def->doc = NULL; 00707 def->closure = (void *) &fields[i]; 00708 } 00709 00710 /* Flag getters */ 00711 for (flagno = 0; flagno < NUM_MAPFLAGS; flagno++) 00712 { 00713 PyGetSetDef *def = &getseters[i++]; 00714 00715 def->name = mapflag_names[flagno]; 00716 def->get = (getter) Map_GetFlag; 00717 def->set = (setter) Map_SetFlag; 00718 def->doc = NULL; 00719 def->closure = (void *) flagno; 00720 } 00721 00722 getseters[i].name = NULL; 00723 00724 Atrinik_MapType.tp_new = PyType_GenericNew; 00725 00726 if (PyType_Ready(&Atrinik_MapType) < 0) 00727 { 00728 return 0; 00729 } 00730 00731 Py_INCREF(&Atrinik_MapType); 00732 PyModule_AddObject(module, "Map", (PyObject *) &Atrinik_MapType); 00733 00734 return 1; 00735 } 00736 00741 PyObject *wrap_map(mapstruct *what) 00742 { 00743 Atrinik_Map *wrapper; 00744 00745 /* Return None if no map was to be wrapped. */ 00746 if (!what) 00747 { 00748 Py_INCREF(Py_None); 00749 return Py_None; 00750 } 00751 00752 wrapper = PyObject_NEW(Atrinik_Map, &Atrinik_MapType); 00753 00754 if (wrapper) 00755 { 00756 wrapper->map = what; 00757 } 00758 00759 return (PyObject *) wrapper; 00760 }
1.7.4