--- deliantra/server/server/player.C 2007/05/12 18:40:40 1.128 +++ deliantra/server/server/player.C 2007/08/15 04:59:46 1.159 @@ -1,25 +1,24 @@ /* - * CrossFire, A Multiplayer game - * - * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team - * Copyright (C) 2002 Mark Wedel & Crossfire Development Team - * Copyright (C) 1992 Frank Tore Johansen - * - * This program is free software; you can redistribute it and/or modify + * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. + * + * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team + * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team + * Copyright (©) 1992,2007 Frank Tore Johansen + * + * Crossfire TRT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * The author can be reached via e-mail to + * along with this program. If not, see . + * + * The authors can be reached via e-mail to */ #include @@ -159,19 +158,6 @@ } void -player::enter_map () -{ - object *tmp = object::create (); - - EXIT_PATH (tmp) = maplevel; - EXIT_X (tmp) = ob->x; - EXIT_Y (tmp) = ob->y; - ob->enter_exit (tmp); - - tmp->destroy (); -} - -void player::activate () { if (active) @@ -183,7 +169,6 @@ ob->activate_recursive (); CLEAR_FLAG (ob, FLAG_FRIENDLY); add_friendly_object (ob); - enter_map (); } void @@ -223,34 +208,31 @@ ns->update_look = 0; ns->look_position = 0; - clear_los (ob); + clear_los (this); ns->reset_stats (); /* make sure he's a player -- needed because of class change. */ ob->type = PLAYER; // we are paranoid - ob->race = ob->arch->clone.race; + ob->race = ob->arch->race; ob->carrying = sum_weight (ob); link_player_skills (ob); CLEAR_FLAG (ob, FLAG_NO_FIX_PLAYER); - assign (title, ob->arch->clone.name); + assign (title, ob->arch->object::name); /* if it's a dragon player, set the correct title here */ if (is_dragon_pl (ob)) { object *tmp, *abil = 0, *skin = 0; - shstr_cmp dragon_ability_force ("dragon_ability_force"); - shstr_cmp dragon_skin_force ("dragon_skin_force"); - for (tmp = ob->inv; tmp; tmp = tmp->below) if (tmp->type == FORCE) - if (tmp->arch->name == dragon_ability_force) + if (tmp->arch->archname == shstr_dragon_ability_force) abil = tmp; - else if (tmp->arch->name == dragon_skin_force) + else if (tmp->arch->archname == shstr_dragon_skin_force) skin = tmp; set_dragon_name (ob, abil, skin); @@ -260,25 +242,34 @@ esrv_new_player (this, ob->weight + ob->carrying); + ob->flag [FLAG_READY_WEAPON] = false; + ob->flag [FLAG_READY_SKILL] = false; + ob->flag [FLAG_READY_BOW] = false; + for (object *op = ob->inv; op; op = op->below) if (op->flag [FLAG_APPLIED]) switch (op->type) { + case SKILL: + ob->flag [FLAG_APPLIED] = false; + break; + case WAND: case ROD: case HORN: case BOW: - case SKILL: - case SKILL_TOOL: + ranged_ob = op; + break; + case WEAPON: - apply_special (ob, op, AP_UNAPPLY); - apply_special (ob, op, AP_APPLY); + combat_ob = op; break; } + ob->change_weapon (combat_ob ? combat_ob : ranged_ob); ob->update_stats (); - ns->floorbox_update (); + ns->floorbox_update (); esrv_send_inventory (ob, ob); esrv_add_spells (this, 0); @@ -295,6 +286,12 @@ void player::disconnect () { + if (ob) + { + ob->close_container (); //TODO: client-specific + ob->drop_unpaid_items (); + } + if (ns) { if (active) @@ -307,8 +304,7 @@ ns = 0; } - if (ob) - ob->close_container (); //TODO: client-specific + observe = ob; deactivate (); } @@ -318,12 +314,20 @@ void player::set_object (object *op) { - ob = op; + ob = observe = op; ob->contr = this; /* this aren't yet in archetype */ - ob->speed_left = 0.5; - ob->speed = 1.0; - ob->direction = 5; /* So player faces south */ + ob->speed = 1.0f; + ob->speed_left = 0.5f; + + ob->direction = 5; /* So player faces south */ +} + +void +player::set_observe (object *op) +{ + observe = op ? op : ob; + do_los = 1; } player::player () @@ -344,6 +348,9 @@ usekeys = containers; peaceful = 1; /* default peaceful */ do_los = 1; + + weapon_sp = 1.0f; + weapon_sp_left = 0.5f; } void @@ -358,6 +365,8 @@ ob->destroy_inv (false); ob->destroy (); } + + ob = observe = 0; } player::~player () @@ -394,23 +403,17 @@ archetype * get_player_archetype (archetype *at) { - archetype *start = at; + archvec::iterator i = at ? archetypes.find (at) : archetypes.begin (); for (;;) { - if (at == NULL || at->next == NULL) - at = first_archetype; - else - at = at->next; - - if (at->clone.type == PLAYER) - return at; + if (++i == archetypes.end ()) + i = archetypes.begin (); + else if (*i == at) + cleanup ("not a single player archetype found"); - if (at == start) - { - LOG (llevError, "No Player archetypes\n"); - exit (-1); - } + if ((*i)->type == PLAYER) + return *i; } } @@ -910,7 +913,7 @@ object *tmp; char mapname[MAX_BUF]; - snprintf (mapname, MAX_BUF - 1, "%s/%s", &first_map_ext_path, &ob->arch->name); + snprintf (mapname, MAX_BUF - 1, "%s/%s", &first_map_ext_path, &ob->arch->archname); tmp = object::create (); EXIT_PATH (tmp) = mapname; EXIT_X (tmp) = ob->x; @@ -939,7 +942,7 @@ ob->remove_statbonus (); ob->remove (); ob->arch = get_player_archetype (ob->arch); - ob->arch->clone.copy_to (ob); + ob->arch->copy_to (ob); ob->instantiate (); ob->stats = ob->contr->orig_stats; ob->name = ob->name_pl = name; @@ -947,7 +950,7 @@ ob->y = y; SET_ANIMATION (ob, 2); /* So player faces south */ insert_ob_in_map (ob, ob->map, ob, 0); - assign (ob->contr->title, ob->arch->clone.name); + assign (ob->contr->title, ob->arch->object::name); ob->add_statbonus (); } while (!allowed_class (ob)); @@ -1102,7 +1105,7 @@ &tmp->name, tmp->type, (int) (query_cost (tmp, op, F_TRUE) * 100 / (tmp->weight * MAX (tmp->nrof, 1)))); else sprintf (putstring, "item name: %s item type: %d weight/value: %d", - &tmp->arch->name, tmp->type, (int) (query_cost (tmp, op, F_TRUE) * 100 / (tmp->weight * MAX (tmp->nrof, 1)))); + &tmp->arch->archname, tmp->type, (int) (query_cost (tmp, op, F_TRUE) * 100 / (tmp->weight * MAX (tmp->nrof, 1)))); new_draw_info (NDI_UNIQUE, 0, op, putstring); } @@ -1187,7 +1190,7 @@ } if (op->contr->mode & PU_READABLES) - if (tmp->type == BOOK || tmp->type == SCROLL) + if (tmp->type == BOOK || tmp->type == SCROLL || tmp->type == INSCRIBABLE) { pick_up (op, tmp); continue; @@ -1305,8 +1308,8 @@ { if (tmp->type == WEAPON && tmp->name != NULL) { - if (strstr (tmp->name, "table") == NULL && strstr (tmp->arch->name, "table") == NULL && - strstr (tmp->name, "chair") && strstr (tmp->arch->name, "chair") == NULL) + if (strstr (tmp->name, "table") == NULL && strstr (tmp->arch->archname, "table") == NULL && + strstr (tmp->name, "chair") && strstr (tmp->arch->archname, "chair") == NULL) { pick_up (op, tmp); continue; @@ -1315,7 +1318,7 @@ if (tmp->type == WEAPON && tmp->name == NULL) { - if (strstr (tmp->arch->name, "table") == NULL && strstr (tmp->arch->name, "chair") == NULL) + if (strstr (tmp->arch->archname, "table") == NULL && strstr (tmp->arch->archname, "chair") == NULL) { pick_up (op, tmp); continue; @@ -1350,7 +1353,7 @@ fprintf (stderr, "%s", tmp->name); } else - fprintf (stderr, "%s", tmp->arch->name); + fprintf (stderr, "%s", tmp->arch->archname); fprintf (stderr, ",%d] = ", tmp->type); fprintf (stderr, "%d\n", (int) (query_cost (tmp, op, F_TRUE) * 100 / (tmp->weight * MAX (tmp->nrof, 1)))); #endif @@ -1430,11 +1433,11 @@ for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) { attacktype = 1 << attacknum; - if ((arrow->attacktype & attacktype) && (target->arch->clone.resist[attacknum]) < 0) - if (((arrow->magic + arrow->stats.dam) * (100 - target->arch->clone.resist[attacknum]) / 100) > betterby) + if ((arrow->attacktype & attacktype) && (target->arch->resist[attacknum]) < 0) + if (((arrow->magic + arrow->stats.dam) * (100 - target->arch->resist[attacknum]) / 100) > betterby) { tmp = arrow; - betterby = (arrow->magic + arrow->stats.dam) * (100 - target->arch->clone.resist[attacknum]) / 100; + betterby = (arrow->magic + arrow->stats.dam) * (100 - target->arch->resist[attacknum]) / 100; } } if ((2 + arrow->magic + arrow->stats.dam) > betterby) @@ -1537,7 +1540,7 @@ fire_bow (object *op, object *part, object *arrow, int dir, int wc_mod, sint16 sx, sint16 sy) { object *left, *bow; - int bowspeed, mflags; + int mflags; maptile *m; if (!dir) @@ -1546,12 +1549,8 @@ return 0; } - if (player *pl = op->contr) - { - bow = pl->ranged_ob; - if (!op->change_weapon (bow)) - return 0; - } + if (op->contr) + bow = op->current_weapon; else { for (bow = op->inv; bow; bow = bow->below) @@ -1582,15 +1581,6 @@ return 0; } - bowspeed = bow->stats.sp + dex_bonus[op->stats.Dex]; - - /* penalize ROF for bestarrow */ - if (op->type == PLAYER && op->contr->bowtype == bow_bestarrow) - bowspeed -= dex_bonus[op->stats.Dex] + 5; - - if (bowspeed < 1) - bowspeed = 1; - if (arrow == NULL) { if ((arrow = find_arrow (op, bow->race)) == NULL) @@ -1641,29 +1631,36 @@ if (arrow->slaying) arrow->spellarg = strdup (arrow->slaying); - if (op->type == PLAYER) +#if 0 + if (player *pl = op->contr) { - op->speed_left = 0.01 - (float) FABS (op->speed) * 100 / bowspeed; - op->update_stats (); + float speed = pl->weapon_sp; + + /* penalize ROF for bestarrow */ + if (pl->bowtype == bow_bestarrow) + speed *= .9f; + else + speed *= 1.f + dex_bonus[op->stats.Dex] * .2f; + + op->speed_left += speed - op->speed; } +#endif SET_ANIMATION (arrow, arrow->direction); - arrow->stats.dam += op->stats.dam + arrow->magic; - /* update the speed */ - arrow->speed = ((bow->flag [FLAG_NO_STRENGTH] ? 0 : dam_bonus[op->stats.Str]) + bow->magic + arrow->magic) / 5.0 - + bow->stats.dam / 7.0; + arrow->speed = ((bow->flag [FLAG_NO_STRENGTH] ? 0 : dam_bonus[op->stats.Str]) + bow->magic + arrow->magic) / 5.f + + bow->stats.dam / 7.f; - arrow->set_speed (max (arrow->speed, 2.0)); + arrow->set_speed (max (arrow->speed, 2.f)); arrow->speed_left = 0; - arrow->stats.wc = op->stats.wc + wc_mod - arrow->magic - arrow->stats.wc; + int wc = op->stats.wc + wc_mod - arrow->magic - arrow->stats.wc; if (op->type == PLAYER) { arrow->level = op->chosen_skill ? op->chosen_skill->level : op->level; - arrow->stats.wc -= dex_bonus[op->stats.Dex]; + wc -= dex_bonus[op->stats.Dex]; if (!arrow->slaying) arrow->slaying = op->slaying; @@ -1681,12 +1678,14 @@ arrow->attacktype |= bow->attacktype; } - arrow->stats.wc -= arrow->level; + wc -= arrow->level; + arrow->stats.dam = clamp (arrow->stats.dam + op->stats.dam + arrow->magic, MIN_DAM, MAX_DAM); + arrow->stats.wc = clamp (wc, MIN_WC, MAX_WC); arrow->move_type = MOVE_FLY_LOW; arrow->move_on = MOVE_FLY_LOW | MOVE_WALK; - play_sound_map (op->map, op->x, op->y, SOUND_FIRE_ARROW); + op->play_sound (sound_find ("fire_arrow")); m->insert (arrow, sx, sy, op); if (!arrow->destroyed ()) @@ -1747,7 +1746,6 @@ return ret; } - /* Fires a misc (wand/rod/horn) object in 'dir'. * Broken apart from 'fire' to keep it more readable. */ @@ -1775,7 +1773,7 @@ { if (item->stats.food <= 0) { - play_sound_player_only (op->contr, SOUND_WAND_POOF, 0, 0); + op->contr->play_sound (sound_find ("wand_poof")); new_draw_info_format (NDI_UNIQUE, 0, op, "The %s goes poof.", query_base_name (item, 0)); return; @@ -1785,7 +1783,7 @@ { if (item->stats.hp < MAX (item->inv->stats.sp, item->inv->stats.grace)) { - play_sound_player_only (op->contr, SOUND_WAND_POOF, 0, 0); + op->contr->play_sound (sound_find ("wand_poof")); if (item->type == ROD) new_draw_info_format (NDI_UNIQUE, 0, op, "The %s whines for a while, but nothing happens.", query_base_name (item, 0)); @@ -1808,7 +1806,7 @@ if (item->arch) { CLEAR_FLAG (item, FLAG_ANIMATE); - item->face = item->arch->clone.face; + item->face = item->arch->face; item->set_speed (0); } @@ -1823,7 +1821,7 @@ /* Received a fire command for the player - go and do it. */ -void +bool fire (object *op, int dir) { int spellcost = 0; @@ -1837,13 +1835,21 @@ if (pl->golem) { control_golem (op->contr->golem, dir); - return; + return false; } object *ob = pl->ranged_ob; if (!ob) - return; + return false; + + if (!op->change_weapon (ob)) + return false; + + if (op->speed_left > 0.f) + --op->speed_left; + else + return false; switch (ob->type) { @@ -1860,7 +1866,6 @@ break; case SKILL: - case SKILL_TOOL: do_skill (op, op, ob, dir, 0); break; @@ -1868,6 +1873,8 @@ fire_misc_object (op, dir); break; } + + return true; } /* find_key @@ -1964,19 +1971,17 @@ static int player_attack_door (object *op, object *door) { - /* If its a door, try to find a use a key. If we do destroy the door, + /* If its a door, try to find a key. If we do destroy the door, * might as well return immediately as there is nothing more to do - * otherwise, we fall through to the rest of the code. */ object *key = find_key (op, op, door); - /* IF we found a key, do some extra work */ + /* If we found a key, do some extra work */ if (key) { object *container = key->env; - play_sound_map (op->map, op->x, op->y, SOUND_OPEN_DOOR); - if (action_makes_visible (op)) make_visible (op); @@ -2015,18 +2020,25 @@ * (taking into account confusion.) The player is also actually * going to try and move (not fire weapons). */ -void +bool move_player_attack (object *op, int dir) { - object *tmp, *mon; int on_battleground; - maptile *m; sint16 nx = freearr_x[dir] + op->x; sint16 ny = freearr_y[dir] + op->y; on_battleground = op_on_battleground (op, 0, 0); + if (out_of_map (op->map, nx, ny)) + return false; + + if (!op->contr->braced && op->speed_left > 0.f && move_ob (op, dir, op)) + { + --op->speed_left; + return true; + } + /* If braced, or can't move to the square, and it is not out of the * map, attack it. Note order of if statement is important - don't * want to be calling move_ob if braced, because move_ob will move the @@ -2036,110 +2048,92 @@ * quite a bit of processing. However, it probably is less than what * move_ob uses. */ - if ((op->contr->braced || !move_ob (op, dir, op)) && !out_of_map (op->map, nx, ny)) - { - if (OUT_OF_REAL_MAP (op->map, nx, ny)) - { - m = op->map->xy_find (nx, ny); - if (!m) - return; /* Don't think this should happen */ - } - else - m = op->map; + maptile *m = op->map->xy_find (nx, ny); - if (!(tmp = m->at (nx, ny).bot)) - return; - - mon = 0; - /* Go through all the objects, and find ones of interest. Only stop if - * we find a monster - that is something we know we want to attack. - * if its a door or barrel (can roll) see if there may be monsters - * on the space - */ - while (tmp) - { - if (tmp == op) - { - tmp = tmp->above; - continue; - } + /* Go through all the objects, and find ones of interest. Only stop if + * we find a monster - that is something we know we want to attack. + * if its a door or barrel (can roll) see if there may be monsters + * on the space + */ + object *mon; + for (mon = m->at (nx, ny).bot; mon; mon = mon->above) + { + if ((mon->flag [FLAG_ALIVE] + || mon->type == LOCKED_DOOR + || mon->flag [FLAG_CAN_ROLL]) + && mon != op) + break; + } - if (QUERY_FLAG (tmp, FLAG_ALIVE)) - { - mon = tmp; - break; - } + if (!mon) /* This happens anytime the player tries to move */ + return false; /* into a wall */ - if (tmp->type == LOCKED_DOOR || QUERY_FLAG (tmp, FLAG_CAN_ROLL)) - mon = tmp; + mon = mon->head_ (); - tmp = tmp->above; + if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR)) + if (op->contr->weapon_sp_left > 0.f) + if (player_attack_door (op, mon)) + { + --op->contr->weapon_sp_left; + return true; } - if (!mon) /* This happens anytime the player tries to move */ - return; /* into a wall */ - - if (mon->head) - mon = mon->head; - - if ((mon->type == DOOR && mon->stats.hp >= 0) || (mon->type == LOCKED_DOOR)) - if (player_attack_door (op, mon)) - return; + /* The following deals with possibly attacking peaceful + * or friendly creatures. Basically, all players are considered + * unaggressive. If the moving player has peaceful set, then the + * object should be pushed instead of attacked. It is assumed that + * if you are braced, you will not attack friends accidently, + * and thus will not push them. + */ - /* The following deals with possibly attacking peaceful - * or frienddly creatures. Basically, all players are considered - * unaggressive. If the moving player has peaceful set, then the - * object should be pushed instead of attacked. It is assumed that - * if you are braced, you will not attack friends accidently, - * and thus will not push them. - */ + /* If the creature is a pet, push it even if the player is not + * peaceful. Our assumption is the creature is a pet if the + * player owns it and it is either friendly or unagressive. + */ + if (op->type == PLAYER + && ((mon->owner && mon->owner->contr + && same_party (mon->owner->contr->party, op->contr->party)) + || mon->owner == op) + && (QUERY_FLAG (mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG (mon, FLAG_FRIENDLY))) + { + /* If we're braced, we don't want to switch places with it */ + if (op->contr->braced) + return false; - /* If the creature is a pet, push it even if the player is not - * peaceful. Our assumption is the creature is a pet if the - * player owns it and it is either friendly or unagressive. - */ - if ((op->type == PLAYER) -#if COZY_SERVER - && - ((mon->owner && mon->owner->contr - && same_party (mon->owner->contr->party, op->contr->party)) || mon->owner == op) -#else - && mon->owner == op -#endif - && (QUERY_FLAG (mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG (mon, FLAG_FRIENDLY))) + if (op->speed_left > 0.f) { - /* If we're braced, we don't want to switch places with it */ - if (op->contr->braced) - return; + --op->speed_left; - play_sound_map (op->map, op->x, op->y, SOUND_PUSH_PLAYER); + op->play_sound (sound_find ("push_player")); push_ob (mon, dir, op); + if (op->contr->tmp_invis || op->hide) make_visible (op); - return; + return true; } + else + return false; + } - /* in certain circumstances, you shouldn't attack friendly - * creatures. Note that if you are braced, you can't push - * someone, but put it inside this loop so that you won't - * attack them either. - */ - if ((mon->type == PLAYER || mon->enemy != op) && - (mon->type == PLAYER || QUERY_FLAG (mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG (mon, FLAG_FRIENDLY)) && ( -#ifdef PROHIBIT_PLAYERKILL - (op->contr->peaceful - || (mon->type == PLAYER - && mon->contr-> - peaceful)) && -#else - op->contr->peaceful && -#endif - !on_battleground)) + /* in certain circumstances, you shouldn't attack friendly + * creatures. Note that if you are braced, you can't push + * someone, but put it inside this loop so that you won't + * attack them either. + */ + if ((mon->type == PLAYER || mon->enemy != op) + && (mon->type == PLAYER || QUERY_FLAG (mon, FLAG_UNAGGRESSIVE) || QUERY_FLAG (mon, FLAG_FRIENDLY)) + && ((op->contr->peaceful + || (mon->type == PLAYER && mon->contr->peaceful)) + && !on_battleground)) + { + if (op->speed_left > 0.f) { + --op->speed_left; + if (!op->contr->braced) { - play_sound_map (op->map, op->x, op->y, SOUND_PUSH_PLAYER); + op->play_sound (sound_find ("push_player")); push_ob (mon, dir, op); } else @@ -2147,63 +2141,52 @@ if (op->contr->tmp_invis || op->hide) make_visible (op); - } - /* If the object is a boulder or other rollable object, then - * roll it if not braced. You can't roll it if you are braced. - */ - else if (QUERY_FLAG (mon, FLAG_CAN_ROLL) && (!op->contr->braced)) + return true; + } + } + /* If the object is a boulder or other rollable object, then + * roll it if not braced. You can't roll it if you are braced. + */ + else if (QUERY_FLAG (mon, FLAG_CAN_ROLL) && (!op->contr->braced)) + { + if (op->speed_left > 0.f) { + --op->speed_left; + recursive_roll (mon, dir, op); if (action_makes_visible (op)) make_visible (op); - } - /* Any generic living creature. Including things like doors. - * Way it works is like this: First, it must have some hit points - * and be living. Then, it must be one of the following: - * 1) Not a player, 2) A player, but of a different party. Note - * that party_number -1 is no party, so attacks can still happen. - */ - else if ((mon->stats.hp >= 0) && QUERY_FLAG (mon, FLAG_ALIVE) && - ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) + return true; + } + } + /* Any generic living creature. Including things like doors. + * Way it works is like this: First, it must have some hit points + * and be living. Then, it must be one of the following: + * 1) Not a player, 2) A player, but of a different party. Note + * that party_number -1 is no party, so attacks can still happen. + */ + else if ((mon->stats.hp >= 0) && QUERY_FLAG (mon, FLAG_ALIVE) && + ((mon->type != PLAYER || op->contr->party == NULL || op->contr->party != mon->contr->party))) + { + if (op->contr->weapon_sp_left > 0.f && !op->flag [FLAG_WIZPASS]) { - - /* If the player hasn't hit something this tick, and does - * so, give them speed boost based on weapon speed. Doing - * it here is better than process_players2, which basically - * incurred a 1 tick offset. - */ - if (!op->contr->has_hit) - { - op->speed_left += op->speed / op->contr->weapon_sp; - - op->contr->has_hit = 1; /* The last action was to hit, so use weapon_sp */ - } + --op->contr->weapon_sp_left; skill_attack (mon, op, 0, 0, 0); - /* If attacking another player, that player gets automatic - * hitback, and doesn't loose luck either. - * Disable hitback on the battleground or if the target is - * the wiz. - */ - if (mon->type == PLAYER && mon->stats.hp >= 0 && !mon->contr->has_hit && !on_battleground && !QUERY_FLAG (mon, FLAG_WIZ)) - { - short luck = mon->stats.luck; - - mon->contr->has_hit = 1; - skill_attack (op, mon, 0, 0, 0); - mon->stats.luck = luck; - } - if (action_makes_visible (op)) make_visible (op); + + return true; } - } /* if player should attack something */ + } + + return false; } -int +bool move_player (object *op, int dir) { int pick; @@ -2227,13 +2210,15 @@ if (op->hide) do_hidden_move (op); + bool retval; + if (INVOKE_PLAYER (MOVE, op->contr, ARG_INT (dir))) - /*nop */ ; + retval = RESULT_INT (0); else if (op->contr->fire_on) - fire (op, dir); + retval = fire (op, dir); else { - move_player_attack (op, dir); + retval = move_player_attack (op, dir); pick = check_pick (op); } @@ -2250,7 +2235,8 @@ * for players. */ animate_object (op, op->facing); - return 0; + + return retval; } /* This is similar to handle_player, below, but is only used by the @@ -2258,20 +2244,24 @@ * This is sort of special, in that the new client/server actually uses * the new speed values for commands. * - * Returns true if there are more actions we can do. + * Returns true if there are more actions we can do. Should not do + * many actions in a row, as that would be too unfair to other + * players. */ -int +bool handle_newcs_player (object *op) { if (QUERY_FLAG (op, FLAG_SCARED)) { - flee_player (op); - /* If player is still scared, that is his action for this tick */ - if (QUERY_FLAG (op, FLAG_SCARED)) + if (op->speed_left > 0.f) { - op->speed_left--; - return 0; + --op->speed_left; + flee_player (op); + + return true; } + else + return false; } /* call this here - we also will call this in do_ericserver, but @@ -2279,26 +2269,12 @@ * called, so we recheck it here. */ if (op->contr->ns->handle_command ()) - return 1; - - if (op->speed_left > 0) - { - if (op->direction && (op->contr->run_on || op->contr->fire_on)) - { - /* All move commands take 1 tick, at least for now */ - op->speed_left--; - - /* Instead of all the stuff below, let move_player take care - * of it. Also, some of the skill stuff is only put in - * there, as well as the confusion stuff. - */ - move_player (op, op->direction); + return true; - return op->speed_left > 0; - } - } + if (op->direction && (op->contr->run_on || op->contr->fire_on)) + return move_player (op, op->direction); - return 0; + return false; } int @@ -2310,7 +2286,7 @@ for (object *tmp = op->inv; tmp; tmp = tmp->below) if (QUERY_FLAG (tmp, FLAG_APPLIED) && QUERY_FLAG (tmp, FLAG_LIFESAVE)) { - play_sound_map (op->map, op->x, op->y, SOUND_OB_EVAPORATE); + op->play_sound (sound_find ("ob_evaporate")); new_draw_info_format (NDI_UNIQUE, 0, op, "Your %s vibrates violently, then evaporates.", query_name (tmp)); if (op->contr) @@ -2340,8 +2316,8 @@ * function will descend into containers. op is the object to start the search * from. */ -void -remove_unpaid_objects (object *op, object *env) +static void +drop_unpaid_items (object *op, object *env) { while (op) { @@ -2355,12 +2331,19 @@ op->insert_at (env); } else if (op->inv) - remove_unpaid_objects (op->inv, env); + drop_unpaid_items (op->inv, env); op = next; } } +void +object::drop_unpaid_items () +{ + if (!flag [FLAG_REMOVED]) + ::drop_unpaid_items (inv, this); +} + /* * Returns pointer a static string containing gravestone text * Moved from apply.c to player.c - player.c is what @@ -2574,17 +2557,10 @@ /* Digestion */ if (--op->last_eat < 0) { -#ifdef COZY_SERVER - int dg = op->contr->digestion >= 0 && op->contr->digestion < 2 ? 2 : op->contr->digestion; - int bonus = dg > 0 ? dg : 0, penalty = dg < 0 ? -dg : 0; -#else - int bonus = op->contr->digestion > 0 ? op->contr->digestion : 0, penalty = op->contr->digestion < 0 ? -op->contr->digestion : 0; -#endif + int bonus = max (0, op->contr->digestion), + penalty = max (0, -op->contr->digestion); - if (op->contr->gen_hp > 0) - op->last_eat = 25 * (1 + bonus) / (op->contr->gen_hp + penalty + 1); - else - op->last_eat = 25 * (1 + bonus) / (penalty + 1); + op->last_eat = 25 * (1 + bonus) / (max (0, op->contr->gen_hp) + penalty + 1); /* dms do not consume food */ if (!QUERY_FLAG (op, FLAG_WIZ)) @@ -2655,7 +2631,6 @@ if (save_life (op)) return; - /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas * in cities ONLY!!! It is very important that this doesn't get abused. * Look at op_on_battleground() for more info --AndreasV @@ -2717,7 +2692,7 @@ else sprintf (buf, "%s died.", &op->name); - play_sound_player_only (op->contr, SOUND_PLAYER_DIES, 0, 0); + op->contr->play_sound (sound_find ("player_dies")); /* save the map location for corpse, gravestone */ x = op->x; @@ -2904,7 +2879,7 @@ * Check to see if the player has any unpaid items. If so, remove them * and put them back in the map. */ - remove_unpaid_objects (op->inv, op); + op->drop_unpaid_items (); /****************************************/ /* */ @@ -2934,8 +2909,8 @@ force = get_archetype (FORCE_NAME); /* 50 ticks should be enough time for the spell to abate */ - force->speed = 0.1; - force->speed_left = -5.0; + force->speed = 0.1f; + force->speed_left = -5.f; SET_FLAG (force, FLAG_APPLIED); for (at = 0; at < NROFATTACKS; at++) if (will_kill_again & (1 << at)) @@ -3066,7 +3041,7 @@ int is_true_undead (object *op) { - if (QUERY_FLAG (&op->arch->clone, FLAG_UNDEAD)) + if (QUERY_FLAG (op->arch, FLAG_UNDEAD)) return 1; return 0; @@ -3120,7 +3095,6 @@ * AND, for players, if they move into a ridiculously unhideable * spot (surrounded by clear terrain in broad daylight). -b.t. */ - void do_hidden_move (object *op) { @@ -3247,8 +3221,8 @@ */ while (op) { - dx = rv.distance_x + op->arch->clone.x; - dy = rv.distance_y + op->arch->clone.y; + dx = rv.distance_x + op->arch->x; + dy = rv.distance_y + op->arch->y; /* only the viewable area the player sees is updated by LOS * code, so we need to restrict ourselves to that range of values @@ -3383,7 +3357,7 @@ } /* everything seems okay - now bring on the gift: */ - item = &(tr->item->clone); + item = tr->item; if (item->type == SPELL) { @@ -3452,8 +3426,7 @@ object *skin; /* first get the dragon skin force */ - shstr_cmp dragon_skin_force ("dragon_skin_force"); - for (skin = who->inv; skin && !(skin->arch->name == dragon_skin_force); skin = skin->below) + for (skin = who->inv; skin && !(skin->arch->archname == shstr_dragon_skin_force); skin = skin->below) ; if (!skin)