Atrinik Server 2.5
plugins/plugin_python/atrinik_object.c
Go to the documentation of this file.
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 }