Atrinik Server 2.5
types/player.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 <global.h>
00031 
00032 static archetype *get_player_archetype(archetype *at);
00033 static int save_life(object *op);
00034 static void remove_unpaid_objects(object *op, object *env);
00035 
00040 player *find_player(const char *plname)
00041 {
00042     player *pl;
00043 
00044     for (pl = first_player; pl; pl = pl->next)
00045     {
00046         if (pl->ob && pl->state == ST_PLAYING && !strncasecmp(pl->ob->name, plname, MAX_NAME))
00047         {
00048             return pl;
00049         }
00050     }
00051 
00052     return NULL;
00053 }
00054 
00061 void display_motd(object *op)
00062 {
00063     char buf[MAX_BUF];
00064     FILE *fp;
00065 
00066     snprintf(buf, sizeof(buf), "%s/motd_custom", settings.localdir);
00067 
00068     if ((fp = fopen(buf, "r")) == NULL)
00069     {
00070         snprintf(buf, sizeof(buf), "%s/motd", settings.localdir);
00071 
00072         if ((fp = fopen(buf, "r")) == NULL)
00073         {
00074             return;
00075         }
00076     }
00077 
00078     while (fgets(buf, MAX_BUF, fp) != NULL)
00079     {
00080         char *cp;
00081 
00082         if (buf[0] == '#' || buf[0] == '\n')
00083         {
00084             continue;
00085         }
00086 
00087         cp = strchr(buf, '\n');
00088 
00089         if (cp != NULL)
00090         {
00091             *cp = '\0';
00092         }
00093 
00094         new_draw_info(0, COLOR_WHITE, op, buf);
00095     }
00096 
00097     fclose(fp);
00098     new_draw_info(0, COLOR_WHITE, op, " ");
00099 }
00100 
00106 int playername_ok(char *cp)
00107 {
00108     for (; *cp != '\0'; cp++)
00109     {
00110         if (!((*cp >= 'a' && *cp <= 'z') || (*cp >= 'A' && *cp <= 'Z')) && *cp != '-' && *cp != '_')
00111         {
00112             return 0;
00113         }
00114     }
00115 
00116     return 1;
00117 }
00118 
00124 static player *get_player(player *p)
00125 {
00126     object *op = arch_to_object(get_player_archetype(NULL));
00127     int i;
00128 
00129     if (!p)
00130     {
00131         p = (player *) get_poolchunk(pool_player);
00132         memset(p, 0, sizeof(player));
00133 
00134         if (p == NULL)
00135         {
00136             LOG(llevError, "get_player(): Out of memory\n");
00137         }
00138 
00139         if (!last_player)
00140         {
00141             first_player = last_player = p;
00142         }
00143         else
00144         {
00145             last_player->next = p;
00146             p->prev = last_player;
00147             last_player = p;
00148         }
00149     }
00150     else
00151     {
00152         /* Clears basically the entire player structure except
00153          * for next and socket. */
00154         memset((void *) ((char *) p + offsetof(player, maplevel)), 0, sizeof(player) - offsetof(player, maplevel));
00155     }
00156 
00157 #ifdef AUTOSAVE
00158     p->last_save_tick = 9999999;
00159 #endif
00160 
00161     /* Init. respawn position */
00162     strcpy(p->savebed_map, first_map_path);
00163 
00164     p->firemode_type = p->firemode_tag1 = p->firemode_tag2 = -1;
00165     /* This is where we set up initial CONTR(op) */
00166     op->custom_attrset = p;
00167     p->ob = op;
00168     op->speed_left = 0.5;
00169     op->speed = 1.0;
00170     op->run_away = 0;
00171 
00172     p->state = ST_ROLL_STAT;
00173 
00174     p->target_hp = -1;
00175     p->target_hp_p = -1;
00176     p->gen_sp_armour = 0;
00177     p->last_speed = -1;
00178     p->shoottype = range_none;
00179     p->last_weapon_sp = -1;
00180     p->update_los = 1;
00181 
00182     FREE_AND_COPY_HASH(op->race, op->arch->clone.race);
00183 
00184     /* Would be better if '0' was not a defined spell */
00185     for (i = 0; i < NROFREALSPELLS; i++)
00186     {
00187         p->known_spells[i] = -1;
00188     }
00189 
00190     for (i = 0; i < MAX_QUICKSLOT; i++)
00191     {
00192         p->spell_quickslots[i] = SP_NO_SPELL;
00193     }
00194 
00195     p->chosen_spell = -1;
00196 
00197     /* We need to clear these to -1 and not zero - otherwise, if a player
00198      * quits and starts a new character, we won't send new values to the
00199      * client, as things like exp start at zero. */
00200     for (i = 0; i < MAX_EXP_CAT; i++)
00201     {
00202         p->last_skill_exp[i] = -1;
00203         p->last_skill_level[i] = -1;
00204     }
00205 
00206     /* Quick skill reminder for select hand weapon */
00207     p->set_skill_weapon = NO_SKILL_READY;
00208     p->set_skill_archery = NO_SKILL_READY;
00209     p->last_skill_index = -1;
00210     p->last_stats.exp = -1;
00211 
00212     return p;
00213 }
00214 
00219 void free_player(player *pl)
00220 {
00221     if (pl->ob)
00222     {
00223         SET_FLAG(pl->ob, FLAG_NO_FIX_PLAYER);
00224 
00225         if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
00226         {
00227             remove_ob(pl->ob);
00228             check_walk_off(pl->ob, NULL, MOVE_APPLY_VANISHED);
00229         }
00230     }
00231 
00232     /* Free command permissions. */
00233     if (pl->cmd_permissions)
00234     {
00235         int i;
00236 
00237         for (i = 0; i < pl->num_cmd_permissions; i++)
00238         {
00239             if (pl->cmd_permissions[i])
00240             {
00241                 free(pl->cmd_permissions[i]);
00242             }
00243         }
00244 
00245         free(pl->cmd_permissions);
00246     }
00247 
00248     if (pl->faction_ids)
00249     {
00250         int i;
00251 
00252         for (i = 0; i < pl->num_faction_ids; i++)
00253         {
00254             FREE_ONLY_HASH(pl->faction_ids[i]);
00255         }
00256 
00257         free(pl->faction_ids);
00258     }
00259 
00260     if (pl->faction_reputation)
00261     {
00262         free(pl->faction_reputation);
00263     }
00264 
00265     player_path_clear(pl);
00266 
00267     /* Now remove from list of players. */
00268     if (pl->prev)
00269     {
00270         pl->prev->next = pl->next;
00271     }
00272     else
00273     {
00274         first_player = pl->next;
00275     }
00276 
00277     if (pl->next)
00278     {
00279         pl->next->prev = pl->prev;
00280     }
00281     else
00282     {
00283         last_player = pl->prev;
00284     }
00285 
00286     free_newsocket(&pl->socket);
00287 
00288     if (pl->ob)
00289     {
00290         destroy_object(pl->ob);
00291     }
00292 }
00293 
00301 int add_player(socket_struct *ns)
00302 {
00303     player *p = get_player(NULL);
00304     memcpy(&p->socket, ns, sizeof(socket_struct));
00305 
00306     /* now, we start the login procedure! */
00307     p->socket.status = Ns_Login;
00308     p->socket.below_clear = 0;
00309     p->socket.update_tile = 0;
00310     p->socket.look_position = 0;
00311     p->socket.inbuf.len = 0;
00312 
00313     get_name(p->ob);
00314 
00315     /* Avoid gc of the player */
00316     insert_ob_in_ob(p->ob, &void_container);
00317 
00318     return 0;
00319 }
00320 
00327 static archetype *get_player_archetype(archetype *at)
00328 {
00329     archetype *start = at;
00330 
00331     for (; ;)
00332     {
00333         if (at == NULL || at->next == NULL)
00334         {
00335             at = first_archetype;
00336         }
00337         else
00338         {
00339             at = at->next;
00340         }
00341 
00342         if (at->clone.type == PLAYER)
00343         {
00344             return at;
00345         }
00346 
00347         if (at == start)
00348         {
00349             LOG(llevError, "No player achetypes\n");
00350             exit(-1);
00351         }
00352     }
00353 }
00354 
00360 void give_initial_items(object *pl, treasurelist *items)
00361 {
00362     object *op, *next = NULL;
00363 
00364     if (pl->randomitems)
00365     {
00366         create_treasure(items, pl, GT_ONLY_GOOD | GT_NO_VALUE, 1, T_STYLE_UNSET, ART_CHANCE_UNSET, 0, NULL);
00367     }
00368 
00369     for (op = pl->inv; op; op = next)
00370     {
00371         next = op->below;
00372 
00373         /* Forces get applied by default */
00374         if (op->type == FORCE)
00375         {
00376             SET_FLAG(op, FLAG_APPLIED);
00377         }
00378 
00379         /* We never give weapons/armour if they cannot be used by this
00380          * player due to race restrictions */
00381         if (pl->type == PLAYER)
00382         {
00383             if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) && (op->type == ARMOUR || op->type == BOOTS || op->type == CLOAK || op->type == HELMET || op->type == SHIELD || op->type == GLOVES || op->type == BRACERS || op->type == GIRDLE)) || (!QUERY_FLAG(pl, FLAG_USE_WEAPON) && op->type == WEAPON))
00384             {
00385                 /* Inventory action */
00386                 remove_ob(op);
00387                 continue;
00388             }
00389         }
00390 
00391         /* Give starting characters identified, uncursed, and undamned
00392          * items. Just don't identify gold or silver, or it won't be
00393          * merged properly. */
00394         if (need_identify(op))
00395         {
00396             SET_FLAG(op, FLAG_IDENTIFIED);
00397             CLEAR_FLAG(op, FLAG_CURSED);
00398             CLEAR_FLAG(op, FLAG_DAMNED);
00399         }
00400 
00401         /* Apply initial armor */
00402         if (IS_ARMOR(op))
00403         {
00404             manual_apply(pl, op, 0);
00405         }
00406 
00407         if (op->type == ABILITY)
00408         {
00409             CONTR(pl)->known_spells[CONTR(pl)->nrofknownspells++] = op->stats.sp;
00410             remove_ob(op);
00411             continue;
00412         }
00413     }
00414 }
00415 
00419 void get_name(object *op)
00420 {
00421     CONTR(op)->write_buf[0] = '\0';
00422     CONTR(op)->state = ST_GET_NAME;
00423     send_query(&CONTR(op)->socket, 0, "What is your name?\n:");
00424 }
00425 
00429 void get_password(object *op)
00430 {
00431     CONTR(op)->write_buf[0] = '\0';
00432     CONTR(op)->state = ST_GET_PASSWORD;
00433     send_query(&CONTR(op)->socket, CS_QUERY_HIDEINPUT, "What is your password?\n:");
00434 }
00435 
00439 void confirm_password(object *op)
00440 {
00441     CONTR(op)->write_buf[0] = '\0';
00442     CONTR(op)->state = ST_CONFIRM_PASSWORD;
00443     send_query(&CONTR(op)->socket, CS_QUERY_HIDEINPUT, "Please type your password again.\n:");
00444 }
00445 
00452 object *find_arrow(object *op, const char *type)
00453 {
00454     object *tmp = NULL;
00455 
00456     for (op = op->inv; op; op = op->below)
00457     {
00458         if (!tmp && op->type == CONTAINER && op->race == type && QUERY_FLAG(op, FLAG_APPLIED))
00459         {
00460             tmp = find_arrow(op, type);
00461         }
00462         else if (op->type == ARROW && op->race == type)
00463         {
00464             return op;
00465         }
00466     }
00467 
00468     return tmp;
00469 }
00470 
00475 void fire(object *op, int dir)
00476 {
00477     object *weap = NULL;
00478     int spellcost = 0;
00479 
00480     /* A check for players, make sure things are groovy. This routine
00481      * will change the skill of the player as appropriate in order to
00482      * fire whatever is requested. In the case of spells (range_magic)
00483      * it handles whether cleric or mage spell is requested to be
00484      * cast. */
00485     if (op->type == PLAYER)
00486     {
00487         if (CONTR(op)->firemode_type == FIRE_MODE_NONE)
00488         {
00489             return;
00490         }
00491 
00492         if (CONTR(op)->firemode_type == FIRE_MODE_BOW)
00493         {
00494             CONTR(op)->shoottype = range_bow;
00495         }
00496         else if (CONTR(op)->firemode_type == FIRE_MODE_THROW)
00497         {
00498             object *tmp;
00499 
00500             /* Insert here test for more throwing skills */
00501             if (!change_skill(op, SK_THROWING))
00502             {
00503                 return;
00504             }
00505 
00506             /* Special case - we must redirect the fire cmd to throwing something */
00507             tmp = find_throw_tag(op, (tag_t) CONTR(op)->firemode_tag1);
00508 
00509             if (tmp)
00510             {
00511                 if (!check_skill_action_time(op, op->chosen_skill))
00512                 {
00513                     return;
00514                 }
00515 
00516                 do_throw(op, tmp, dir);
00517                 get_skill_time(op, op->chosen_skill->stats.sp);
00518                 CONTR(op)->action_timer = (float) (CONTR(op)->action_range - global_round_tag) / (1000000 / MAX_TIME) * 1000.0f;
00519 
00520                 if (CONTR(op)->last_action_timer > 0)
00521                 {
00522                     CONTR(op)->action_timer *= -1;
00523                 }
00524             }
00525 
00526             return;
00527         }
00528         else if (CONTR(op)->firemode_type == FIRE_MODE_SPELL)
00529         {
00530             CONTR(op)->shoottype = range_magic;
00531         }
00532         else if (CONTR(op)->firemode_type == FIRE_MODE_WAND)
00533         {
00534             /* We do a jump in fire wand if we haven one */
00535             CONTR(op)->shoottype = range_wand;
00536         }
00537         else if (CONTR(op)->firemode_type == FIRE_MODE_SKILL)
00538         {
00539             command_rskill(op, CONTR(op)->firemode_name);
00540             CONTR(op)->shoottype = range_skill;
00541         }
00542         else if (CONTR(op)->firemode_type == FIRE_MODE_SUMMON)
00543         {
00544             CONTR(op)->shoottype = range_scroll;
00545         }
00546         else
00547         {
00548             CONTR(op)->shoottype = range_none;
00549         }
00550 
00551         if (!check_skill_to_fire(op))
00552         {
00553             return;
00554         }
00555     }
00556 
00557     switch (CONTR(op)->shoottype)
00558     {
00559         case range_none:
00560             return;
00561 
00562         case range_bow:
00563             if (CONTR(op)->firemode_tag2 != -1 || CONTR(op)->socket.socket_version >= 1048)
00564             {
00565                 /* Still need to recover from range action? */
00566                 if (!check_skill_action_time(op, op->chosen_skill))
00567                 {
00568                     return;
00569                 }
00570 
00571                 bow_fire(op, dir);
00572                 get_skill_time(op, op->chosen_skill->stats.sp);
00573                 CONTR(op)->action_timer = (float) (CONTR(op)->action_range - global_round_tag) / (1000000 / MAX_TIME) * 1000.0f;
00574 
00575                 if (CONTR(op)->last_action_timer > 0)
00576                 {
00577                     CONTR(op)->action_timer *= -1;
00578                 }
00579             }
00580 
00581             return;
00582 
00583         /* Casting spells */
00584         case range_magic:
00585             if (!check_skill_action_time(op, op->chosen_skill))
00586             {
00587                 return;
00588             }
00589 
00590             spellcost = cast_spell(op, op, dir, CONTR(op)->chosen_spell, 0, CAST_NORMAL, NULL);
00591 
00592             if (spells[CONTR(op)->chosen_spell].type == SPELL_TYPE_PRIEST)
00593             {
00594                 op->stats.grace -= spellcost;
00595             }
00596             else
00597             {
00598                 op->stats.sp -= spellcost;
00599             }
00600 
00601             /* Only change the action timer if the spell required mana/grace cost (ie, was successful). */
00602             if (spellcost)
00603             {
00604                 CONTR(op)->action_casting = ROUND_TAG + spells[CONTR(op)->chosen_spell].time;
00605                 CONTR(op)->action_timer = (float) (CONTR(op)->action_casting - global_round_tag) / (1000000 / MAX_TIME) * 1000.0f;
00606 
00607                 if (CONTR(op)->last_action_timer > 0)
00608                 {
00609                     CONTR(op)->action_timer *= -1;
00610                 }
00611             }
00612 
00613             return;
00614 
00615         case range_wand:
00616             for (weap = op->inv; weap != NULL; weap = weap->below)
00617             {
00618                 if (weap->type == WAND && QUERY_FLAG(weap, FLAG_APPLIED))
00619                 {
00620                     break;
00621                 }
00622             }
00623 
00624             if (weap == NULL)
00625             {
00626                 CONTR(op)->shoottype = range_rod;
00627                 goto trick_jump;
00628             }
00629 
00630             if (!check_skill_action_time(op, op->chosen_skill))
00631             {
00632                 return;
00633             }
00634 
00635             if (weap->stats.food <= 0)
00636             {
00637                 play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "rod.ogg", 0, 0, 0, 0);
00638                 new_draw_info(0, COLOR_WHITE, op, "The wand says poof.");
00639                 return;
00640             }
00641 
00642             new_draw_info(0, COLOR_WHITE, op, "fire wand");
00643 
00644             if (cast_spell(op, weap, dir, weap->stats.sp, 0, CAST_WAND, NULL))
00645             {
00646                 /* You now know something about it */
00647                 SET_FLAG(op, FLAG_BEEN_APPLIED);
00648 
00649                 if (!(--weap->stats.food))
00650                 {
00651                     object *tmp;
00652 
00653                     if (weap->arch)
00654                     {
00655                         CLEAR_FLAG(weap, FLAG_ANIMATE);
00656                         weap->face = weap->arch->clone.face;
00657                         weap->speed = 0;
00658                         update_ob_speed(weap);
00659                     }
00660 
00661                     if ((tmp = is_player_inv(weap)))
00662                     {
00663                         esrv_update_item(UPD_ANIM, tmp, weap);
00664                     }
00665                 }
00666             }
00667 
00668             get_skill_time(op, op->chosen_skill->stats.sp);
00669             CONTR(op)->action_timer = (float) (CONTR(op)->action_range - global_round_tag) / (1000000 / MAX_TIME) * 1000.0f;
00670 
00671             if (CONTR(op)->last_action_timer > 0)
00672             {
00673                 CONTR(op)->action_timer *= -1;
00674             }
00675 
00676             return;
00677 
00678         case range_rod:
00679         case range_horn:
00680 trick_jump:
00681             for (weap = op->inv; weap != NULL; weap = weap->below)
00682             {
00683                 if (QUERY_FLAG(weap, FLAG_APPLIED) && weap->type == (CONTR(op)->shoottype == range_rod ? ROD : HORN))
00684                 {
00685                     break;
00686                 }
00687             }
00688 
00689             if (weap == NULL)
00690             {
00691                 if (CONTR(op)->shoottype == range_rod)
00692                 {
00693                     CONTR(op)->shoottype = range_horn;
00694                     goto trick_jump;
00695                 }
00696                 else
00697                 {
00698                     new_draw_info_format(0, COLOR_WHITE, op, "You have no tool readied.");
00699                     return;
00700                 }
00701             }
00702 
00703             if (!check_skill_action_time(op, op->chosen_skill))
00704             {
00705                 return;
00706             }
00707 
00708             /* If the device level is higher than player's magic skill,
00709              * don't allow using the device. */
00710             if (!CONTR(op)->exp_ptr[EXP_MAGICAL] || weap->level > CONTR(op)->exp_ptr[EXP_MAGICAL]->level + settings.magic_devices_level)
00711             {
00712                 new_draw_info_format(0, COLOR_WHITE, op, "The %s is impossible to handle for you.", weap->name);
00713                 return;
00714             }
00715 
00716             if (weap->stats.hp < spells[weap->stats.sp].sp)
00717             {
00718                 play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "rod.ogg", 0, 0, 0, 0);
00719 
00720                 if (CONTR(op)->shoottype == range_rod)
00721                 {
00722                     new_draw_info(0, COLOR_WHITE, op, "The rod whines for a while, but nothing happens.");
00723                 }
00724                 else
00725                 {
00726                     new_draw_info(0, COLOR_WHITE, op, "No matter how hard you try you can't get another note out.");
00727                 }
00728 
00729                 return;
00730             }
00731 
00732             if (cast_spell(op, weap, dir, weap->stats.sp, 0, CONTR(op)->shoottype == range_rod ? CAST_ROD : CAST_HORN, NULL))
00733             {
00734                 /* You now know something about it */
00735                 SET_FLAG(op, FLAG_BEEN_APPLIED);
00736                 drain_rod_charge(weap);
00737             }
00738 
00739             get_skill_time(op, op->chosen_skill->stats.sp);
00740             CONTR(op)->action_timer = (float) (CONTR(op)->action_range - global_round_tag) / (1000000 / MAX_TIME) * 1000.0f;
00741 
00742             if (CONTR(op)->last_action_timer > 0)
00743             {
00744                 CONTR(op)->action_timer *= -1;
00745             }
00746 
00747             return;
00748 
00749         /* Control summoned monsters from scrolls */
00750         case range_scroll:
00751             CONTR(op)->shoottype = range_none;
00752             CONTR(op)->chosen_spell = -1;
00753             return;
00754 
00755         case range_skill:
00756             if (!op->chosen_skill)
00757             {
00758                 if (op->type == PLAYER)
00759                     new_draw_info(0, COLOR_WHITE, op, "You have no applicable skill to use.");
00760                 return;
00761             }
00762 
00763             if (op->chosen_skill->sub_type != ST1_SKILL_USE)
00764             {
00765                 new_draw_info(0, COLOR_WHITE, op, "You can't use this skill in this way.");
00766             }
00767             else
00768             {
00769                 do_skill(op, dir, NULL);
00770             }
00771 
00772             return;
00773 
00774         default:
00775             new_draw_info(0, COLOR_WHITE, op, "Illegal shoot type.");
00776             return;
00777     }
00778 }
00779 
00785 int move_player(object *op, int dir)
00786 {
00787     int ret = 0;
00788 
00789     CONTR(op)->praying = 0;
00790 
00791     if (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY)
00792     {
00793         return 0;
00794     }
00795 
00796     if (dir)
00797     {
00798         op->facing = dir;
00799     }
00800 
00801     if (QUERY_FLAG(op, FLAG_CONFUSED) && dir)
00802     {
00803         dir = get_randomized_dir(dir);
00804     }
00805 
00806     op->anim_moving_dir = -1;
00807     op->anim_enemy_dir = -1;
00808     op->anim_last_facing = -1;
00809 
00810     /* firemode is set from client command fire xx xx xx */
00811     if (CONTR(op)->firemode_type != -1)
00812     {
00813         fire(op, dir);
00814 
00815         if (dir)
00816         {
00817             op->anim_enemy_dir = dir;
00818         }
00819         else
00820         {
00821             op->anim_enemy_dir = op->facing;
00822         }
00823 
00824         CONTR(op)->fire_on = 0;
00825     }
00826     else
00827     {
00828         ret = move_ob(op, dir, op);
00829 
00830         if (!ret)
00831         {
00832             op->anim_enemy_dir = dir;
00833         }
00834         else
00835         {
00836             op->anim_moving_dir = dir;
00837         }
00838     }
00839 
00840     if (QUERY_FLAG(op, FLAG_ANIMATE))
00841     {
00842         if (op->anim_enemy_dir == -1 && op->anim_moving_dir == -1)
00843         {
00844             op->anim_last_facing = dir;
00845         }
00846 
00847         animate_object(op, 0);
00848     }
00849 
00850     return ret;
00851 }
00852 
00863 int handle_newcs_player(player *pl)
00864 {
00865     if (!pl->ob || !OBJECT_ACTIVE(pl->ob))
00866     {
00867         return -1;
00868     }
00869 
00870     handle_client(&pl->socket, pl);
00871 
00872     if (!pl->ob || !OBJECT_ACTIVE(pl->ob) || pl->socket.status == Ns_Dead)
00873     {
00874         return -1;
00875     }
00876 
00877     /* Check speed. */
00878     if (pl->ob->speed_left < 0.0f)
00879     {
00880         return 0;
00881     }
00882 
00883     /* If we are here, we're never paralyzed anymore. */
00884     CLEAR_FLAG(pl->ob, FLAG_PARALYZED);
00885 
00886     if (pl->ob->direction && (CONTR(pl->ob)->run_on || CONTR(pl->ob)->fire_on))
00887     {
00888         /* All move commands take 1 tick, at least for now. */
00889         pl->ob->speed_left--;
00890         move_player(pl->ob, pl->ob->direction);
00891 
00892         if (pl->ob->speed_left > 0)
00893         {
00894             return 1;
00895         }
00896         else
00897         {
00898             return 0;
00899         }
00900     }
00901 
00902     return 0;
00903 }
00904 
00911 static int save_life(object *op)
00912 {
00913     object *tmp;
00914 
00915     if (!QUERY_FLAG(op, FLAG_LIFESAVE))
00916     {
00917         return 0;
00918     }
00919 
00920     for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
00921     {
00922         if (QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, FLAG_LIFESAVE))
00923         {
00924             play_sound_map(op->map, CMD_SOUND_EFFECT, "explosion.ogg", op->x, op->y, 0, 0);
00925             new_draw_info_format(0, COLOR_WHITE, op, "Your %s vibrates violently, then evaporates.", query_name(tmp, NULL));
00926 
00927             if (CONTR(op))
00928             {
00929                 esrv_del_item(CONTR(op), tmp->count, tmp->env);
00930             }
00931 
00932             remove_ob(tmp);
00933             CLEAR_FLAG(op, FLAG_LIFESAVE);
00934 
00935             if (op->stats.hp < 0)
00936             {
00937                 op->stats.hp = op->stats.maxhp;
00938             }
00939 
00940             if (op->stats.food < 0)
00941             {
00942                 op->stats.food = 999;
00943             }
00944 
00945             /* Bring him home. */
00946             enter_player_savebed(op);
00947             return 1;
00948         }
00949     }
00950 
00951     LOG(llevBug, "save_life(): LIFESAVE set without applied object.\n");
00952     CLEAR_FLAG(op, FLAG_LIFESAVE);
00953     /* Bring him home. */
00954     enter_player_savebed(op);
00955     return 0;
00956 }
00957 
00964 static void remove_unpaid_objects(object *op, object *env)
00965 {
00966     object *next;
00967 
00968     while (op)
00969     {
00970         /* Make sure we have a good value, in case
00971          * we remove object 'op' */
00972         next = op->below;
00973 
00974         if (QUERY_FLAG(op, FLAG_UNPAID))
00975         {
00976             remove_ob(op);
00977             op->x = env->x;
00978             op->y = env->y;
00979             insert_ob_in_map(op, env->map, NULL, 0);
00980         }
00981         else if (op->inv)
00982         {
00983             remove_unpaid_objects(op->inv, env);
00984         }
00985 
00986         op = next;
00987     }
00988 }
00989 
00995 static int get_regen_amount(uint16 regen, uint16 *remainder)
00996 {
00997     int ret = 0;
00998     float division;
00999 
01000     /* Check whether it's time to update the remainder variable (which
01001      * will distribute the remainder evenly over time). */
01002     if (pticks % 8 == 0)
01003     {
01004         *remainder += regen;
01005     }
01006 
01007     /* First check if we can distribute it evenly, if not, try to remove
01008      * leftovers, if any. */
01009     for (division = (float) 1000000 / MAX_TIME; ; division = 1.0f)
01010     {
01011         if (*remainder / 10.0f / division >= 1.0f)
01012         {
01013             int add = (int) *remainder / 10.0f / division;
01014 
01015             ret += add;
01016             *remainder -= add * 10;
01017             break;
01018         }
01019 
01020         if (division == 1.0f)
01021         {
01022             break;
01023         }
01024     }
01025 
01026     return ret;
01027 }
01028 
01035 void do_some_living(object *op)
01036 {
01037     int last_food = op->stats.food;
01038     int gen_hp, gen_sp, gen_grace;
01039     int rate_hp = 2000;
01040     int rate_sp = 1200;
01041     int rate_grace = 400;
01042     int add;
01043 
01044     if (CONTR(op)->state != ST_PLAYING)
01045     {
01046         return;
01047     }
01048 
01049     gen_hp = (CONTR(op)->gen_hp * (rate_hp / 20)) + (op->stats.maxhp / 4);
01050     gen_sp = (CONTR(op)->gen_sp * (rate_sp / 20)) + op->stats.maxsp;
01051     gen_grace = (CONTR(op)->gen_grace * (rate_grace / 20)) + op->stats.maxgrace;
01052 
01053     gen_sp = gen_sp * 10 / MAX(CONTR(op)->gen_sp_armour, 10);
01054 
01055     /* Update client's regen rates. */
01056     CONTR(op)->gen_client_hp = ((float) (1000000 / MAX_TIME) / ((float) rate_hp / (MAX(gen_hp, 20) + 10))) * 10.0f;
01057     CONTR(op)->gen_client_sp = ((float) (1000000 / MAX_TIME) / ((float) rate_sp / (MAX(gen_sp, 20) + 10))) * 10.0f;
01058     CONTR(op)->gen_client_grace = ((float) (1000000 / MAX_TIME) / ((float) rate_grace / (MAX(gen_grace, 20) + 10))) * 10.0f;
01059 
01060     /* Regenerate hit points. */
01061     if (op->stats.hp < op->stats.maxhp && op->stats.food)
01062     {
01063         add = get_regen_amount(CONTR(op)->gen_client_hp, &CONTR(op)->gen_hp_remainder);
01064 
01065         if (add)
01066         {
01067             op->stats.hp += add;
01068             CONTR(op)->stat_hp_regen += add;
01069 
01070             if (op->stats.hp > op->stats.maxhp)
01071             {
01072                 op->stats.hp = op->stats.maxhp;
01073             }
01074 
01075             /* DMs do not consume food. */
01076             if (!QUERY_FLAG(op, FLAG_WIZ))
01077             {
01078                 op->stats.food--;
01079 
01080                 if (CONTR(op)->digestion < 0)
01081                 {
01082                     op->stats.food += CONTR(op)->digestion;
01083                 }
01084                 else if (CONTR(op)->digestion > 0 && rndm(0, CONTR(op)->digestion))
01085                 {
01086                     op->stats.food = last_food;
01087                 }
01088             }
01089         }
01090     }
01091     else
01092     {
01093         CONTR(op)->gen_hp_remainder = 0;
01094     }
01095 
01096     /* Regenerate mana. */
01097     if (op->stats.sp < op->stats.maxsp && op->stats.food)
01098     {
01099         add = get_regen_amount(CONTR(op)->gen_client_sp, &CONTR(op)->gen_sp_remainder);
01100 
01101         if (add)
01102         {
01103             op->stats.sp += add;
01104             CONTR(op)->stat_sp_regen += add;
01105 
01106             if (op->stats.sp > op->stats.maxsp)
01107             {
01108                 op->stats.sp = op->stats.maxsp;
01109             }
01110 
01111             /* DMs do not consume food. */
01112             if (!QUERY_FLAG(op, FLAG_WIZ))
01113             {
01114                 op->stats.food--;
01115 
01116                 if (CONTR(op)->digestion < 0)
01117                 {
01118                     op->stats.food += CONTR(op)->digestion;
01119                 }
01120                 else if (CONTR(op)->digestion > 0 && rndm(0, CONTR(op)->digestion))
01121                 {
01122                     op->stats.food = last_food;
01123                 }
01124             }
01125         }
01126     }
01127     else
01128     {
01129         CONTR(op)->gen_sp_remainder = 0;
01130     }
01131 
01132     /* Stop and pray. */
01133     if (CONTR(op)->praying && !CONTR(op)->was_praying)
01134     {
01135         if (op->stats.grace < op->stats.maxgrace)
01136         {
01137             object *god = find_god(determine_god(op));
01138 
01139             if (god)
01140             {
01141                 if (CONTR(op)->combat_mode)
01142                 {
01143                     new_draw_info_format(0, COLOR_WHITE, op, "You stop combat and start praying to %s...", god->name);
01144                     CONTR(op)->combat_mode = 0;
01145                     send_target_command(CONTR(op));
01146                 }
01147                 else
01148                 {
01149                     new_draw_info_format(0, COLOR_WHITE, op, "You start praying to %s...", god->name);
01150                 }
01151 
01152                 CONTR(op)->was_praying = 1;
01153             }
01154             else
01155             {
01156                 new_draw_info(0, COLOR_WHITE, op, "You worship no deity to pray to!");
01157                 CONTR(op)->praying = 0;
01158             }
01159         }
01160         else
01161         {
01162             CONTR(op)->praying = 0;
01163             CONTR(op)->was_praying = 0;
01164         }
01165     }
01166     else if (!CONTR(op)->praying && CONTR(op)->was_praying)
01167     {
01168         new_draw_info(0, COLOR_WHITE, op, "You stop praying.");
01169         CONTR(op)->was_praying = 0;
01170     }
01171 
01172     /* Regenerate grace. */
01173     if (CONTR(op)->praying || op->stats.grace < op->stats.maxgrace / 3)
01174     {
01175         if (op->stats.grace < op->stats.maxgrace)
01176         {
01177             add = get_regen_amount(!CONTR(op)->praying ? CONTR(op)->gen_client_grace / 10 : CONTR(op)->gen_client_grace, &CONTR(op)->gen_grace_remainder);
01178 
01179             if (add)
01180             {
01181                 op->stats.grace += add;
01182                 CONTR(op)->stat_grace_regen += add;
01183 
01184                 if (op->stats.grace > op->stats.maxgrace)
01185                 {
01186                     op->stats.grace = op->stats.maxgrace;
01187                 }
01188             }
01189         }
01190         else
01191         {
01192             CONTR(op)->gen_grace_remainder = 0;
01193         }
01194 
01195         if (op->stats.grace >= op->stats.maxgrace)
01196         {
01197             op->stats.grace = op->stats.maxgrace;
01198             new_draw_info(0, COLOR_WHITE, op, "You are full of grace and stop praying.");
01199             CONTR(op)->was_praying = 0;
01200         }
01201     }
01202 
01203     /* Digestion */
01204     if (--op->last_eat < 0)
01205     {
01206         int bonus = MAX(CONTR(op)->digestion, 0);
01207         int penalty = MAX(-CONTR(op)->digestion, 0);
01208 
01209         if (CONTR(op)->gen_hp > 0)
01210         {
01211             op->last_eat = 25 * (1 + bonus) / (CONTR(op)->gen_hp + penalty + 1);
01212         }
01213         else
01214         {
01215             op->last_eat = 25 * (1 + bonus) / (penalty + 1);
01216         }
01217 
01218         /* DMs do not consume food. */
01219         if (!QUERY_FLAG(op, FLAG_WIZ))
01220         {
01221             op->stats.food--;
01222         }
01223     }
01224 
01225     if (op->stats.food < 0 && op->stats.hp >= 0)
01226     {
01227         object *tmp, *flesh = NULL;
01228 
01229         for (tmp = op->inv; tmp; tmp = tmp->below)
01230         {
01231             if (!QUERY_FLAG(tmp, FLAG_UNPAID))
01232             {
01233                 if (tmp->type == FOOD || tmp->type == DRINK || tmp->type == POISON)
01234                 {
01235                     new_draw_info(0, COLOR_WHITE, op, "You blindly grab for a bite of food.");
01236                     manual_apply(op, tmp, 0);
01237 
01238                     if (op->stats.food >= 0 || op->stats.hp < 0)
01239                     {
01240                         break;
01241                     }
01242                 }
01243                 else if (tmp->type == FLESH)
01244                 {
01245                     flesh = tmp;
01246                 }
01247             }
01248         }
01249 
01250         /* If player is still starving, it means they don't have any food, so
01251          * eat flesh instead. */
01252         if (op->stats.food < 0 && op->stats.hp >= 0 && flesh)
01253         {
01254             new_draw_info(0, COLOR_WHITE, op, "You blindly grab for a bite of food.");
01255             manual_apply(op, flesh, 0);
01256         }
01257     }
01258 
01259     while (op->stats.food < 0 && op->stats.hp > 0)
01260     {
01261         op->stats.food++;
01262         op->stats.hp--;
01263     }
01264 
01265     if ((op->stats.hp <= 0 || op->stats.food < 0) && !QUERY_FLAG(op, FLAG_WIZ))
01266     {
01267         new_draw_info_format(NDI_ALL, COLOR_WHITE, NULL, "%s starved to death.", op->name);
01268         strcpy(CONTR(op)->killer, "starvation");
01269         kill_player(op);
01270     }
01271 }
01272 
01278 void kill_player(object *op)
01279 {
01280     char buf[HUGE_BUF];
01281     int i;
01282     object *tmp;
01283     int z;
01284     int num_stats_lose;
01285     int lost_a_stat;
01286     int lose_this_stat;
01287     int this_stat;
01288 
01289     if (pvp_area(NULL, op))
01290     {
01291         new_draw_info(0, COLOR_NAVY, op, "You have been defeated in combat!\nLocal medics have saved your life...");
01292 
01293         /* Restore player */
01294         cast_heal(op, MAXLEVEL, op, SP_CURE_POISON);
01295         /* Remove any disease */
01296         cure_disease(op, NULL);
01297         op->stats.hp = op->stats.maxhp;
01298         op->stats.sp = op->stats.maxsp;
01299         op->stats.grace = op->stats.maxgrace;
01300 
01301         if (op->stats.food <= 0)
01302         {
01303             op->stats.food = 999;
01304         }
01305 
01306         /* Create a bodypart-trophy to make the winner happy */
01307         tmp = arch_to_object(find_archetype("finger"));
01308 
01309         if (tmp)
01310         {
01311             char race[MAX_BUF];
01312 
01313             snprintf(buf, sizeof(buf), "%s's finger", op->name);
01314             FREE_AND_COPY_HASH(tmp->name, buf);
01315             snprintf(buf, sizeof(buf), "This finger has been cut off %s the %s, when %s was defeated at level %d by %s.", op->name, player_get_race_class(op, race, sizeof(race)), gender_subjective[object_get_gender(op)], op->level, CONTR(op)->killer[0] == '\0' ? "something nasty" : CONTR(op)->killer);
01316             FREE_AND_COPY_HASH(tmp->msg, buf);
01317             tmp->value = 0;
01318             tmp->material = 0;
01319             tmp->type = 0;
01320             tmp->x = op->x, tmp->y = op->y;
01321             insert_ob_in_map(tmp, op->map, op, 0);
01322         }
01323 
01324         CONTR(op)->killer[0] = '\0';
01325 
01326         /* Teleport defeated player to new destination */
01327         transfer_ob(op, MAP_ENTER_X(op->map), MAP_ENTER_Y(op->map), 0, NULL, NULL);
01328         return;
01329     }
01330 
01331     if (save_life(op))
01332     {
01333         return;
01334     }
01335 
01336     /* Trigger the DEATH event */
01337     if (trigger_event(EVENT_DEATH, NULL, op, NULL, NULL, 0, 0, 0, SCRIPT_FIX_ALL))
01338     {
01339         return;
01340     }
01341 
01342     CONTR(op)->stat_deaths++;
01343 
01344     /* Trigger the global GDEATH event */
01345     trigger_global_event(GEVENT_PLAYER_DEATH, NULL, op);
01346 
01347     play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "playerdead.ogg", 0, 0, 0, 0);
01348 
01349     /* Basically two ways to go - remove a stat permanently, or just
01350      * make it depletion.  This bunch of code deals with that aspect
01351      * of death. */
01352     if (settings.balanced_stat_loss)
01353     {
01354         /* If stat loss is permanent, lose one stat only. */
01355         /* Lower level chars don't lose as many stats because they suffer more
01356            if they do. */
01357         if (settings.stat_loss_on_death)
01358         {
01359             num_stats_lose = 1;
01360         }
01361         else
01362         {
01363             num_stats_lose = 1 + op->level / BALSL_NUMBER_LOSSES_RATIO;
01364         }
01365     }
01366     else
01367     {
01368         num_stats_lose = 1;
01369     }
01370 
01371     lost_a_stat = 0;
01372 
01373     /* Only decrease stats if you are level 3 or higher. */
01374     for (z = 0; z < num_stats_lose; z++)
01375     {
01376         if (settings.stat_loss_on_death && op->level > 3)
01377         {
01378             /* Pick a random stat and take a point off it. Tell the
01379              * player what he lost. */
01380             i = rndm(1, NUM_STATS) - 1;
01381             change_attr_value(&(op->stats), i, -1);
01382             check_stat_bounds(&(op->stats));
01383             change_attr_value(&(CONTR(op)->orig_stats), i, -1);
01384             check_stat_bounds(&(CONTR(op)->orig_stats));
01385             new_draw_info(0, COLOR_WHITE, op, lose_msg[i]);
01386             lost_a_stat = 1;
01387         }
01388         else if (op->level > 3)
01389         {
01390             /* Deplete a stat */
01391             archetype *deparch = find_archetype("depletion");
01392             object *dep;
01393 
01394             i = rndm(1, NUM_STATS) - 1;
01395             dep = present_arch_in_ob(deparch, op);
01396 
01397             if (!dep)
01398             {
01399                 dep = arch_to_object(deparch);
01400                 insert_ob_in_ob(dep, op);
01401             }
01402 
01403             lose_this_stat = 1;
01404 
01405             if (settings.balanced_stat_loss)
01406             {
01407                 /* Get the stat that we're about to deplete. */
01408                 this_stat = get_attr_value(&(dep->stats), i);
01409 
01410                 if (this_stat < 0)
01411                 {
01412                     int loss_chance = 1 + op->level / BALSL_LOSS_CHANCE_RATIO;
01413                     int keep_chance = this_stat * this_stat;
01414 
01415                     /* Yes, I am paranoid. Sue me. */
01416                     if (keep_chance < 1)
01417                     {
01418                         keep_chance = 1;
01419                     }
01420 
01421                     /* There is a maximum depletion total per level. */
01422                     if (this_stat < -1 - op->level / BALSL_MAX_LOSS_RATIO)
01423                     {
01424                         lose_this_stat = 0;
01425                     }
01426                     else
01427                     {
01428                         /* Take loss chance vs keep chance to see if we retain the stat. */
01429                         if (rndm(0, loss_chance + keep_chance - 1) < keep_chance)
01430                         {
01431                             lose_this_stat = 0;
01432                         }
01433                     }
01434                 }
01435             }
01436 
01437             if (lose_this_stat)
01438             {
01439                 this_stat = get_attr_value(&(dep->stats), i);
01440 
01441                 /* We could try to do something clever like find another
01442                  * stat to reduce if this fails.  But chances are, if
01443                  * stats have been depleted to -50, all are pretty low
01444                  * and should be roughly the same, so it shouldn't make a
01445                  * difference. */
01446                 if (this_stat >= -50)
01447                 {
01448                     change_attr_value(&(dep->stats), i, -1);
01449                     SET_FLAG(dep, FLAG_APPLIED);
01450                     new_draw_info(0, COLOR_WHITE, op, lose_msg[i]);
01451                     fix_player(op);
01452                     lost_a_stat = 1;
01453                 }
01454             }
01455         }
01456     }
01457 
01458     /* If no stat lost, tell the player. */
01459     if (!lost_a_stat)
01460     {
01461         const char *god = determine_god(op);
01462 
01463         if (god && god != shstr_cons.none)
01464         {
01465             new_draw_info_format(0, COLOR_WHITE, op, "For a brief moment you feel the holy presence of %s protecting you.", god);
01466         }
01467         else
01468         {
01469             new_draw_info(0, COLOR_WHITE, op, "For a brief moment you feel a holy presence protecting you.");
01470         }
01471     }
01472 
01473     /* Put a gravestone up where the character 'almost' died. */
01474     tmp = arch_to_object(find_archetype("gravestone"));
01475     snprintf(buf, sizeof(buf), "%s's gravestone", op->name);
01476     FREE_AND_COPY_HASH(tmp->name, buf);
01477     FREE_AND_COPY_HASH(tmp->msg, gravestone_text(op));
01478     tmp->x = op->x;
01479     tmp->y = op->y;
01480     insert_ob_in_map(tmp, op->map, NULL, 0);
01481 
01482     /* Subtract the experience points, if we died because of food give us
01483      * food, and reset HP... */
01484 
01485     /* Remove any poisoning the character may be suffering. */
01486     cast_heal(op, MAXLEVEL, op, SP_CURE_POISON);
01487     /* Remove any disease */
01488     cure_disease(op, NULL);
01489 
01490     /* Apply death experience penalty. */
01491     apply_death_exp_penalty(op);
01492 
01493     if (op->stats.food <= 0)
01494     {
01495         op->stats.food = 999;
01496     }
01497 
01498     op->stats.hp = op->stats.maxhp;
01499     op->stats.sp = op->stats.maxsp;
01500     op->stats.grace = op->stats.maxgrace;
01501 
01502     hiscore_check(op, 1);
01503 
01504     /* Otherwise the highscore can get entries like 'xxx was killed by pudding
01505      * on map Wilderness' even if they were killed in a dungeon. */
01506     CONTR(op)->killer[0] = '\0';
01507 
01508     /* Check to see if the player is in a shop. Ii so, then check to see
01509      * if the player has any unpaid items. If so, remove them and put
01510      * them back in the map. */
01511     tmp = get_map_ob(op->map, op->x, op->y);
01512 
01513     if (tmp && tmp->type == SHOP_FLOOR)
01514     {
01515         remove_unpaid_objects(op->inv, op);
01516     }
01517 
01518     /* Move player to his current respawn position (last savebed). */
01519     enter_player_savebed(op);
01520 
01521     /* Show a nasty message */
01522     new_draw_info(0, COLOR_WHITE, op, "YOU HAVE DIED.");
01523     save_player(op, 1);
01524 }
01525 
01533 void cast_dust(object *op, object *throw_ob, int dir)
01534 {
01535     archetype *arch = NULL;
01536 
01537     if (!(spells[throw_ob->stats.sp].flags & SPELL_DESC_DIRECTION))
01538     {
01539         LOG(llevBug, "Warning, dust %s is not AE spell!!\n", query_name(throw_ob, NULL));
01540         return;
01541     }
01542 
01543     if (spells[throw_ob->stats.sp].archname)
01544     {
01545         arch = find_archetype(spells[throw_ob->stats.sp].archname);
01546     }
01547 
01548     /* Casting POTION 'dusts' is really use_magic_item skill */
01549     if (op->type == PLAYER && throw_ob->type == POTION && !change_skill(op, SK_USE_MAGIC_ITEM))
01550     {
01551         return;
01552     }
01553 
01554     if (throw_ob->type == POTION && arch != NULL)
01555     {
01556         cast_cone(op, throw_ob, dir, 10, throw_ob->stats.sp, arch);
01557     }
01558     /* dust_effect */
01559     else if ((arch = find_archetype("dust_effect")) != NULL)
01560     {
01561         cast_cone(op, throw_ob, dir, 1, 0, arch);
01562     }
01563     /* Problem occurred! */
01564     else
01565     {
01566         LOG(llevBug, "cast_dust() can't find an archetype to use!\n");
01567     }
01568 
01569     if (op->type == PLAYER && arch)
01570     {
01571         new_draw_info_format(0, COLOR_WHITE, op, "You cast %s.", query_name(throw_ob, NULL));
01572     }
01573 
01574     if (!QUERY_FLAG(throw_ob, FLAG_REMOVED))
01575     {
01576         destruct_ob(throw_ob);
01577     }
01578 }
01579 
01590 int pvp_area(object *attacker, object *victim)
01591 {
01592     /* No attacking of party members. */
01593     if (attacker && victim && attacker->type == PLAYER && victim->type == PLAYER && CONTR(attacker)->party != NULL && CONTR(victim)->party != NULL && CONTR(attacker)->party == CONTR(victim)->party)
01594     {
01595         return 0;
01596     }
01597 
01598     if (attacker && victim && attacker == victim)
01599     {
01600         return 0;
01601     }
01602 
01603     if (attacker && attacker->map)
01604     {
01605         if (!(attacker->map->map_flags & MAP_FLAG_PVP) || GET_MAP_FLAGS(attacker->map, attacker->x, attacker->y) & P_NO_PVP || GET_MAP_SPACE_PTR(attacker->map, attacker->x, attacker->y)->extra_flags & MSP_EXTRA_NO_PVP)
01606         {
01607             return 0;
01608         }
01609     }
01610 
01611     if (victim && victim->map)
01612     {
01613         if (!(victim->map->map_flags & MAP_FLAG_PVP) || GET_MAP_FLAGS(victim->map, victim->x, victim->y) & P_NO_PVP || GET_MAP_SPACE_PTR(victim->map, victim->x, victim->y)->extra_flags & MSP_EXTRA_NO_PVP)
01614         {
01615             return 0;
01616         }
01617     }
01618 
01619     return 1;
01620 }
01621 
01626 int player_exists(char *player_name)
01627 {
01628     FILE *fp;
01629     char filename[HUGE_BUF];
01630 
01631     snprintf(filename, sizeof(filename), "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, player_name, player_name);
01632     fp = fopen(filename, "r");
01633 
01634     if (fp)
01635     {
01636         fclose(fp);
01637         return 1;
01638     }
01639 
01640     return 0;
01641 }
01642 
01648 object *find_skill(object *op, int skillnr)
01649 {
01650     object *tmp;
01651 
01652     for (tmp = op->inv; tmp; tmp = tmp->below)
01653     {
01654         if (tmp->type == SKILL && tmp->stats.sp == skillnr)
01655         {
01656             return tmp;
01657         }
01658     }
01659 
01660     return NULL;
01661 }
01662 
01668 int player_can_carry(object *pl, uint32 weight)
01669 {
01670     uint32 effective_weight_limit;
01671 
01672     if (pl->stats.Str <= MAX_STAT)
01673     {
01674         effective_weight_limit = weight_limit[pl->stats.Str];
01675     }
01676     else
01677     {
01678         effective_weight_limit = weight_limit[MAX_STAT];
01679     }
01680 
01681     return (pl->carrying + weight) < effective_weight_limit;
01682 }
01683 
01690 char *player_get_race_class(object *op, char *buf, size_t size)
01691 {
01692     strncpy(buf, op->race, size - 1);
01693 
01694     if (CONTR(op)->class_ob)
01695     {
01696         shstr *name_female;
01697 
01698         strncat(buf, " ", size - strlen(buf) - 1);
01699 
01700         if (object_get_gender(op) == GENDER_FEMALE && (name_female = object_get_value(CONTR(op)->class_ob, "name_female")))
01701         {
01702             strncat(buf, name_female, size - strlen(buf) - 1);
01703         }
01704         else
01705         {
01706             strncat(buf, CONTR(op)->class_ob->name, size - strlen(buf) - 1);
01707         }
01708     }
01709 
01710     return buf;
01711 }
01712 
01719 void player_path_add(player *pl, mapstruct *map, sint16 x, sint16 y)
01720 {
01721     player_path *path = malloc(sizeof(player_path));
01722 
01723     /* Initialize the values. */
01724     path->map = map;
01725     path->x = x;
01726     path->y = y;
01727     path->next = NULL;
01728     path->fails = 0;
01729 
01730     if (!pl->move_path)
01731     {
01732         pl->move_path = pl->move_path_end = path;
01733     }
01734     else
01735     {
01736         pl->move_path_end->next = path;
01737         pl->move_path_end = path;
01738     }
01739 }
01740 
01744 void player_path_clear(player *pl)
01745 {
01746     player_path *path, *next;
01747 
01748     if (!pl->move_path)
01749     {
01750         return;
01751     }
01752 
01753     for (path = pl->move_path; path; path = next)
01754     {
01755         next = path->next;
01756         free(path);
01757     }
01758 
01759     pl->move_path = NULL;
01760     pl->move_path_end = NULL;
01761 }
01762 
01766 void player_path_handle(player *pl)
01767 {
01768     while (pl->ob->speed_left >= 0.0f && pl->move_path)
01769     {
01770         player_path *tmp = pl->move_path;
01771         rv_vector rv;
01772 
01773         /* Make sure the map exists and is loaded, then get the range vector. */
01774         if (!tmp->map || tmp->map->in_memory != MAP_IN_MEMORY || !get_rangevector_from_mapcoords(pl->ob->map, pl->ob->x, pl->ob->y, tmp->map, tmp->x, tmp->y, &rv, 0))
01775         {
01776             /* Something went wrong (map not loaded or we got teleported
01777              * somewhere), clear all queued paths. */
01778             player_path_clear(pl);
01779             return;
01780         }
01781         else
01782         {
01783             int success = 0, dir = rv.direction;
01784 
01785             /* Can the player move there directly? */
01786             if (move_player(pl->ob, dir))
01787             {
01788                 success = 1;
01789             }
01790             else
01791             {
01792                 int diff;
01793 
01794                 /* Try to move around corners otherwise. */
01795                 for (diff = 1; diff <= 2; diff++)
01796                 {
01797                     /* Try left or right first? */
01798                     int m = 1 - (RANDOM() & 2);
01799 
01800                     if (move_player(pl->ob, absdir(dir + diff * m)) || move_player(pl->ob, absdir(dir - diff * m)))
01801                     {
01802                         success = 1;
01803                         break;
01804                     }
01805                 }
01806             }
01807 
01808             /* See if we succeeded in moving where we wanted. */
01809             if (pl->ob->map == tmp->map && pl->ob->x == tmp->x && pl->ob->y == tmp->y)
01810             {
01811                 pl->move_path = tmp->next;
01812                 free(tmp);
01813             }
01814             /* Clear all paths if we above check failed: this can happen
01815              * if we got teleported somewhere else by a teleporter or a
01816              * shop mat, in which case the player most likely doesn't want
01817              * to move to the original destination. Also see if we failed
01818              * to move to destination too many times already. */
01819             else if ((rv.distance <= 1 && success) || tmp->fails > PLAYER_PATH_MAX_FAILS)
01820             {
01821                 player_path_clear(pl);
01822                 return;
01823             }
01824             /* Not any of the above; we failed to move where we wanted. */
01825             else
01826             {
01827                 tmp->fails++;
01828             }
01829 
01830             pl->ob->speed_left--;
01831         }
01832     }
01833 }
01834 
01840 sint64 player_faction_reputation(player *pl, shstr *faction)
01841 {
01842     int i;
01843 
01844     for (i = 0; i < pl->num_faction_ids; i++)
01845     {
01846         if (pl->faction_ids[i] == faction)
01847         {
01848             return pl->faction_reputation[i];
01849         }
01850     }
01851 
01852     return 0;
01853 }
01854 
01861 void player_faction_reputation_update(player *pl, shstr *faction, sint64 add)
01862 {
01863     int i;
01864 
01865     for (i = 0; i < pl->num_faction_ids; i++)
01866     {
01867         if (pl->faction_ids[i] == faction)
01868         {
01869             pl->faction_reputation[i] += add;
01870             return;
01871         }
01872     }
01873 
01874     pl->faction_ids = realloc(pl->faction_ids, sizeof(*pl->faction_ids) * (pl->num_faction_ids + 1));
01875     pl->faction_reputation = realloc(pl->faction_reputation, sizeof(*pl->faction_reputation) * (pl->num_faction_ids + 1));
01876     pl->faction_ids[pl->num_faction_ids] = add_string(faction);
01877     pl->faction_reputation[pl->num_faction_ids] = add;
01878     pl->num_faction_ids++;
01879 }