|
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_player_fields Python player fields 00036 * <h2>Python player fields</h2> 00037 * List of the player fields and their meaning. */ 00038 static fields_struct fields[] = 00039 { 00040 {"next", FIELDTYPE_PLAYER, offsetof(player, next), FIELDFLAG_READONLY, 0}, 00041 {"prev", FIELDTYPE_PLAYER, offsetof(player, prev), FIELDFLAG_READONLY, 0}, 00042 00043 {"party", FIELDTYPE_PARTY, offsetof(player, party), FIELDFLAG_READONLY, 0}, 00044 /* Shall not be modified in any way. Instead, one should use @ref Atrinik_Player_Fix "player.Fix()", 00045 * which will set class_ob to the last @ref CLASS object it finds in 00046 * player's inventory. In some cases, this is done automatically after 00047 * a script has finished executing (say events do this, for example). */ 00048 {"class_ob", FIELDTYPE_OBJECT, offsetof(player, class_ob), FIELDFLAG_READONLY, 0}, 00049 {"savebed_map", FIELDTYPE_CARY, offsetof(player, savebed_map), 0, sizeof(((player *) NULL)->savebed_map)}, 00050 {"bed_x", FIELDTYPE_SINT16, offsetof(player, bed_x), 0, 0}, 00051 {"bed_y", FIELDTYPE_SINT16, offsetof(player, bed_y), 0, 0}, 00052 {"ob", FIELDTYPE_OBJECT, offsetof(player, ob), FIELDFLAG_READONLY, 0}, 00053 {"quest_container", FIELDTYPE_OBJECT, offsetof(player, quest_container), FIELDFLAG_READONLY, 0}, 00054 {"dm_stealth", FIELDTYPE_BOOLEAN, offsetof(player, dm_stealth), 0, 0}, 00055 {"target_object", FIELDTYPE_OBJECTREF, offsetof(player, target_object), 0, offsetof(player, target_object_count)}, 00056 {"no_shout", FIELDTYPE_BOOLEAN, offsetof(player, no_shout), 0, 0}, 00057 {"known_spells", FIELDTYPE_LIST, offsetof(player, known_spells), 0, FIELDTYPE_KNOWN_SPELLS}, 00058 {"cmd_permissions", FIELDTYPE_LIST, offsetof(player, cmd_permissions), 0, FIELDTYPE_CMD_PERMISSIONS}, 00059 {"factions", FIELDTYPE_LIST, offsetof(player, faction_ids), 0, FIELDTYPE_FACTIONS}, 00060 {"fame", FIELDTYPE_SINT64, offsetof(player, fame), 0, FIELDTYPE_FACTIONS}, 00061 00062 {"s_ext_title_flag", FIELDTYPE_BOOLEAN, offsetof(player, socket.ext_title_flag), 0, 0}, 00063 {"s_host", FIELDTYPE_CSTR, offsetof(player, socket.host), FIELDFLAG_READONLY, 0}, 00064 {"s_socket_version", FIELDTYPE_UINT32, offsetof(player, socket.socket_version), FIELDFLAG_READONLY, 0} 00065 }; 00066 /* @endcparser */ 00067 00095 static PyObject *Atrinik_Player_GetEquipment(Atrinik_Player *pl, PyObject *args) 00096 { 00097 int slot; 00098 00099 if (!PyArg_ParseTuple(args, "i", &slot)) 00100 { 00101 return NULL; 00102 } 00103 00104 if (slot < 0 || slot >= PLAYER_EQUIP_MAX) 00105 { 00106 PyErr_SetString(PyExc_ValueError, "Invalid slot number."); 00107 return NULL; 00108 } 00109 00110 return wrap_object(pl->pl->equipment[slot]); 00111 } 00112 00121 static PyObject *Atrinik_Player_CanCarry(Atrinik_Player *pl, PyObject *what) 00122 { 00123 uint32 weight; 00124 00125 if (PyObject_TypeCheck(what, &Atrinik_ObjectType)) 00126 { 00127 OBJEXISTCHECK((Atrinik_Object *) what); 00128 weight = WEIGHT_NROF(((Atrinik_Object *) what)->obj, ((Atrinik_Object *) what)->obj->nrof); 00129 } 00130 else if (PyInt_Check(what)) 00131 { 00132 weight = PyInt_AsLong(what); 00133 } 00134 else 00135 { 00136 PyErr_SetString(PyExc_ValueError, "Invalid value for 'what' parameter."); 00137 return NULL; 00138 } 00139 00140 Py_ReturnBoolean(hooks->player_can_carry(pl->pl->ob, weight)); 00141 } 00142 00153 static PyObject *Atrinik_Player_GetSkill(Atrinik_Player *pl, PyObject *args) 00154 { 00155 sint32 type; 00156 uint32 id; 00157 00158 if (!PyArg_ParseTuple(args, "iI", &type, &id)) 00159 { 00160 return NULL; 00161 } 00162 00163 if (type == SKILL) 00164 { 00165 if (id >= NROFSKILLS) 00166 { 00167 PyErr_SetString(PyExc_ValueError, "player.GetSkill(): 'id' is not valid for TYPE_SKILL."); 00168 return NULL; 00169 } 00170 00171 return wrap_object(pl->pl->skill_ptr[id]); 00172 } 00173 else if (type == EXPERIENCE) 00174 { 00175 if (id >= MAX_EXP_CAT) 00176 { 00177 PyErr_SetString(PyExc_ValueError, "player.GetSkill(): 'id' is not valid for TYPE_EXPERIENCE."); 00178 return NULL; 00179 } 00180 00181 return wrap_object(pl->pl->exp_ptr[id]); 00182 } 00183 else 00184 { 00185 PyErr_SetString(PyExc_ValueError, "player.GetSkill(): 'type' is not valid."); 00186 return NULL; 00187 } 00188 } 00189 00196 static PyObject *Atrinik_Player_AddExp(Atrinik_Player *pl, PyObject *args) 00197 { 00198 uint32 skill; 00199 sint64 exp_gain; 00200 int exact = 0; 00201 00202 if (!PyArg_ParseTuple(args, "IL|i", &skill, &exp_gain, &exact)) 00203 { 00204 return NULL; 00205 } 00206 00207 hooks->add_exp(pl->pl->ob, exp_gain, skill, exact); 00208 00209 Py_INCREF(Py_None); 00210 return Py_None; 00211 } 00212 00219 static PyObject *Atrinik_Player_WriteToSocket(Atrinik_Player *pl, PyObject *args) 00220 { 00221 char command_id; 00222 const char *command_data; 00223 int command_data_len; 00224 00225 if (!PyArg_ParseTuple(args, "bs#", &command_id, &command_data, &command_data_len)) 00226 { 00227 return NULL; 00228 } 00229 00230 hooks->Write_String_To_Socket(&pl->pl->socket, command_id, command_data, command_data_len); 00231 00232 Py_INCREF(Py_None); 00233 return Py_None; 00234 } 00235 00242 static PyObject *Atrinik_Player_BankDeposit(Atrinik_Player *pl, PyObject *args) 00243 { 00244 const char *text; 00245 int ret; 00246 sint64 value; 00247 00248 if (!PyArg_ParseTuple(args, "s", &text)) 00249 { 00250 return NULL; 00251 } 00252 00253 ret = hooks->bank_deposit(pl->pl->ob, text, &value); 00254 00255 return Py_BuildValue("(iL)", ret, value); 00256 } 00257 00264 static PyObject *Atrinik_Player_BankWithdraw(Atrinik_Player *pl, PyObject *args) 00265 { 00266 const char *text; 00267 int ret; 00268 sint64 value; 00269 00270 if (!PyArg_ParseTuple(args, "s", &text)) 00271 { 00272 return NULL; 00273 } 00274 00275 ret = hooks->bank_withdraw(pl->pl->ob, text, &value); 00276 00277 return Py_BuildValue("(iL)", ret, value); 00278 } 00279 00284 static PyObject *Atrinik_Player_BankBalance(Atrinik_Player *pl, PyObject *args) 00285 { 00286 (void) args; 00287 00288 return Py_BuildValue("L", hooks->bank_get_balance(pl->pl->ob)); 00289 } 00290 00301 static PyObject *Atrinik_Player_SwapApartments(Atrinik_Player *pl, PyObject *args) 00302 { 00303 const char *mapold, *mapnew; 00304 int x, y; 00305 00306 if (!PyArg_ParseTuple(args, "ssii", &mapold, &mapnew, &x, &y)) 00307 { 00308 return NULL; 00309 } 00310 00311 Py_ReturnBoolean(hooks->swap_apartments(mapold, mapnew, x, y, pl->pl->ob)); 00312 } 00313 00320 static PyObject *Atrinik_Player_ExecuteCommand(Atrinik_Player *pl, PyObject *args) 00321 { 00322 const char *command; 00323 char *cp; 00324 int ret; 00325 00326 if (!PyArg_ParseTuple(args, "s", &command)) 00327 { 00328 return NULL; 00329 } 00330 00331 if (pl->pl->state != ST_PLAYING) 00332 { 00333 PyErr_SetString(AtrinikError, "ExecuteCommand(): Player is not in a state to execute commands."); 00334 return NULL; 00335 } 00336 00337 /* Make a copy of the command, since execute_newserver_command 00338 * modifies the string. */ 00339 cp = hooks->strdup_local(command); 00340 ret = hooks->execute_newserver_command(pl->pl->ob, cp); 00341 free(cp); 00342 00343 return Py_BuildValue("i", ret); 00344 } 00345 00351 static PyObject *Atrinik_Player_DoKnowSpell(Atrinik_Player *pl, PyObject *args) 00352 { 00353 int spell; 00354 00355 if (!PyArg_ParseTuple(args, "i", &spell)) 00356 { 00357 return NULL; 00358 } 00359 00360 Py_ReturnBoolean(hooks->check_spell_known(pl->pl->ob, spell)); 00361 } 00362 00368 static PyObject *Atrinik_Player_AcquireSpell(Atrinik_Player *pl, PyObject *args) 00369 { 00370 int spell, learn = 1; 00371 00372 if (!PyArg_ParseTuple(args, "i|i", &spell, &learn)) 00373 { 00374 return NULL; 00375 } 00376 00377 if (learn) 00378 { 00379 hooks->do_learn_spell(pl->pl->ob, spell, 0); 00380 } 00381 else 00382 { 00383 hooks->do_forget_spell(pl->pl->ob, spell); 00384 } 00385 00386 Py_INCREF(Py_None); 00387 return Py_None; 00388 } 00389 00395 static PyObject *Atrinik_Player_DoKnowSkill(Atrinik_Player *pl, PyObject *args) 00396 { 00397 int skill; 00398 00399 if (!PyArg_ParseTuple(args, "i", &skill)) 00400 { 00401 return NULL; 00402 } 00403 00404 Py_ReturnBoolean(pl->pl->skill_ptr[skill]); 00405 } 00406 00411 static PyObject *Atrinik_Player_AcquireSkill(Atrinik_Player *pl, PyObject *args) 00412 { 00413 int skill; 00414 00415 if (!PyArg_ParseTuple(args, "i", &skill)) 00416 { 00417 return NULL; 00418 } 00419 00420 hooks->learn_skill(pl->pl->ob, NULL, NULL, skill, 0); 00421 00422 Py_INCREF(Py_None); 00423 return Py_None; 00424 } 00425 00430 static PyObject *Atrinik_Player_FindMarkedObject(Atrinik_Player *pl, PyObject *args) 00431 { 00432 (void) args; 00433 00434 return wrap_object(hooks->find_marked_object(pl->pl->ob)); 00435 } 00436 00446 static PyObject *Atrinik_Player_Sound(Atrinik_Player *pl, PyObject *args, PyObject *keywds) 00447 { 00448 static char *kwlist[] = {"filename", "type", "x", "y", "loop", "volume", NULL}; 00449 const char *filename; 00450 int type = CMD_SOUND_EFFECT, x = 0, y = 0, loop = 0, volume = 0; 00451 00452 if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|iiiii", kwlist, &filename, &type, &x, &y, &loop, &volume)) 00453 { 00454 return NULL; 00455 } 00456 00457 hooks->play_sound_player_only(pl->pl, type, filename, x, y, loop, volume); 00458 00459 Py_INCREF(Py_None); 00460 return Py_None; 00461 } 00462 00467 static PyObject *Atrinik_Player_Examine(Atrinik_Player *pl, PyObject *args) 00468 { 00469 Atrinik_Object *obj; 00470 00471 if (!PyArg_ParseTuple(args, "O!", &Atrinik_ObjectType, &obj)) 00472 { 00473 return NULL; 00474 } 00475 00476 hooks->examine(pl->pl->ob, obj->obj); 00477 00478 Py_INCREF(Py_None); 00479 return Py_None; 00480 } 00481 00485 static PyMethodDef methods[] = 00486 { 00487 {"GetEquipment", (PyCFunction) Atrinik_Player_GetEquipment, METH_VARARGS, 0}, 00488 {"CanCarry", (PyCFunction) Atrinik_Player_CanCarry, METH_O, 0}, 00489 {"GetSkill", (PyCFunction) Atrinik_Player_GetSkill, METH_VARARGS, 0}, 00490 {"AddExp", (PyCFunction) Atrinik_Player_AddExp, METH_VARARGS, 0}, 00491 {"WriteToSocket", (PyCFunction) Atrinik_Player_WriteToSocket, METH_VARARGS, 0}, 00492 {"BankDeposit", (PyCFunction) Atrinik_Player_BankDeposit, METH_VARARGS, 0}, 00493 {"BankWithdraw", (PyCFunction) Atrinik_Player_BankWithdraw, METH_VARARGS, 0}, 00494 {"BankBalance", (PyCFunction) Atrinik_Player_BankBalance, METH_NOARGS, 0}, 00495 {"SwapApartments", (PyCFunction) Atrinik_Player_SwapApartments, METH_VARARGS, 0}, 00496 {"ExecuteCommand", (PyCFunction) Atrinik_Player_ExecuteCommand, METH_VARARGS, 0}, 00497 {"DoKnowSpell", (PyCFunction) Atrinik_Player_DoKnowSpell, METH_VARARGS, 0}, 00498 {"AcquireSpell", (PyCFunction) Atrinik_Player_AcquireSpell, METH_VARARGS, 0}, 00499 {"DoKnowSkill", (PyCFunction) Atrinik_Player_DoKnowSkill, METH_VARARGS, 0}, 00500 {"AcquireSkill", (PyCFunction) Atrinik_Player_AcquireSkill, METH_VARARGS, 0}, 00501 {"FindMarkedObject", (PyCFunction) Atrinik_Player_FindMarkedObject, METH_NOARGS, 0}, 00502 {"Sound", (PyCFunction) Atrinik_Player_Sound, METH_VARARGS | METH_KEYWORDS, 0}, 00503 {"Examine", (PyCFunction) Atrinik_Player_Examine, METH_VARARGS, 0}, 00504 {NULL, NULL, 0, 0} 00505 }; 00506 00512 static PyObject *get_attribute(Atrinik_Player *pl, void *context) 00513 { 00514 return generic_field_getter((fields_struct *) context, pl->pl); 00515 } 00516 00523 static int set_attribute(Atrinik_Player *pl, PyObject *value, void *context) 00524 { 00525 fields_struct *field = (fields_struct *) context; 00526 00527 if (generic_field_setter(field, pl->pl, value) == -1) 00528 { 00529 return -1; 00530 } 00531 00532 if (field->offset == offsetof(player, target_object)) 00533 { 00534 hooks->send_target_command(pl->pl); 00535 } 00536 00537 return 0; 00538 } 00539 00546 static PyObject *Atrinik_Player_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 00547 { 00548 Atrinik_Player *pl; 00549 00550 (void) args; 00551 (void) kwds; 00552 00553 pl = (Atrinik_Player *) type->tp_alloc(type, 0); 00554 00555 if (pl) 00556 { 00557 pl->pl = NULL; 00558 } 00559 00560 return (PyObject *) pl; 00561 } 00562 00566 static void Atrinik_Player_dealloc(Atrinik_Player *pl) 00567 { 00568 pl->pl = NULL; 00569 #ifndef IS_PY_LEGACY 00570 Py_TYPE(pl)->tp_free((PyObject *) pl); 00571 #else 00572 pl->ob_type->tp_free((PyObject *) pl); 00573 #endif 00574 } 00575 00580 static PyObject *Atrinik_Player_str(Atrinik_Player *pl) 00581 { 00582 return Py_BuildValue("s", pl->pl->ob->name); 00583 } 00584 00585 static int Atrinik_Player_InternalCompare(Atrinik_Player *left, Atrinik_Player *right) 00586 { 00587 return (left->pl < right->pl ? -1 : (left->pl == right->pl ? 0 : 1)); 00588 } 00589 00590 static PyObject *Atrinik_Player_RichCompare(Atrinik_Player *left, Atrinik_Player *right, int op) 00591 { 00592 if (!left || !right || !PyObject_TypeCheck((PyObject *) left, &Atrinik_PlayerType) || !PyObject_TypeCheck((PyObject *) right, &Atrinik_PlayerType)) 00593 { 00594 Py_INCREF(Py_NotImplemented); 00595 return Py_NotImplemented; 00596 } 00597 00598 return generic_rich_compare(op, Atrinik_Player_InternalCompare(left, right)); 00599 } 00600 00603 static PyGetSetDef getseters[NUM_FIELDS + 1]; 00604 00606 PyTypeObject Atrinik_PlayerType = 00607 { 00608 #ifdef IS_PY3K 00609 PyVarObject_HEAD_INIT(NULL, 0) 00610 #else 00611 PyObject_HEAD_INIT(NULL) 00612 0, 00613 #endif 00614 "Atrinik.Player", 00615 sizeof(Atrinik_Player), 00616 0, 00617 (destructor) Atrinik_Player_dealloc, 00618 NULL, NULL, NULL, 00619 #ifdef IS_PY3K 00620 NULL, 00621 #else 00622 (cmpfunc) Atrinik_Player_InternalCompare, 00623 #endif 00624 0, 0, 0, 0, 0, 0, 00625 (reprfunc) Atrinik_Player_str, 00626 0, 0, 0, 00627 Py_TPFLAGS_DEFAULT, 00628 "Atrinik players", 00629 NULL, NULL, 00630 (richcmpfunc) Atrinik_Player_RichCompare, 00631 0, 0, 0, 00632 methods, 00633 0, 00634 getseters, 00635 0, 0, 0, 0, 0, 0, 0, 00636 Atrinik_Player_new, 00637 0, 0, 0, 0, 0, 0, 0, 0 00638 #ifndef IS_PY_LEGACY 00639 , 0 00640 #endif 00641 }; 00642 00647 int Atrinik_Player_init(PyObject *module) 00648 { 00649 size_t i; 00650 00651 /* Field getters */ 00652 for (i = 0; i < NUM_FIELDS; i++) 00653 { 00654 PyGetSetDef *def = &getseters[i]; 00655 00656 def->name = fields[i].name; 00657 def->get = (getter) get_attribute; 00658 def->set = (setter) set_attribute; 00659 def->doc = NULL; 00660 def->closure = (void *) &fields[i]; 00661 } 00662 00663 getseters[i].name = NULL; 00664 00665 Atrinik_PlayerType.tp_new = PyType_GenericNew; 00666 00667 if (PyType_Ready(&Atrinik_PlayerType) < 0) 00668 { 00669 return 0; 00670 } 00671 00672 Py_INCREF(&Atrinik_PlayerType); 00673 PyModule_AddObject(module, "Player", (PyObject *) &Atrinik_PlayerType); 00674 00675 return 1; 00676 } 00677 00682 PyObject *wrap_player(player *pl) 00683 { 00684 Atrinik_Player *wrapper; 00685 00686 /* Return None if no player was to be wrapped. */ 00687 if (!pl) 00688 { 00689 Py_INCREF(Py_None); 00690 return Py_None; 00691 } 00692 00693 wrapper = PyObject_NEW(Atrinik_Player, &Atrinik_PlayerType); 00694 00695 if (wrapper) 00696 { 00697 wrapper->pl = pl; 00698 } 00699 00700 return (PyObject *) wrapper; 00701 }
1.7.4