|
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_object_fields Python object fields 00036 * <h2>Python object fields</h2> 00037 * List of the object fields and their meaning. */ 00038 static fields_struct fields[] = 00039 { 00040 {"below", FIELDTYPE_OBJECT, offsetof(object, below), FIELDFLAG_READONLY, 0}, 00041 {"above", FIELDTYPE_OBJECT, offsetof(object, above), FIELDFLAG_READONLY, 0}, 00042 {"inv", FIELDTYPE_OBJECT, offsetof(object, inv), FIELDFLAG_READONLY, 0}, 00043 {"env", FIELDTYPE_OBJECT, offsetof(object, env), FIELDFLAG_READONLY, 0}, 00044 {"map", FIELDTYPE_MAP, offsetof(object, map), FIELDFLAG_READONLY, 0}, 00045 {"name", FIELDTYPE_SHSTR, offsetof(object, name), FIELDFLAG_PLAYER_READONLY, 0}, 00046 {"custom_name", FIELDTYPE_SHSTR, offsetof(object, custom_name), 0, 0}, 00047 {"title", FIELDTYPE_SHSTR, offsetof(object, title), 0, 0}, 00048 {"race", FIELDTYPE_SHSTR, offsetof(object, race), 0, 0}, 00049 {"slaying", FIELDTYPE_SHSTR, offsetof(object, slaying), 0, 0}, 00050 {"msg", FIELDTYPE_SHSTR, offsetof(object, msg), 0, 0}, 00051 {"artifact", FIELDTYPE_SHSTR, offsetof(object, artifact), 0, 0}, 00052 {"weight", FIELDTYPE_SINT32, offsetof(object, weight), 0, 0}, 00053 {"count", FIELDTYPE_UINT32, offsetof(object, count), FIELDFLAG_READONLY, 0}, 00054 00055 {"weight_limit", FIELDTYPE_UINT32, offsetof(object, weight_limit), 0, 0}, 00056 {"carrying", FIELDTYPE_SINT32, offsetof(object, carrying), 0, 0}, 00057 {"path_attuned", FIELDTYPE_UINT32, offsetof(object, path_attuned), 0, 0}, 00058 {"path_repelled", FIELDTYPE_UINT32, offsetof(object, path_repelled), 0, 0}, 00059 {"path_denied", FIELDTYPE_UINT32, offsetof(object, path_denied), 0, 0}, 00060 {"value", FIELDTYPE_SINT64, offsetof(object, value), 0, 0}, 00061 {"nrof", FIELDTYPE_UINT32, offsetof(object, nrof), 0, 0}, 00062 00063 {"enemy", FIELDTYPE_OBJECTREF, offsetof(object, enemy), FIELDFLAG_PLAYER_READONLY, offsetof(object, enemy_count)}, 00064 {"attacked_by", FIELDTYPE_OBJECTREF, offsetof(object, attacked_by), FIELDFLAG_READONLY, offsetof(object, attacked_by_count)}, 00065 {"owner", FIELDTYPE_OBJECTREF, offsetof(object, owner), FIELDFLAG_READONLY, offsetof(object, ownercount)}, 00066 00067 {"x", FIELDTYPE_SINT16, offsetof(object, x), FIELDFLAG_READONLY, 0}, 00068 {"y", FIELDTYPE_SINT16, offsetof(object, y), FIELDFLAG_READONLY, 0}, 00069 {"attacked_by_distance", FIELDTYPE_SINT16, offsetof(object, attacked_by_distance), 0, 0}, 00070 {"last_damage", FIELDTYPE_UINT16, offsetof(object, last_damage), 0, 0}, 00071 {"terrain_type", FIELDTYPE_UINT16, offsetof(object, terrain_type), 0, 0}, 00072 {"terrain_flag", FIELDTYPE_UINT16, offsetof(object, terrain_flag), 0, 0}, 00073 {"material", FIELDTYPE_UINT16, offsetof(object, material), 0, 0}, 00074 {"material_real", FIELDTYPE_SINT16, offsetof(object, material_real), 0, 0}, 00075 00076 {"last_heal", FIELDTYPE_SINT16, offsetof(object, last_heal), 0, 0}, 00077 {"last_sp", FIELDTYPE_SINT16, offsetof(object, last_sp), 0, 0}, 00078 {"last_grace", FIELDTYPE_SINT16, offsetof(object, last_grace), 0, 0}, 00079 {"last_eat", FIELDTYPE_SINT16, offsetof(object, last_eat), 0, 0}, 00080 00081 {"magic", FIELDTYPE_SINT8, offsetof(object, magic), 0, 0}, 00082 {"state", FIELDTYPE_UINT8, offsetof(object, state), 0, 0}, 00083 {"level", FIELDTYPE_SINT8, offsetof(object, level), FIELDFLAG_PLAYER_READONLY, 0}, 00084 {"direction", FIELDTYPE_SINT8, offsetof(object, direction), 0, 0}, 00085 {"facing", FIELDTYPE_SINT8, offsetof(object, facing), 0, 0}, 00086 {"quick_pos", FIELDTYPE_UINT8, offsetof(object, quick_pos), 0, 0}, 00087 {"quickslot", FIELDTYPE_UINT8, offsetof(object, quickslot), FIELDFLAG_READONLY, 0}, 00088 00089 {"type", FIELDTYPE_UINT8, offsetof(object, type), 0, 0}, 00090 {"sub_type", FIELDTYPE_UINT8, offsetof(object, sub_type), 0, 0}, 00091 {"item_quality", FIELDTYPE_UINT8, offsetof(object, item_quality), 0, 0}, 00092 {"item_condition", FIELDTYPE_UINT8, offsetof(object, item_condition), 0, 0}, 00093 {"item_race", FIELDTYPE_UINT8, offsetof(object, item_race), 0, 0}, 00094 {"item_level", FIELDTYPE_UINT8, offsetof(object, item_level), 0, 0}, 00095 {"item_skill", FIELDTYPE_UINT8, offsetof(object, item_skill), 0, 0}, 00096 {"glow_radius", FIELDTYPE_SINT8, offsetof(object, glow_radius), 0, 0}, 00097 {"move_status", FIELDTYPE_SINT8, offsetof(object, move_status), 0, 0}, 00098 {"move_type", FIELDTYPE_UINT8, offsetof(object, move_type), 0, 0}, 00099 00100 {"anim_enemy_dir", FIELDTYPE_SINT8, offsetof(object, anim_enemy_dir), 0, 0}, 00101 {"anim_moving_dir", FIELDTYPE_SINT8, offsetof(object, anim_moving_dir), 0, 0}, 00102 {"anim_enemy_dir_last", FIELDTYPE_SINT8, offsetof(object, anim_enemy_dir_last), 0, 0}, 00103 {"anim_moving_dir_last", FIELDTYPE_SINT8, offsetof(object, anim_moving_dir_last), 0, 0}, 00104 {"anim_last_facing", FIELDTYPE_SINT8, offsetof(object, anim_last_facing), 0, 0}, 00105 {"anim_last_facing_last", FIELDTYPE_SINT8, offsetof(object, anim_last_facing_last), 0, 0}, 00106 {"anim_speed", FIELDTYPE_UINT8, offsetof(object, anim_speed), 0, 0}, 00107 {"last_anim", FIELDTYPE_UINT8, offsetof(object, last_anim), 0, 0}, 00108 {"behavior", FIELDTYPE_UINT8, offsetof(object, behavior), 0, 0}, 00109 {"run_away", FIELDTYPE_UINT8, offsetof(object, run_away), 0, 0}, 00110 00111 {"layer", FIELDTYPE_UINT8, offsetof(object, layer), 0, 0}, 00112 {"speed", FIELDTYPE_FLOAT, offsetof(object, speed), FIELDFLAG_PLAYER_READONLY, 0}, 00113 {"speed_left", FIELDTYPE_FLOAT, offsetof(object, speed_left), 0, 0}, 00114 {"weapon_speed", FIELDTYPE_FLOAT, offsetof(object, weapon_speed), 0, 0}, 00115 {"weapon_speed_left", FIELDTYPE_FLOAT, offsetof(object, weapon_speed_left), 0, 0}, 00116 {"weapon_speed_add", FIELDTYPE_FLOAT, offsetof(object, weapon_speed_add), 0, 0}, 00117 {"exp", FIELDTYPE_SINT64, offsetof(object, stats.exp), 0, 0}, 00118 00119 {"hp", FIELDTYPE_SINT32, offsetof(object, stats.hp), 0, 0}, 00120 {"maxhp", FIELDTYPE_SINT32, offsetof(object, stats.maxhp), FIELDFLAG_PLAYER_READONLY, 0}, 00121 {"sp", FIELDTYPE_SINT16, offsetof(object, stats.sp), 0, 0}, 00122 {"maxsp", FIELDTYPE_SINT16, offsetof(object, stats.maxsp), FIELDFLAG_PLAYER_READONLY, 0}, 00123 {"grace", FIELDTYPE_SINT16, offsetof(object, stats.grace), 0, 0}, 00124 {"maxgrace", FIELDTYPE_SINT16, offsetof(object, stats.maxgrace), FIELDFLAG_PLAYER_READONLY, 0}, 00125 00126 {"food", FIELDTYPE_SINT16, offsetof(object, stats.food), 0, 0}, 00127 {"dam", FIELDTYPE_SINT16, offsetof(object, stats.dam), FIELDFLAG_PLAYER_READONLY, 0}, 00128 {"wc", FIELDTYPE_SINT16, offsetof(object, stats.wc), FIELDFLAG_PLAYER_READONLY, 0}, 00129 {"ac", FIELDTYPE_SINT16, offsetof(object, stats.ac), FIELDFLAG_PLAYER_READONLY, 0}, 00130 {"wc_range", FIELDTYPE_UINT8, offsetof(object, stats.wc_range), 0, 0}, 00131 00132 {"Str", FIELDTYPE_SINT8, offsetof(object, stats.Str), FIELDFLAG_PLAYER_FIX, 0}, 00133 {"Dex", FIELDTYPE_SINT8, offsetof(object, stats.Dex), FIELDFLAG_PLAYER_FIX, 0}, 00134 {"Con", FIELDTYPE_SINT8, offsetof(object, stats.Con), FIELDFLAG_PLAYER_FIX, 0}, 00135 {"Wis", FIELDTYPE_SINT8, offsetof(object, stats.Wis), FIELDFLAG_PLAYER_FIX, 0}, 00136 {"Cha", FIELDTYPE_SINT8, offsetof(object, stats.Cha), FIELDFLAG_PLAYER_FIX, 0}, 00137 {"Int", FIELDTYPE_SINT8, offsetof(object, stats.Int), FIELDFLAG_PLAYER_FIX, 0}, 00138 {"Pow", FIELDTYPE_SINT8, offsetof(object, stats.Pow), FIELDFLAG_PLAYER_FIX, 0}, 00139 00140 {"arch", FIELDTYPE_ARCH, offsetof(object, arch), 0, 0}, 00141 {"z", FIELDTYPE_SINT16, offsetof(object, z), 0, 0}, 00142 {"zoom", FIELDTYPE_UINT8, offsetof(object, zoom), 0, 0}, 00143 {"rotate", FIELDTYPE_SINT16, offsetof(object, rotate), 0, 0}, 00144 {"align", FIELDTYPE_SINT16, offsetof(object, align), 0, 0}, 00145 {"alpha", FIELDTYPE_UINT8, offsetof(object, alpha), 0, 0}, 00146 /* Returns the object's face in a tuple containing the face name as 00147 * string, and the face ID as integer.\n 00148 * There are a few different ways to set object's face. You can use 00149 * the face name (obj.face = "eyes.101"), the ID (obj.face = 1000), 00150 * or the tuple returned by a previous call to obj.face. */ 00151 {"face", FIELDTYPE_FACE, offsetof(object, face), 0, 0}, 00152 /* Returns the object's animation in a tuple containing the animation 00153 * name as string, and the animation ID as integer.\n 00154 * There are a few different ways to set object's animation. You can 00155 * use the animation name (obj.animation = "raas"), the ID (obj.animation = 100), 00156 * or the tuple returned by a previous call to obj.animation. */ 00157 {"animation", FIELDTYPE_ANIMATION, offsetof(object, animation_id), 0, 0}, 00158 /* See notes for object's animation. */ 00159 {"inv_animation", FIELDTYPE_ANIMATION, offsetof(object, inv_animation_id), 0, 0} 00160 }; 00161 /* @endcparser */ 00162 00173 static PyObject *Atrinik_Object_ActivateRune(Atrinik_Object *obj, PyObject *args) 00174 { 00175 Atrinik_Object *who; 00176 00177 if (!PyArg_ParseTuple(args, "O!", &Atrinik_ObjectType, &who)) 00178 { 00179 return NULL; 00180 } 00181 00182 OBJEXISTCHECK(obj); 00183 OBJEXISTCHECK(who); 00184 00185 if (obj->obj->type != RUNE) 00186 { 00187 PyErr_SetString(PyExc_TypeError, "object.ActivateRune(): 'object' is not a rune."); 00188 return NULL; 00189 } 00190 00191 hooks->spring_trap(obj->obj, who->obj); 00192 00193 Py_INCREF(Py_None); 00194 return Py_None; 00195 } 00196 00201 static PyObject *Atrinik_Object_GetGod(Atrinik_Object *obj, PyObject *args) 00202 { 00203 (void) args; 00204 OBJEXISTCHECK(obj); 00205 00206 return Py_BuildValue("s", hooks->determine_god(obj->obj)); 00207 } 00208 00215 static PyObject *Atrinik_Object_SetGod(Atrinik_Object *obj, PyObject *args) 00216 { 00217 const char *name; 00218 00219 if (!PyArg_ParseTuple(args, "s", &name)) 00220 { 00221 return NULL; 00222 } 00223 00224 OBJEXISTCHECK(obj); 00225 00226 if (hooks->command_rskill(obj->obj, "divine prayers")) 00227 { 00228 object *god = hooks->find_god(name); 00229 00230 hooks->become_follower(obj->obj, god); 00231 } 00232 00233 Py_INCREF(Py_None); 00234 return Py_None; 00235 } 00236 00245 static PyObject *Atrinik_Object_TeleportTo(Atrinik_Object *obj, PyObject *args, PyObject *keywds) 00246 { 00247 static char *kwlist[] = {"path", "x", "y", "unique", "sound", NULL}; 00248 const char *path; 00249 object *tmp; 00250 int x, y, unique = 0, sound = 1; 00251 00252 if (!PyArg_ParseTupleAndKeywords(args, keywds, "sii|ii", kwlist, &path, &x, &y, &unique, &sound)) 00253 { 00254 return NULL; 00255 } 00256 00257 OBJEXISTCHECK(obj); 00258 00259 tmp = hooks->get_object(); 00260 FREE_AND_COPY_HASH(EXIT_PATH(tmp), path); 00261 EXIT_X(tmp) = x; 00262 EXIT_Y(tmp) = y; 00263 00264 if (unique) 00265 { 00266 tmp->last_eat = MAP_PLAYER_MAP; 00267 } 00268 00269 hooks->enter_exit(obj->obj, tmp); 00270 00271 if (obj->obj->map && sound) 00272 { 00273 hooks->play_sound_map(obj->obj->map, CMD_SOUND_EFFECT, "teleport.ogg", obj->obj->x, obj->obj->y, 0, 0); 00274 } 00275 00276 Py_INCREF(Py_None); 00277 return Py_None; 00278 } 00279 00284 static PyObject *Atrinik_Object_InsertInto(Atrinik_Object *obj, PyObject *args) 00285 { 00286 Atrinik_Object *where; 00287 object *tmp; 00288 00289 if (!PyArg_ParseTuple(args, "O!", &Atrinik_ObjectType, &where)) 00290 { 00291 return NULL; 00292 } 00293 00294 OBJEXISTCHECK(obj); 00295 OBJEXISTCHECK(where); 00296 00297 if (!QUERY_FLAG(obj->obj, FLAG_REMOVED)) 00298 { 00299 hooks->object_remove_esrv_update(obj->obj); 00300 } 00301 00302 tmp = hooks->insert_ob_in_ob(obj->obj, where->obj); 00303 00304 if (tmp) 00305 { 00306 object *pl = hooks->object_need_esrv_update(tmp); 00307 00308 if (pl) 00309 { 00310 hooks->esrv_send_item(pl, tmp); 00311 } 00312 } 00313 00314 Py_INCREF(Py_None); 00315 return Py_None; 00316 } 00317 00331 static PyObject *Atrinik_Object_Apply(Atrinik_Object *obj, PyObject *args) 00332 { 00333 Atrinik_Object *what; 00334 int flags; 00335 00336 if (!PyArg_ParseTuple(args, "O!i", &Atrinik_ObjectType, &what, &flags)) 00337 { 00338 return NULL; 00339 } 00340 00341 OBJEXISTCHECK(obj); 00342 OBJEXISTCHECK(what); 00343 00344 return Py_BuildValue("i", hooks->manual_apply(obj->obj, what->obj, flags)); 00345 } 00346 00353 static PyObject *Atrinik_Object_Take(Atrinik_Object *obj, PyObject *what) 00354 { 00355 OBJEXISTCHECK(obj); 00356 00357 if (PyObject_TypeCheck(what, &Atrinik_ObjectType)) 00358 { 00359 OBJEXISTCHECK((Atrinik_Object *) what); 00360 hooks->pick_up(obj->obj, ((Atrinik_Object *) what)->obj, 0); 00361 } 00362 else if (PyString_Check(what)) 00363 { 00364 hooks->command_take(obj->obj, PyString_AsString(what)); 00365 } 00366 else 00367 { 00368 PyErr_SetString(PyExc_TypeError, "object.Take(): Argument 'what' must be either Atrinik object or string."); 00369 return NULL; 00370 } 00371 00372 Py_INCREF(Py_None); 00373 return Py_None; 00374 } 00375 00382 static PyObject *Atrinik_Object_Drop(Atrinik_Object *obj, PyObject *what) 00383 { 00384 OBJEXISTCHECK(obj); 00385 00386 if (PyObject_TypeCheck(what, &Atrinik_ObjectType)) 00387 { 00388 OBJEXISTCHECK((Atrinik_Object *) what); 00389 hooks->drop(obj->obj, ((Atrinik_Object *) what)->obj, 0); 00390 } 00391 else if (PyString_Check(what)) 00392 { 00393 hooks->command_drop(obj->obj, PyString_AsString(what)); 00394 } 00395 else 00396 { 00397 PyErr_SetString(PyExc_TypeError, "object.Drop(): Argument 'what' must be either Atrinik object or string."); 00398 return NULL; 00399 } 00400 00401 Py_INCREF(Py_None); 00402 return Py_None; 00403 } 00404 00409 static PyObject *Atrinik_Object_Communicate(Atrinik_Object *obj, PyObject *args) 00410 { 00411 const char *message; 00412 char *str; 00413 00414 if (!PyArg_ParseTuple(args, "s", &message)) 00415 { 00416 return NULL; 00417 } 00418 00419 OBJEXISTCHECK(obj); 00420 00421 str = hooks->strdup_local(message); 00422 hooks->communicate(obj->obj, str); 00423 free(str); 00424 00425 Py_INCREF(Py_None); 00426 return Py_None; 00427 } 00428 00434 static PyObject *Atrinik_Object_Say(Atrinik_Object *obj, PyObject *args) 00435 { 00436 const char *message; 00437 char buf[HUGE_BUF]; 00438 int mode = 0; 00439 00440 if (!PyArg_ParseTuple(args, "s|i", &message, &mode)) 00441 { 00442 return NULL; 00443 } 00444 00445 OBJEXISTCHECK(obj); 00446 00447 if (mode) 00448 { 00449 hooks->new_info_map(0, COLOR_NAVY, obj->obj->map, obj->obj->x, obj->obj->y, MAP_INFO_NORMAL, message); 00450 } 00451 else 00452 { 00453 snprintf(buf, sizeof(buf), "%s says: %s", hooks->query_name(obj->obj, NULL), message); 00454 hooks->new_info_map(0, COLOR_NAVY, obj->obj->map, obj->obj->x, obj->obj->y, MAP_INFO_NORMAL, buf); 00455 } 00456 00457 Py_INCREF(Py_None); 00458 return Py_None; 00459 } 00460 00468 static PyObject *Atrinik_Object_SayTo(Atrinik_Object *obj, PyObject *args) 00469 { 00470 Atrinik_Object *target; 00471 const char *message; 00472 int mode = 0; 00473 00474 if (!PyArg_ParseTuple(args, "O!s|i", &Atrinik_ObjectType, &target, &message, &mode)) 00475 { 00476 return NULL; 00477 } 00478 00479 OBJEXISTCHECK(obj); 00480 OBJEXISTCHECK(target); 00481 00482 if (mode) 00483 { 00484 hooks->new_draw_info(0, COLOR_NAVY, target->obj, message); 00485 } 00486 else 00487 { 00488 char buf[HUGE_BUF]; 00489 00490 snprintf(buf, sizeof(buf), "%s talks to %s.", hooks->query_name(obj->obj, NULL), hooks->query_name(target->obj, NULL)); 00491 hooks->new_info_map_except(0, COLOR_WHITE, obj->obj->map, obj->obj->x, obj->obj->y, MAP_INFO_NORMAL, obj->obj, target->obj, buf); 00492 00493 snprintf(buf, sizeof(buf), "\n%s says: %s", hooks->query_name(obj->obj, NULL), message); 00494 hooks->new_draw_info(0, COLOR_NAVY, target->obj, buf); 00495 } 00496 00497 Py_INCREF(Py_None); 00498 return Py_None; 00499 } 00500 00508 static PyObject *Atrinik_Object_Write(Atrinik_Object *obj, PyObject *args, PyObject *keywds) 00509 { 00510 static char *kwlist[] = {"message", "color", "flags", NULL}; 00511 int flags = 0; 00512 const char *message, *color = COLOR_ORANGE; 00513 00514 if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|si", kwlist, &message, &color, &flags)) 00515 { 00516 return NULL; 00517 } 00518 00519 OBJEXISTCHECK(obj); 00520 00521 hooks->new_draw_info(flags, color, obj->obj, message); 00522 00523 Py_INCREF(Py_None); 00524 return Py_None; 00525 } 00526 00531 static PyObject *Atrinik_Object_GetGender(Atrinik_Object *obj, PyObject *args) 00532 { 00533 (void) args; 00534 OBJEXISTCHECK(obj); 00535 00536 return Py_BuildValue("i", hooks->object_get_gender(obj->obj)); 00537 } 00538 00543 static PyObject *Atrinik_Object_SetGender(Atrinik_Object *obj, PyObject *args) 00544 { 00545 int gender; 00546 00547 if (!PyArg_ParseTuple(args, "i", &gender)) 00548 { 00549 return NULL; 00550 } 00551 00552 OBJEXISTCHECK(obj); 00553 00554 /* Set object to neuter */ 00555 CLEAR_FLAG(obj->obj, FLAG_IS_MALE); 00556 CLEAR_FLAG(obj->obj, FLAG_IS_FEMALE); 00557 00558 if (gender == GENDER_MALE || gender == GENDER_HERMAPHRODITE) 00559 { 00560 SET_FLAG(obj->obj, FLAG_IS_MALE); 00561 } 00562 00563 if (gender == GENDER_FEMALE || gender == GENDER_HERMAPHRODITE) 00564 { 00565 SET_FLAG(obj->obj, FLAG_IS_FEMALE); 00566 } 00567 00568 /* Update the player's client if object was a player. */ 00569 if (obj->obj->type == PLAYER) 00570 { 00571 CONTR(obj->obj)->socket.ext_title_flag = 1; 00572 } 00573 00574 Py_INCREF(Py_None); 00575 return Py_None; 00576 } 00577 00594 static PyObject *Atrinik_Object_SetGuildForce(Atrinik_Object *obj, PyObject *args) 00595 { 00596 object *walk; 00597 const char *guild; 00598 00599 if (!PyArg_ParseTuple(args, "s", &guild)) 00600 { 00601 return NULL; 00602 } 00603 00604 OBJEXISTCHECK(obj); 00605 00606 if (obj->obj->type != PLAYER) 00607 { 00608 Py_INCREF(Py_None); 00609 return Py_None; 00610 } 00611 00612 for (walk = obj->obj->inv; walk != NULL; walk = walk->below) 00613 { 00614 if (walk->name == hooks->shstr_cons->GUILD_FORCE && walk->arch->name == hooks->shstr_cons->guild_force) 00615 { 00616 /* We find the rank of the player, now change it to new one */ 00617 if (walk->title) 00618 { 00619 FREE_AND_CLEAR_HASH(walk->title); 00620 } 00621 00622 if (guild && strcmp(guild, "")) 00623 { 00624 FREE_AND_COPY_HASH(walk->title, guild); 00625 } 00626 00627 /* Demand update to client */ 00628 CONTR(obj->obj)->socket.ext_title_flag = 1; 00629 00630 return wrap_object(walk); 00631 } 00632 } 00633 00634 LOG(llevDebug, "Python Warning:: SetGuildForce: Object %s has no guild_force!\n", hooks->query_name(obj->obj, NULL)); 00635 00636 Py_INCREF(Py_None); 00637 return Py_None; 00638 } 00639 00644 static PyObject *Atrinik_Object_GetGuildForce(Atrinik_Object *obj, PyObject *args) 00645 { 00646 object *walk; 00647 00648 (void) args; 00649 OBJEXISTCHECK(obj); 00650 00651 if (obj->obj->type != PLAYER) 00652 { 00653 Py_INCREF(Py_None); 00654 return Py_None; 00655 } 00656 00657 for (walk = obj->obj->inv; walk != NULL; walk = walk->below) 00658 { 00659 if (walk->name == hooks->shstr_cons->GUILD_FORCE && walk->arch->name == hooks->shstr_cons->guild_force) 00660 { 00661 return wrap_object(walk); 00662 } 00663 } 00664 00665 LOG(llevDebug, "Python Warning:: GetGuildForce: Object %s has no guild_force!\n", hooks->query_name(obj->obj, NULL)); 00666 00667 Py_INCREF(Py_None); 00668 return Py_None; 00669 } 00670 00675 static PyObject *Atrinik_Object_Fix(Atrinik_Object *obj, PyObject *args) 00676 { 00677 (void) args; 00678 OBJEXISTCHECK(obj); 00679 00680 hooks->fix_player(obj->obj); 00681 00682 Py_INCREF(Py_None); 00683 return Py_None; 00684 } 00685 00694 static PyObject *Atrinik_Object_Hit(Atrinik_Object *obj, PyObject *args) 00695 { 00696 Atrinik_Object *target; 00697 int damage; 00698 00699 if (!PyArg_ParseTuple(args, "O!i", &Atrinik_ObjectType, &target, &damage)) 00700 { 00701 return NULL; 00702 } 00703 00704 OBJEXISTCHECK(obj); 00705 OBJEXISTCHECK(target); 00706 00707 /* Cannot kill objects that are not alive or on map. */ 00708 if (!target->obj->map || !IS_LIVE(target->obj)) 00709 { 00710 PyErr_SetString(PyExc_ValueError, "object.Hit(): Invalid object to hit/kill."); 00711 return NULL; 00712 } 00713 00714 /* Kill the target. */ 00715 if (damage == -1) 00716 { 00717 target->obj->stats.hp = -1; 00718 hooks->kill_object(target->obj, 0, obj->obj, 0); 00719 } 00720 /* Do damage. */ 00721 else 00722 { 00723 hooks->hit_player(target->obj, damage, obj->obj, 0); 00724 } 00725 00726 Py_INCREF(Py_None); 00727 return Py_None; 00728 } 00729 00741 static PyObject *Atrinik_Object_Cast(Atrinik_Object *obj, PyObject *args, PyObject *keywds) 00742 { 00743 static char *kwlist[] = {"target", "spell", "mode", "direction", "option", NULL}; 00744 Atrinik_Object *target = NULL; 00745 int spell, direction = 0, mode = -1; 00746 const char *option = NULL; 00747 00748 if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|O!iis", kwlist, &spell, &Atrinik_ObjectType, &target, &mode, &direction, &option)) 00749 { 00750 return NULL; 00751 } 00752 00753 OBJEXISTCHECK(obj); 00754 00755 if (target) 00756 { 00757 OBJEXISTCHECK(target); 00758 } 00759 00760 /* Figure out the mode automatically. */ 00761 if (mode == -1) 00762 { 00763 if (obj->obj->type != PLAYER) 00764 { 00765 mode = CAST_NPC; 00766 } 00767 else 00768 { 00769 mode = CAST_NORMAL; 00770 } 00771 } 00772 /* Ensure the mode is valid. */ 00773 else if (mode == CAST_NORMAL && target && target != obj && obj->obj->type != PLAYER) 00774 { 00775 mode = CAST_NPC; 00776 } 00777 00778 hooks->cast_spell(target ? target->obj : obj->obj, obj->obj, direction, spell, 1, mode, option); 00779 00780 Py_INCREF(Py_None); 00781 return Py_None; 00782 } 00783 00795 static PyObject *Atrinik_Object_CreatePlayerForce(Atrinik_Object *obj, PyObject *args) 00796 { 00797 const char *txt; 00798 object *myob; 00799 int expire_time = 0; 00800 00801 if (!PyArg_ParseTuple(args, "s|i", &txt, &expire_time)) 00802 { 00803 return NULL; 00804 } 00805 00806 OBJEXISTCHECK(obj); 00807 00808 myob = hooks->get_archetype("player_force"); 00809 00810 if (!myob) 00811 { 00812 LOG(llevDebug, "Python WARNING:: CreatePlayerForce: Can't find archetype 'player_force'\n"); 00813 RAISE("Can't find archetype 'player_force'"); 00814 } 00815 00816 /* For temporary forces */ 00817 if (expire_time > 0) 00818 { 00819 SET_FLAG(myob, FLAG_IS_USED_UP); 00820 myob->stats.food = expire_time; 00821 myob->speed = 0.02f; 00822 hooks->update_ob_speed(myob); 00823 } 00824 00825 /* Setup the force and put it in activator */ 00826 if (myob->name) 00827 { 00828 FREE_AND_CLEAR_HASH(myob->name); 00829 } 00830 00831 FREE_AND_COPY_HASH(myob->name, txt); 00832 myob = hooks->insert_ob_in_ob(myob, obj->obj); 00833 00834 hooks->esrv_send_item(obj->obj, myob); 00835 00836 return wrap_object(myob); 00837 } 00838 00848 static PyObject *Atrinik_Object_CreatePlayerInfo(Atrinik_Object *obj, PyObject *args) 00849 { 00850 const char *txt; 00851 object *myob; 00852 00853 if (!PyArg_ParseTuple(args, "s", &txt)) 00854 { 00855 return NULL; 00856 } 00857 00858 OBJEXISTCHECK(obj); 00859 00860 myob = hooks->get_archetype("player_info"); 00861 00862 if (!myob) 00863 { 00864 LOG(llevDebug, "Python WARNING:: CreatePlayerInfo: Can't find archetype 'player_info'\n"); 00865 RAISE("Can't find archtype 'player_info'"); 00866 } 00867 00868 /* Setup the info and put it in activator */ 00869 if (myob->name) 00870 { 00871 FREE_AND_CLEAR_HASH(myob->name); 00872 } 00873 00874 FREE_AND_COPY_HASH(myob->name, txt); 00875 myob = hooks->insert_ob_in_ob(myob, obj->obj); 00876 00877 hooks->esrv_send_item(obj->obj, myob); 00878 00879 return wrap_object(myob); 00880 } 00881 00889 static PyObject *Atrinik_Object_GetPlayerInfo(Atrinik_Object *obj, PyObject *args) 00890 { 00891 const char *name; 00892 object *walk; 00893 00894 if (!PyArg_ParseTuple(args, "s", &name)) 00895 { 00896 return NULL; 00897 } 00898 00899 OBJEXISTCHECK(obj); 00900 00901 /* Get the first linked player info arch in this inventory */ 00902 for (walk = obj->obj->inv; walk != NULL; walk = walk->below) 00903 { 00904 if (walk->name && walk->arch->name == hooks->shstr_cons->player_info && !strcmp(walk->name, name)) 00905 { 00906 return wrap_object(walk); 00907 } 00908 } 00909 00910 Py_INCREF(Py_None); 00911 return Py_None; 00912 } 00913 00921 static PyObject *Atrinik_Object_GetNextPlayerInfo(Atrinik_Object *obj, PyObject *args) 00922 { 00923 Atrinik_Object *myob; 00924 char name[128]; 00925 object *walk; 00926 00927 (void) obj; 00928 00929 if (!PyArg_ParseTuple(args, "O!", &Atrinik_ObjectType, &myob)) 00930 { 00931 return NULL; 00932 } 00933 00934 OBJEXISTCHECK(myob); 00935 00936 /* Our check parameters: arch "force_info", name of this arch */ 00937 strncpy(name, STRING_OBJ_NAME(myob->obj), 127); 00938 name[63] = '\0'; 00939 00940 /* Get the next linked player_info arch in this inventory */ 00941 for (walk = myob->obj->below; walk != NULL; walk = walk->below) 00942 { 00943 if (walk->name && walk->arch->name == hooks->shstr_cons->player_info && !strcmp(walk->name, name)) 00944 { 00945 return wrap_object(walk); 00946 } 00947 } 00948 00949 Py_INCREF(Py_None); 00950 return Py_None; 00951 } 00952 00960 static PyObject *Atrinik_Object_CreateForce(Atrinik_Object *obj, PyObject *args) 00961 { 00962 const char *name; 00963 int expire_time = 0; 00964 object *force; 00965 00966 if (!PyArg_ParseTuple(args, "s|i", &name, &expire_time)) 00967 { 00968 return NULL; 00969 } 00970 00971 OBJEXISTCHECK(obj); 00972 00973 force = hooks->get_archetype("force"); 00974 00975 if (expire_time > 0) 00976 { 00977 SET_FLAG(force, FLAG_IS_USED_UP); 00978 force->stats.food = expire_time; 00979 force->speed = 0.02f; 00980 } 00981 else 00982 { 00983 force->speed = 0.0; 00984 } 00985 00986 hooks->update_ob_speed(force); 00987 FREE_AND_COPY_HASH(force->name, name); 00988 00989 return wrap_object(hooks->insert_ob_in_ob(force, obj->obj)); 00990 } 00991 01001 static PyObject *Atrinik_Object_CreateObject(Atrinik_Object *obj, PyObject *args, PyObject *keywds) 01002 { 01003 static char *kwlist[] = {"archname", "nrof", "value", "identified", NULL}; 01004 const char *archname; 01005 uint32 nrof = 1; 01006 sint64 value = -1; 01007 int identified = 1; 01008 archetype *at; 01009 object *tmp, *env; 01010 01011 if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|ILi", kwlist, &archname, &nrof, &value, &identified)) 01012 { 01013 return NULL; 01014 } 01015 01016 OBJEXISTCHECK(obj); 01017 01018 at = hooks->find_archetype(archname); 01019 01020 if (!at) 01021 { 01022 PyErr_Format(AtrinikError, "object.CreateObject(): The archetype '%s' doesn't exist.", archname); 01023 return NULL; 01024 } 01025 01026 tmp = hooks->arch_to_object(at); 01027 01028 if (value != -1) 01029 { 01030 tmp->value = value; 01031 } 01032 01033 if (nrof > 1) 01034 { 01035 tmp->nrof = nrof; 01036 } 01037 01038 if (identified) 01039 { 01040 SET_FLAG(tmp, FLAG_IDENTIFIED); 01041 } 01042 01043 tmp = hooks->insert_ob_in_ob(tmp, obj->obj); 01044 01045 /* Make sure inventory image/text is updated */ 01046 for (env = obj->obj; env; env = env->env) 01047 { 01048 if (env->type == PLAYER) 01049 { 01050 hooks->esrv_send_item(env, tmp); 01051 } 01052 } 01053 01054 return wrap_object(tmp); 01055 } 01056 01061 static object *object_find_object(object *tmp, int mode, shstr *archname, shstr *name, shstr *title, int type, PyObject *list, int unpaid) 01062 { 01063 object *tmp2; 01064 01065 while (tmp) 01066 { 01067 if ((!archname || tmp->arch->name == archname) && (!name || tmp->name == name) && (!title || tmp->title == title) && (type == -1 || tmp->type == type) && (!unpaid || QUERY_FLAG(tmp, FLAG_UNPAID))) 01068 { 01069 if (list) 01070 { 01071 PyList_Append(list, wrap_object(tmp)); 01072 } 01073 else 01074 { 01075 return tmp; 01076 } 01077 } 01078 01079 if (tmp->inv && (mode == INVENTORY_ALL || (mode == INVENTORY_CONTAINERS && tmp->type == CONTAINER))) 01080 { 01081 tmp2 = object_find_object(tmp->inv, mode, archname, name, title, type, list, unpaid); 01082 01083 if (tmp2 && !list) 01084 { 01085 return tmp2; 01086 } 01087 } 01088 01089 tmp = tmp->below; 01090 } 01091 01092 return NULL; 01093 } 01109 static PyObject *Atrinik_Object_FindObject(Atrinik_Object *obj, PyObject *args, PyObject *keywds) 01110 { 01111 static char *kwlist[] = {"mode", "archname", "name", "title", "type", "multiple", "unpaid", NULL}; 01112 uint8 mode = INVENTORY_ONLY; 01113 int type = -1, multiple = 0, unpaid = 0; 01114 shstr *archname = NULL, *name = NULL, *title = NULL; 01115 object *match; 01116 PyObject *list = NULL; 01117 01118 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|Bzzziii", kwlist, &mode, &archname, &name, &title, &type, &multiple, &unpaid)) 01119 { 01120 return NULL; 01121 } 01122 01123 OBJEXISTCHECK(obj); 01124 01125 if (!archname && !name && !title && type == -1 && !unpaid) 01126 { 01127 PyErr_SetString(PyExc_ValueError, "object.FindObject(): No conditions to search for given."); 01128 return NULL; 01129 } 01130 01131 if (multiple) 01132 { 01133 list = PyList_New(0); 01134 } 01135 01136 /* Try to find the strings we got from Python in the shared strings 01137 * library. If they are not found, it is impossible that the inventory 01138 * lookups succeed. */ 01139 if (archname) 01140 { 01141 archname = hooks->find_string(archname); 01142 01143 if (!archname) 01144 { 01145 Py_INCREF(Py_None); 01146 return Py_None; 01147 } 01148 } 01149 01150 if (name) 01151 { 01152 name = hooks->find_string(name); 01153 01154 if (!name) 01155 { 01156 Py_INCREF(Py_None); 01157 return Py_None; 01158 } 01159 } 01160 01161 if (title) 01162 { 01163 title = hooks->find_string(title); 01164 01165 if (!title) 01166 { 01167 Py_INCREF(Py_None); 01168 return Py_None; 01169 } 01170 } 01171 01172 match = object_find_object(obj->obj->inv, mode, archname, name, title, type, list, unpaid); 01173 01174 if (multiple) 01175 { 01176 return list; 01177 } 01178 01179 if (match) 01180 { 01181 return wrap_object(match); 01182 } 01183 01184 Py_INCREF(Py_None); 01185 return Py_None; 01186 } 01187 01195 static PyObject *Atrinik_Object_Remove(Atrinik_Object *obj, PyObject *args) 01196 { 01197 (void) args; 01198 OBJEXISTCHECK(obj); 01199 01200 /* Don't allow removing any of the involved objects. Messes things up... */ 01201 if (current_context->activator == obj->obj || current_context->who == obj->obj || current_context->other == obj->obj) 01202 { 01203 RAISE("You are not allowed to remove one of the active objects."); 01204 } 01205 01206 hooks->object_remove_esrv_update(obj->obj); 01207 01208 Py_INCREF(Py_None); 01209 return Py_None; 01210 } 01211 01220 static PyObject *Atrinik_Object_SetPosition(Atrinik_Object *obj, PyObject *args) 01221 { 01222 int x, y; 01223 01224 if (!PyArg_ParseTuple(args, "ii", &x, &y)) 01225 { 01226 return NULL; 01227 } 01228 01229 OBJEXISTCHECK(obj); 01230 01231 hooks->transfer_ob(obj->obj, x, y, 0, NULL, NULL); 01232 01233 Py_INCREF(Py_None); 01234 return Py_None; 01235 } 01236 01243 static PyObject *Atrinik_Object_CastIdentify(Atrinik_Object *obj, PyObject *args) 01244 { 01245 Atrinik_Object *target; 01246 PyObject *marked = NULL; 01247 object *ob = NULL; 01248 int mode; 01249 01250 if (!PyArg_ParseTuple(args, "O!i|O", &Atrinik_ObjectType, &target, &mode, &marked)) 01251 { 01252 return NULL; 01253 } 01254 01255 OBJEXISTCHECK(obj); 01256 OBJEXISTCHECK(target); 01257 01258 if (marked && marked != Py_None) 01259 { 01260 if (!PyObject_TypeCheck(marked, &Atrinik_ObjectType)) 01261 { 01262 PyErr_SetString(PyExc_TypeError, "Must be Atrinik.Object"); 01263 return NULL; 01264 } 01265 01266 OBJEXISTCHECK((Atrinik_Object *) marked); 01267 ob = ((Atrinik_Object *) marked)->obj; 01268 } 01269 01270 hooks->cast_identify(target->obj, obj->obj->level, ob, mode); 01271 hooks->play_sound_map(obj->obj->map, CMD_SOUND_EFFECT, hooks->spells[SP_IDENTIFY].sound, obj->obj->x, obj->obj->y, 0, 0); 01272 01273 Py_INCREF(Py_None); 01274 return Py_None; 01275 } 01276 01283 static PyObject *Atrinik_Object_Save(Atrinik_Object *obj, PyObject *args) 01284 { 01285 PyObject *ret; 01286 StringBuffer *sb; 01287 char *result; 01288 01289 (void) args; 01290 OBJEXISTCHECK(obj); 01291 01292 sb = hooks->stringbuffer_new(); 01293 hooks->dump_object_rec(obj->obj, sb); 01294 result = hooks->stringbuffer_finish(sb); 01295 ret = Py_BuildValue("s", result); 01296 free(result); 01297 01298 return ret; 01299 } 01300 01307 static PyObject *Atrinik_Object_GetCost(Atrinik_Object *obj, PyObject *args) 01308 { 01309 Atrinik_Object *what; 01310 int flag; 01311 01312 if (!PyArg_ParseTuple(args, "O!i", &Atrinik_ObjectType, &what, &flag)) 01313 { 01314 return NULL; 01315 } 01316 01317 OBJEXISTCHECK(obj); 01318 OBJEXISTCHECK(what); 01319 01320 return Py_BuildValue("L", hooks->query_cost(what->obj, obj->obj, flag)); 01321 } 01322 01329 static PyObject *Atrinik_Object_GetMoney(Atrinik_Object *obj, PyObject *args) 01330 { 01331 (void) args; 01332 OBJEXISTCHECK(obj); 01333 01334 return Py_BuildValue("L", hooks->query_money(obj->obj)); 01335 } 01336 01343 static PyObject *Atrinik_Object_PayAmount(Atrinik_Object *obj, PyObject *args) 01344 { 01345 sint64 value; 01346 01347 if (!PyArg_ParseTuple(args, "L", &value)) 01348 { 01349 return NULL; 01350 } 01351 01352 OBJEXISTCHECK(obj); 01353 01354 Py_ReturnBoolean(hooks->pay_for_amount(value, obj->obj)); 01355 } 01356 01369 static PyObject *Atrinik_Object_Clone(Atrinik_Object *obj, PyObject *args) 01370 { 01371 int mode = 0; 01372 object *clone; 01373 01374 if (!PyArg_ParseTuple(args, "|i", &mode)) 01375 { 01376 return NULL; 01377 } 01378 01379 OBJEXISTCHECK(obj); 01380 01381 if (!mode) 01382 { 01383 clone = hooks->object_create_clone(obj->obj); 01384 } 01385 else 01386 { 01387 clone = hooks->get_object(); 01388 hooks->copy_object(obj->obj, clone, 0); 01389 } 01390 01391 if (clone->type == PLAYER || QUERY_FLAG(clone, FLAG_IS_PLAYER)) 01392 { 01393 clone->type = MONSTER; 01394 CLEAR_FLAG(clone, FLAG_IS_PLAYER); 01395 } 01396 01397 return wrap_object(clone); 01398 } 01399 01405 static PyObject *Atrinik_Object_ReadKey(Atrinik_Object *obj, PyObject *args) 01406 { 01407 const char *key; 01408 01409 if (!PyArg_ParseTuple(args, "s", &key)) 01410 { 01411 return NULL; 01412 } 01413 01414 OBJEXISTCHECK(obj); 01415 01416 return Py_BuildValue("s", hooks->object_get_value(obj->obj, key)); 01417 } 01418 01427 static PyObject *Atrinik_Object_WriteKey(Atrinik_Object *obj, PyObject *args) 01428 { 01429 const char *key, *value = NULL; 01430 int add_key = 1; 01431 01432 if (!PyArg_ParseTuple(args, "s|si", &key, &value, &add_key)) 01433 { 01434 return NULL; 01435 } 01436 01437 OBJEXISTCHECK(obj); 01438 01439 return Py_BuildValue("i", hooks->object_set_value(obj->obj, key, value, add_key)); 01440 } 01441 01448 static PyObject *Atrinik_Object_GetName(Atrinik_Object *what, PyObject *args) 01449 { 01450 Atrinik_Object *ob = NULL; 01451 01452 if (!PyArg_ParseTuple(args, "|O!", &Atrinik_ObjectType, &ob)) 01453 { 01454 return NULL; 01455 } 01456 01457 OBJEXISTCHECK(what); 01458 01459 if (ob) 01460 { 01461 OBJEXISTCHECK(ob); 01462 } 01463 01464 return Py_BuildValue("s", hooks->query_short_name(what->obj, ob ? ob->obj : what->obj)); 01465 } 01466 01474 static PyObject *Atrinik_Object_CreateTimer(Atrinik_Object *what, PyObject *args) 01475 { 01476 int mode, timer; 01477 long delay; 01478 01479 if (!PyArg_ParseTuple(args, "li", &delay, &mode)) 01480 { 01481 return NULL; 01482 } 01483 01484 OBJEXISTCHECK(what); 01485 01486 timer = hooks->cftimer_find_free_id(); 01487 01488 if (timer != TIMER_ERR_ID) 01489 { 01490 int res = hooks->cftimer_create(timer, delay, what->obj, mode); 01491 01492 if (res != TIMER_ERR_NONE) 01493 { 01494 timer = res; 01495 } 01496 } 01497 01498 return Py_BuildValue("i", timer); 01499 } 01500 01506 static PyObject *Atrinik_Object_Controller(Atrinik_Object *what, PyObject *args) 01507 { 01508 (void) args; 01509 01510 OBJEXISTCHECK(what); 01511 01512 if (what->obj->type != PLAYER) 01513 { 01514 RAISE("Can only be used on players."); 01515 } 01516 01517 return wrap_player(CONTR(what->obj)); 01518 } 01519 01526 static PyObject *Atrinik_Object_Protection(Atrinik_Object *what, PyObject *args) 01527 { 01528 int nr; 01529 01530 if (!PyArg_ParseTuple(args, "i", &nr)) 01531 { 01532 return NULL; 01533 } 01534 01535 OBJEXISTCHECK(what); 01536 01537 if (nr < 0 || nr >= NROFATTACKS) 01538 { 01539 PyErr_SetString(PyExc_IndexError, "Protection ID is invalid."); 01540 return NULL; 01541 } 01542 01543 return Py_BuildValue("b", what->obj->protection[nr]); 01544 } 01545 01553 static PyObject *Atrinik_Object_SetProtection(Atrinik_Object *what, PyObject *args) 01554 { 01555 int nr; 01556 sint8 val; 01557 01558 if (!PyArg_ParseTuple(args, "ib", &nr, &val)) 01559 { 01560 return NULL; 01561 } 01562 01563 OBJEXISTCHECK(what); 01564 01565 if (nr < 0 || nr >= NROFATTACKS) 01566 { 01567 PyErr_SetString(PyExc_IndexError, "Protection ID is invalid."); 01568 return NULL; 01569 } 01570 01571 what->obj->protection[nr] = val; 01572 01573 Py_INCREF(Py_None); 01574 return Py_None; 01575 } 01576 01583 static PyObject *Atrinik_Object_Attack(Atrinik_Object *what, PyObject *args) 01584 { 01585 int nr; 01586 01587 if (!PyArg_ParseTuple(args, "i", &nr)) 01588 { 01589 return NULL; 01590 } 01591 01592 OBJEXISTCHECK(what); 01593 01594 if (nr < 0 || nr >= NROFATTACKS) 01595 { 01596 PyErr_SetString(PyExc_IndexError, "Attack ID is invalid."); 01597 return NULL; 01598 } 01599 01600 return Py_BuildValue("B", what->obj->attack[nr]); 01601 } 01602 01610 static PyObject *Atrinik_Object_SetAttack(Atrinik_Object *what, PyObject *args) 01611 { 01612 int nr; 01613 uint8 val; 01614 01615 if (!PyArg_ParseTuple(args, "iB", &nr, &val)) 01616 { 01617 return NULL; 01618 } 01619 01620 OBJEXISTCHECK(what); 01621 01622 if (nr < 0 || nr >= NROFATTACKS) 01623 { 01624 PyErr_SetString(PyExc_IndexError, "Attack ID is invalid."); 01625 return NULL; 01626 } 01627 01628 what->obj->attack[nr] = val; 01629 01630 Py_INCREF(Py_None); 01631 return Py_None; 01632 } 01633 01639 static PyObject *Atrinik_Object_ChangeAbil(Atrinik_Object *obj, PyObject *args) 01640 { 01641 Atrinik_Object *what; 01642 01643 if (!PyArg_ParseTuple(args, "O!", &Atrinik_ObjectType, &what)) 01644 { 01645 return NULL; 01646 } 01647 01648 OBJEXISTCHECK(obj); 01649 OBJEXISTCHECK(what); 01650 01651 Py_ReturnBoolean(hooks->change_abil(obj->obj, what->obj)); 01652 } 01653 01659 static PyObject *Atrinik_Object_Decrease(Atrinik_Object *what, PyObject *args) 01660 { 01661 uint32 num = 1; 01662 01663 if (!PyArg_ParseTuple(args, "|I", &num)) 01664 { 01665 return NULL; 01666 } 01667 01668 OBJEXISTCHECK(what); 01669 01670 return wrap_object(hooks->decrease_ob_nr(what->obj, num)); 01671 } 01672 01710 static PyObject *Atrinik_Object_SquaresAround(Atrinik_Object *what, PyObject *args, PyObject *keywds) 01711 { 01712 uint8 range, type = AROUND_ALL; 01713 static char *kwlist[] = {"range", "type", "beyond", "callable", NULL}; 01714 int i, j, xt, yt, beyond = 0; 01715 mapstruct *m; 01716 PyObject *callable = NULL, *list; 01717 01718 if (!PyArg_ParseTupleAndKeywords(args, keywds, "B|BiO", kwlist, &range, &type, &beyond, &callable)) 01719 { 01720 return NULL; 01721 } 01722 01723 OBJEXISTCHECK(what); 01724 01725 if (range == 0) 01726 { 01727 PyErr_SetString(PyExc_ValueError, "SquaresAround(): 'range' must be higher than 0."); 01728 return NULL; 01729 } 01730 01731 if (callable && !PyCallable_Check(callable)) 01732 { 01733 PyErr_SetString(PyExc_TypeError, "Argument 'callable' must be callable."); 01734 return NULL; 01735 } 01736 01737 list = PyList_New(0); 01738 01739 /* Go through the squares in the specified range. */ 01740 for (i = -range; i <= range; i++) 01741 { 01742 for (j = -range; j <= range; j++) 01743 { 01744 xt = what->obj->x + i; 01745 yt = what->obj->y + j; 01746 01747 /* Skip ourselves. */ 01748 if (xt == what->obj->x && yt == what->obj->y) 01749 { 01750 continue; 01751 } 01752 01753 m = hooks->get_map_from_coord(what->obj->map, &xt, &yt); 01754 01755 if (!m) 01756 { 01757 continue; 01758 } 01759 01760 /* We want all squares. */ 01761 if (type == AROUND_ALL && !callable) 01762 { 01763 SQUARES_AROUND_ADD(m, xt, yt); 01764 } 01765 /* Only those that are not blocked by view, or beyond a wall, etc, 01766 * so use the Bresenham algorithm. */ 01767 else if (beyond) 01768 { 01769 int xt2, yt2, fraction, dx2, dy2, stepx, stepy; 01770 mapstruct *m2; 01771 rv_vector rv; 01772 01773 m2 = what->obj->map; 01774 xt2 = what->obj->x; 01775 yt2 = what->obj->y; 01776 01777 if (!hooks->get_rangevector_from_mapcoords(m2, xt2, yt2, m, xt, yt, &rv, RV_NO_DISTANCE)) 01778 { 01779 continue; 01780 } 01781 01782 BRESENHAM_INIT(rv.distance_x, rv.distance_y, fraction, stepx, stepy, dx2, dy2); 01783 01784 while (1) 01785 { 01786 BRESENHAM_STEP(xt2, yt2, fraction, stepx, stepy, dx2, dy2); 01787 m2 = hooks->get_map_from_coord(m2, &xt2, &yt2); 01788 01789 if (m2 == NULL || (type & AROUND_BLOCKSVIEW && GET_MAP_FLAGS(m2, xt2, yt2) & P_BLOCKSVIEW) || (type & AROUND_PLAYER_ONLY && GET_MAP_FLAGS(m2, xt2, yt2) & P_PLAYER_ONLY) || (type & AROUND_WALL && hooks->wall(m2, xt2, yt2)) || (callable && python_call_int(callable, Py_BuildValue("(OiiO)", wrap_map(m2), xt2, yt2, wrap_object(what->obj))))) 01790 { 01791 break; 01792 } 01793 01794 if (m2 == m && xt2 == xt && yt2 == yt) 01795 { 01796 SQUARES_AROUND_ADD(m, xt, yt); 01797 break; 01798 } 01799 } 01800 } 01801 /* We only want to ignore squares that either block view, or have 01802 * a wall, etc, but not any squares behind them. */ 01803 else 01804 { 01805 if ((type & AROUND_BLOCKSVIEW && GET_MAP_FLAGS(m, xt, yt) & P_BLOCKSVIEW) || (type & AROUND_PLAYER_ONLY && GET_MAP_FLAGS(m, xt, yt) & P_PLAYER_ONLY) || (type & AROUND_WALL && hooks->wall(m, xt, yt)) || (callable && python_call_int(callable, Py_BuildValue("(OiiO)", wrap_map(m), xt, yt, wrap_object(what->obj))))) 01806 { 01807 continue; 01808 } 01809 01810 SQUARES_AROUND_ADD(m, xt, yt); 01811 } 01812 } 01813 } 01814 01815 return list; 01816 } 01817 01830 static PyObject *Atrinik_Object_GetRangeVector(Atrinik_Object *obj, PyObject *args) 01831 { 01832 Atrinik_Object *to; 01833 int flags = 0; 01834 rv_vector rv; 01835 PyObject *tuple; 01836 01837 if (!PyArg_ParseTuple(args, "O!|i", &Atrinik_ObjectType, &to, &flags)) 01838 { 01839 return NULL; 01840 } 01841 01842 OBJEXISTCHECK(obj); 01843 OBJEXISTCHECK(to); 01844 01845 if (!hooks->get_rangevector(obj->obj, to->obj, &rv, flags)) 01846 { 01847 Py_INCREF(Py_None); 01848 return Py_None; 01849 } 01850 01851 tuple = PyTuple_New(5); 01852 PyTuple_SET_ITEM(tuple, 0, Py_BuildValue("i", rv.direction)); 01853 PyTuple_SET_ITEM(tuple, 1, Py_BuildValue("i", rv.distance)); 01854 PyTuple_SET_ITEM(tuple, 2, Py_BuildValue("i", rv.distance_x)); 01855 PyTuple_SET_ITEM(tuple, 3, Py_BuildValue("i", rv.distance_y)); 01856 PyTuple_SET_ITEM(tuple, 4, wrap_object(rv.part)); 01857 01858 return tuple; 01859 } 01860 01873 static PyObject *Atrinik_Object_CreateTreasure(Atrinik_Object *obj, PyObject *args, PyObject *keywds) 01874 { 01875 static char *kwlist[] = {"treasure", "level", "flags", "a_chance", NULL}; 01876 const char *treasure_name = NULL; 01877 int level = 0, flags = 0, a_chance = ART_CHANCE_UNSET; 01878 treasurelist *t; 01879 01880 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|ziii", kwlist, &treasure_name, &level, &flags, &a_chance)) 01881 { 01882 return NULL; 01883 } 01884 01885 OBJEXISTCHECK(obj); 01886 01887 /* Figure out the treasure list. */ 01888 if (treasure_name) 01889 { 01890 t = hooks->find_treasurelist(treasure_name); 01891 } 01892 else 01893 { 01894 t = obj->obj->randomitems; 01895 } 01896 01897 /* Invalid treasure list. */ 01898 if (!t) 01899 { 01900 if (treasure_name) 01901 { 01902 PyErr_Format(PyExc_ValueError, "CreateTreasure(): '%s' is not a valid treasure list.", treasure_name); 01903 } 01904 else 01905 { 01906 PyErr_SetString(PyExc_ValueError, "CreateTreasure(): Object has no treasure list."); 01907 } 01908 01909 return NULL; 01910 } 01911 01912 /* Figure out the level if none was given. */ 01913 if (!level) 01914 { 01915 /* Try the object's level first. */ 01916 if (obj->obj->level) 01917 { 01918 level = obj->obj->level; 01919 } 01920 /* Otherwise the map's difficulty. */ 01921 else if (obj->obj->map) 01922 { 01923 level = obj->obj->map->difficulty; 01924 } 01925 /* Default to MAXLEVEL. */ 01926 else 01927 { 01928 level = MAXLEVEL; 01929 } 01930 } 01931 01932 /* Create the treasure. */ 01933 hooks->create_treasure(t, obj->obj, flags, level, T_STYLE_UNSET, a_chance, 0, NULL); 01934 01935 Py_INCREF(Py_None); 01936 return Py_None; 01937 } 01938 01947 static PyObject *Atrinik_Object_Move(Atrinik_Object *obj, PyObject *args) 01948 { 01949 int direction; 01950 01951 if (!PyArg_ParseTuple(args, "i", &direction)) 01952 { 01953 return NULL; 01954 } 01955 01956 OBJEXISTCHECK(obj); 01957 01958 if (!obj->obj->map) 01959 { 01960 PyErr_SetString(AtrinikError, "object.Move(): Object not on map."); 01961 return NULL; 01962 } 01963 01964 if (obj->obj->type == PLAYER) 01965 { 01966 Py_ReturnBoolean(hooks->move_player(obj->obj, direction)); 01967 } 01968 else 01969 { 01970 Py_ReturnBoolean(hooks->move_ob(obj->obj, direction, obj->obj)); 01971 } 01972 } 01973 01977 static PyObject *Atrinik_Object_Activate(Atrinik_Object *obj, PyObject *args) 01978 { 01979 (void) args; 01980 01981 OBJEXISTCHECK(obj); 01982 hooks->push_button(obj->obj); 01983 01984 Py_INCREF(Py_None); 01985 return Py_None; 01986 } 01987 01991 static PyMethodDef methods[] = 01992 { 01993 {"ActivateRune", (PyCFunction) Atrinik_Object_ActivateRune, METH_VARARGS, 0}, 01994 {"GetGod", (PyCFunction) Atrinik_Object_GetGod, METH_NOARGS, 0}, 01995 {"SetGod", (PyCFunction) Atrinik_Object_SetGod, METH_VARARGS, 0}, 01996 {"TeleportTo", (PyCFunction) Atrinik_Object_TeleportTo, METH_VARARGS | METH_KEYWORDS, 0}, 01997 {"InsertInto", (PyCFunction) Atrinik_Object_InsertInto, METH_VARARGS, 0}, 01998 {"Apply", (PyCFunction) Atrinik_Object_Apply, METH_VARARGS, 0}, 01999 {"Take", (PyCFunction) Atrinik_Object_Take, METH_O, 0}, 02000 {"Drop", (PyCFunction) Atrinik_Object_Drop, METH_O, 0}, 02001 {"Communicate", (PyCFunction) Atrinik_Object_Communicate, METH_VARARGS, 0}, 02002 {"Say", (PyCFunction) Atrinik_Object_Say, METH_VARARGS, 0}, 02003 {"SayTo", (PyCFunction) Atrinik_Object_SayTo, METH_VARARGS, 0}, 02004 {"Write", (PyCFunction) Atrinik_Object_Write, METH_VARARGS | METH_KEYWORDS, 0}, 02005 {"GetGender", (PyCFunction) Atrinik_Object_GetGender, METH_NOARGS, 0}, 02006 {"SetGender", (PyCFunction) Atrinik_Object_SetGender, METH_VARARGS, 0}, 02007 {"SetGuildForce", (PyCFunction) Atrinik_Object_SetGuildForce, METH_VARARGS, 0}, 02008 {"GetGuildForce", (PyCFunction) Atrinik_Object_GetGuildForce, METH_NOARGS, 0}, 02009 {"Fix", (PyCFunction) Atrinik_Object_Fix, METH_NOARGS, 0}, 02010 {"Hit", (PyCFunction) Atrinik_Object_Hit, METH_VARARGS, 0}, 02011 {"Cast", (PyCFunction) Atrinik_Object_Cast, METH_VARARGS | METH_KEYWORDS, 0}, 02012 {"CreatePlayerForce", (PyCFunction) Atrinik_Object_CreatePlayerForce, METH_VARARGS, 0}, 02013 {"CreatePlayerInfo", (PyCFunction) Atrinik_Object_CreatePlayerInfo, METH_VARARGS, 0}, 02014 {"GetPlayerInfo", (PyCFunction) Atrinik_Object_GetPlayerInfo, METH_VARARGS, 0}, 02015 {"GetNextPlayerInfo", (PyCFunction) Atrinik_Object_GetNextPlayerInfo, METH_VARARGS, 0}, 02016 {"CreateForce", (PyCFunction) Atrinik_Object_CreateForce, METH_VARARGS, 0}, 02017 {"CreateObject", (PyCFunction) Atrinik_Object_CreateObject, METH_VARARGS | METH_KEYWORDS, 0}, 02018 {"FindObject", (PyCFunction) Atrinik_Object_FindObject, METH_VARARGS | METH_KEYWORDS, 0}, 02019 {"Remove", (PyCFunction) Atrinik_Object_Remove, METH_NOARGS, 0}, 02020 {"SetPosition", (PyCFunction) Atrinik_Object_SetPosition, METH_VARARGS, 0}, 02021 {"CastIdentify", (PyCFunction) Atrinik_Object_CastIdentify, METH_VARARGS, 0}, 02022 {"Save", (PyCFunction) Atrinik_Object_Save, METH_NOARGS, 0}, 02023 {"GetCost", (PyCFunction) Atrinik_Object_GetCost, METH_VARARGS, 0}, 02024 {"GetMoney", (PyCFunction) Atrinik_Object_GetMoney, METH_NOARGS, 0}, 02025 {"PayAmount", (PyCFunction) Atrinik_Object_PayAmount, METH_VARARGS, 0}, 02026 {"Clone", (PyCFunction) Atrinik_Object_Clone, METH_VARARGS, 0}, 02027 {"ReadKey", (PyCFunction) Atrinik_Object_ReadKey, METH_VARARGS, 0}, 02028 {"WriteKey", (PyCFunction) Atrinik_Object_WriteKey, METH_VARARGS, 0}, 02029 {"GetName", (PyCFunction) Atrinik_Object_GetName, METH_VARARGS, 0}, 02030 {"CreateTimer", (PyCFunction) Atrinik_Object_CreateTimer, METH_VARARGS, 0}, 02031 {"Controller", (PyCFunction) Atrinik_Object_Controller, METH_NOARGS, 0}, 02032 {"Protection", (PyCFunction) Atrinik_Object_Protection, METH_VARARGS, 0}, 02033 {"SetProtection", (PyCFunction) Atrinik_Object_SetProtection, METH_VARARGS, 0}, 02034 {"Attack", (PyCFunction) Atrinik_Object_Attack, METH_VARARGS, 0}, 02035 {"SetAttack", (PyCFunction) Atrinik_Object_SetAttack, METH_VARARGS, 0}, 02036 {"ChangeAbil", (PyCFunction) Atrinik_Object_ChangeAbil, METH_VARARGS, 0}, 02037 {"Decrease", (PyCFunction) Atrinik_Object_Decrease, METH_VARARGS, 0}, 02038 {"SquaresAround", (PyCFunction) Atrinik_Object_SquaresAround, METH_VARARGS | METH_KEYWORDS, 0}, 02039 {"GetRangeVector", (PyCFunction) Atrinik_Object_GetRangeVector, METH_VARARGS, 0}, 02040 {"CreateTreasure", (PyCFunction) Atrinik_Object_CreateTreasure, METH_VARARGS | METH_KEYWORDS, 0}, 02041 {"Move", (PyCFunction) Atrinik_Object_Move, METH_VARARGS, 0}, 02042 {"Activate", (PyCFunction) Atrinik_Object_Activate, METH_NOARGS, 0}, 02043 {NULL, NULL, 0, 0} 02044 }; 02045 02051 static PyObject *Object_GetAttribute(Atrinik_Object *obj, void *context) 02052 { 02053 OBJEXISTCHECK(obj); 02054 02055 return generic_field_getter((fields_struct *) context, obj->obj); 02056 } 02057 02064 static int Object_SetAttribute(Atrinik_Object *obj, PyObject *value, void *context) 02065 { 02066 object *tmp; 02067 fields_struct *field = (fields_struct *) context; 02068 02069 OBJEXISTCHECK_INT(obj); 02070 02071 if ((field->flags & FIELDFLAG_PLAYER_READONLY) && obj->obj->type == PLAYER) 02072 { 02073 INTRAISE("Trying to modify a field that is read-only for player objects."); 02074 } 02075 02076 if (generic_field_setter(field, obj->obj, value) == -1) 02077 { 02078 return -1; 02079 } 02080 02081 /* Make sure the inventory image/text is updated. */ 02082 for (tmp = obj->obj->env; tmp; tmp = tmp->env) 02083 { 02084 if (tmp->type == PLAYER) 02085 { 02086 hooks->esrv_send_item(tmp, obj->obj); 02087 } 02088 } 02089 02090 /* Special handling for some player stuff. */ 02091 if (obj->obj->type == PLAYER) 02092 { 02093 switch (field->offset) 02094 { 02095 case offsetof(object, stats.Str): 02096 CONTR(obj->obj)->orig_stats.Str = (sint8) PyInt_AsLong(value); 02097 break; 02098 02099 case offsetof(object, stats.Dex): 02100 CONTR(obj->obj)->orig_stats.Dex = (sint8) PyInt_AsLong(value); 02101 break; 02102 02103 case offsetof(object, stats.Con): 02104 CONTR(obj->obj)->orig_stats.Con = (sint8) PyInt_AsLong(value); 02105 break; 02106 02107 case offsetof(object, stats.Wis): 02108 CONTR(obj->obj)->orig_stats.Wis = (sint8) PyInt_AsLong(value); 02109 break; 02110 02111 case offsetof(object, stats.Pow): 02112 CONTR(obj->obj)->orig_stats.Pow = (sint8) PyInt_AsLong(value); 02113 break; 02114 02115 case offsetof(object, stats.Cha): 02116 CONTR(obj->obj)->orig_stats.Cha = (sint8) PyInt_AsLong(value); 02117 break; 02118 02119 case offsetof(object, stats.Int): 02120 CONTR(obj->obj)->orig_stats.Int = (sint8) PyInt_AsLong(value); 02121 break; 02122 } 02123 02124 if (field->flags & FIELDFLAG_PLAYER_FIX) 02125 { 02126 hooks->fix_player(obj->obj); 02127 } 02128 } 02129 02130 /* Update object's speed. */ 02131 if (field->offset == offsetof(object, speed)) 02132 { 02133 hooks->update_ob_speed(obj->obj); 02134 } 02135 /* Handle object's type changing. */ 02136 else if (field->offset == offsetof(object, type)) 02137 { 02138 /* Changing to a spawn point monster requires special handling: 02139 * as the object was most likely created and put on active list, 02140 * we must remove it from the active list, as spawn point monsters 02141 * are not allowed to be on the list. */ 02142 if (obj->obj->type == SPAWN_POINT_MOB) 02143 { 02144 float old_speed; 02145 02146 /* Store original speed, as in order to actually remove the object 02147 * from the active list, we need to set its speed to 0 and make it 02148 * a non-SPAWN_POINT_MOB type. */ 02149 old_speed = obj->obj->speed; 02150 obj->obj->speed = 0.0f; 02151 obj->obj->type = MONSTER; 02152 /* Remove it from the active list. */ 02153 hooks->update_ob_speed(obj->obj); 02154 02155 /* Restore original speed and type info. */ 02156 obj->obj->speed = old_speed; 02157 obj->obj->type = SPAWN_POINT_MOB; 02158 } 02159 } 02160 /* Direction, update object's facing. */ 02161 else if (field->offset == offsetof(object, direction)) 02162 { 02163 obj->obj->anim_last_facing = obj->obj->anim_last_facing_last = obj->obj->facing = obj->obj->direction; 02164 02165 /* If the object is animated and turnable, updated its face as well. */ 02166 if (obj->obj->animation_id && QUERY_FLAG(obj->obj, FLAG_IS_TURNABLE)) 02167 { 02168 SET_ANIMATION(obj->obj, (NUM_ANIMATIONS(obj->obj) / NUM_FACINGS(obj->obj)) * obj->obj->direction + obj->obj->state); 02169 } 02170 } 02171 02172 return 0; 02173 } 02174 02182 static PyObject *Object_GetFlag(Atrinik_Object *obj, void *context) 02183 { 02184 size_t flagno = (size_t) context; 02185 02186 /* Should not happen. */ 02187 if (flagno >= NUM_FLAGS) 02188 { 02189 PyErr_SetString(PyExc_OverflowError, "Invalid flag ID."); 02190 return NULL; 02191 } 02192 02193 OBJEXISTCHECK(obj); 02194 02195 Py_ReturnBoolean(QUERY_FLAG(obj->obj, flagno)); 02196 } 02197 02204 static int Object_SetFlag(Atrinik_Object *obj, PyObject *val, void *context) 02205 { 02206 object *env; 02207 size_t flagno = (size_t) context; 02208 02209 /* Should not happen. */ 02210 if (flagno >= NUM_FLAGS) 02211 { 02212 PyErr_SetString(PyExc_OverflowError, "Invalid flag ID."); 02213 return -1; 02214 } 02215 02216 OBJEXISTCHECK_INT(obj); 02217 02218 if (val == Py_True) 02219 { 02220 SET_FLAG(obj->obj, flagno); 02221 } 02222 else if (val == Py_False) 02223 { 02224 CLEAR_FLAG(obj->obj, flagno); 02225 } 02226 else 02227 { 02228 PyErr_SetString(PyExc_TypeError, "Flag value must be either True or False."); 02229 return -1; 02230 } 02231 02232 /* Make sure the inventory image/text/etc is updated */ 02233 for (env = obj->obj->env; env; env = env->env) 02234 { 02235 if (env->type == PLAYER) 02236 { 02237 hooks->esrv_send_item(env, obj->obj); 02238 } 02239 } 02240 02241 return 0; 02242 } 02243 02250 static PyObject *Atrinik_Object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 02251 { 02252 Atrinik_Object *self = (Atrinik_Object *) type->tp_alloc(type, 0); 02253 02254 (void) args; 02255 (void) kwds; 02256 02257 if (self) 02258 { 02259 self->obj = NULL; 02260 self->count = 0; 02261 } 02262 02263 return (PyObject *) self; 02264 } 02265 02269 static void Atrinik_Object_dealloc(PyObject *self) 02270 { 02271 ((Atrinik_Object *) self)->obj = NULL; 02272 ((Atrinik_Object *) self)->count = 0; 02273 #ifndef IS_PY_LEGACY 02274 Py_TYPE(self)->tp_free(self); 02275 #else 02276 self->ob_type->tp_free(self); 02277 #endif 02278 } 02279 02284 static PyObject *Atrinik_Object_str(Atrinik_Object *self) 02285 { 02286 OBJEXISTCHECK(self); 02287 return PyString_FromFormat("[%s \"%s\"]", STRING_OBJ_ARCH_NAME(self->obj), STRING_OBJ_NAME(self->obj)); 02288 } 02289 02290 static int Atrinik_Object_InternalCompare(Atrinik_Object *left, Atrinik_Object *right) 02291 { 02292 OBJEXISTCHECK_INT(left); 02293 OBJEXISTCHECK_INT(right); 02294 return (left->obj < right->obj ? -1 : (left->obj == right->obj ? 0 : 1)); 02295 } 02296 02297 static PyObject *Atrinik_Object_RichCompare(Atrinik_Object *left, Atrinik_Object *right, int op) 02298 { 02299 int result; 02300 02301 if (!left || !right || !PyObject_TypeCheck((PyObject *) left, &Atrinik_ObjectType) || !PyObject_TypeCheck((PyObject *) right, &Atrinik_ObjectType)) 02302 { 02303 Py_INCREF(Py_NotImplemented); 02304 return Py_NotImplemented; 02305 } 02306 02307 result = Atrinik_Object_InternalCompare(left, right); 02308 02309 /* Handle removed objects. */ 02310 if (result == -1 && PyErr_Occurred()) 02311 { 02312 return NULL; 02313 } 02314 02315 return generic_rich_compare(op, result); 02316 } 02317 02323 static PyObject *object_iter(PyObject *seq) 02324 { 02325 Atrinik_Object *obj, *orig_obj = (Atrinik_Object *) seq; 02326 02327 OBJEXISTCHECK(orig_obj); 02328 02329 obj = PyObject_NEW(Atrinik_Object, &Atrinik_ObjectType); 02330 Py_INCREF(seq); 02331 obj->iter = (Atrinik_Object *) seq; 02332 obj->iter_type = OBJ_ITER_TYPE_ONE; 02333 02334 /* Select which iteration type we're doing. It's possible that 02335 * an object has both below and above set (it's not the first and 02336 * not the last object), in which case we will prefer below. */ 02337 if (orig_obj->obj->below) 02338 { 02339 obj->iter_type = OBJ_ITER_TYPE_BELOW; 02340 } 02341 else if (orig_obj->obj->above) 02342 { 02343 obj->iter_type = OBJ_ITER_TYPE_ABOVE; 02344 } 02345 02346 return (PyObject *) obj; 02347 } 02348 02353 static PyObject *object_iternext(Atrinik_Object *obj) 02354 { 02355 /* Do we need to iterate? */ 02356 if (obj->iter_type != OBJ_ITER_TYPE_NONE) 02357 { 02358 object *tmp; 02359 02360 OBJEXISTCHECK(obj->iter); 02361 tmp = obj->iter->obj; 02362 02363 /* Check which way we're iterating. */ 02364 if (obj->iter_type == OBJ_ITER_TYPE_BELOW) 02365 { 02366 obj->iter->obj = tmp->below; 02367 } 02368 else if (obj->iter_type == OBJ_ITER_TYPE_ABOVE) 02369 { 02370 obj->iter->obj = tmp->above; 02371 } 02372 else if (obj->iter_type == OBJ_ITER_TYPE_ONE) 02373 { 02374 obj->iter->obj = NULL; 02375 } 02376 02377 obj->iter->count = obj->iter->obj ? obj->iter->obj->count : 0; 02378 02379 /* Nothing left, so mark iter_type to show that. */ 02380 if (!obj->iter->obj) 02381 { 02382 obj->iter_type = OBJ_ITER_TYPE_NONE; 02383 } 02384 02385 return wrap_object(tmp); 02386 } 02387 02388 return NULL; 02389 } 02390 02392 static PyGetSetDef getseters[NUM_FIELDS + NUM_FLAGS + 1]; 02393 02395 PyTypeObject Atrinik_ObjectType = 02396 { 02397 #ifdef IS_PY3K 02398 PyVarObject_HEAD_INIT(NULL, 0) 02399 #else 02400 PyObject_HEAD_INIT(NULL) 02401 0, 02402 #endif 02403 "Atrinik.Object", 02404 sizeof(Atrinik_Object), 02405 0, 02406 (destructor) Atrinik_Object_dealloc, 02407 NULL, NULL, NULL, 02408 #ifdef IS_PY3K 02409 NULL, 02410 #else 02411 (cmpfunc) Atrinik_Object_InternalCompare, 02412 #endif 02413 0, 0, 0, 0, 0, 0, 02414 (reprfunc) Atrinik_Object_str, 02415 0, 0, 0, 02416 Py_TPFLAGS_DEFAULT, 02417 "Atrinik objects", 02418 NULL, NULL, 02419 (richcmpfunc) Atrinik_Object_RichCompare, 02420 0, 02421 (getiterfunc) object_iter, 02422 (iternextfunc) object_iternext, 02423 methods, 02424 0, 02425 getseters, 02426 0, 0, 0, 0, 0, 0, 0, 02427 Atrinik_Object_new, 02428 0, 0, 0, 0, 0, 0, 0, 0 02429 #ifndef IS_PY_LEGACY 02430 , 0 02431 #endif 02432 }; 02433 02438 int Atrinik_Object_init(PyObject *module) 02439 { 02440 size_t i, flagno; 02441 char buf[MAX_BUF]; 02442 02443 /* Field getseters */ 02444 for (i = 0; i < NUM_FIELDS; i++) 02445 { 02446 PyGetSetDef *def = &getseters[i]; 02447 02448 def->name = fields[i].name; 02449 def->get = (getter) Object_GetAttribute; 02450 def->set = (setter) Object_SetAttribute; 02451 def->doc = NULL; 02452 def->closure = (void *) &fields[i]; 02453 } 02454 02455 /* Flag getseters */ 02456 for (flagno = 0; flagno < NUM_FLAGS; flagno++) 02457 { 02458 if (hooks->object_flag_names[flagno]) 02459 { 02460 PyGetSetDef *def = &getseters[i++]; 02461 02462 strncpy(buf, "f_", sizeof(buf) - 1); 02463 strncat(buf, hooks->object_flag_names[flagno], sizeof(buf) - strlen(buf) - 1); 02464 def->name = hooks->strdup_local(buf); 02465 02466 def->get = (getter) Object_GetFlag; 02467 def->set = (setter) Object_SetFlag; 02468 def->doc = NULL; 02469 def->closure = (void *) flagno; 02470 } 02471 } 02472 02473 getseters[i].name = NULL; 02474 02475 Atrinik_ObjectType.tp_new = PyType_GenericNew; 02476 02477 if (PyType_Ready(&Atrinik_ObjectType) < 0) 02478 { 02479 return 0; 02480 } 02481 02482 Py_INCREF(&Atrinik_ObjectType); 02483 PyModule_AddObject(module, "Object", (PyObject *) &Atrinik_ObjectType); 02484 02485 return 1; 02486 } 02487 02492 PyObject *wrap_object(object *what) 02493 { 02494 Atrinik_Object *wrapper; 02495 02496 /* Return None if no object was to be wrapped. */ 02497 if (!what || OBJECT_FREE(what)) 02498 { 02499 Py_INCREF(Py_None); 02500 return Py_None; 02501 } 02502 02503 wrapper = PyObject_NEW(Atrinik_Object, &Atrinik_ObjectType); 02504 02505 if (wrapper) 02506 { 02507 wrapper->obj = HEAD(what); 02508 wrapper->count = wrapper->obj->count; 02509 } 02510 02511 return (PyObject *) wrapper; 02512 }
1.7.4