/************************************************************** * FFTacticsMUD : move.cpp * ************************************************************** * (c) 2002 Damien Dailidenas (Trenton). All rights reserved. * **************************************************************/ #include "main.h" #include <strstream> short dir_id(const string str) { return find(str, "north") ? DIR_N : find(str, "south") ? DIR_S : find(str, "east") ? DIR_E : find(str, "west") ? DIR_W : find(str, "ne") ? DIR_NE : find(str, "nw") ? DIR_NW : find(str, "se") ? DIR_SE : find(str, "sw") ? DIR_SW : find(str, "up") ? DIR_UP : DIR_DOWN; } bool CH::can_move(const ROOM *room) { if(!room) return false; return true; } void do_move(CH *ch, string argument="") { if(!ch->battle_room) { if(argument.empty() || !find(argument, "n e s w", true)) { ch->printf("Usage: move [n | e | s | w]\n\r"); return; } if(ch->room != ch->area->room[ROOM_OUTSIDE]) { ch->room->echo(ch->name + " leaves.\n\r", ch); ch->to(ch->area->room[ROOM_OUTSIDE]); do_look(ch); ch->room->echo(ch->name + " arrives.\n\r", ch); return; } short dir = dir_id(argument); if(!ch->can_move(ch->area->exits[dir])) { ch->printf("ERROR: Can't move " + (string)dir_name[dir] + ".\n\r"); return; } if(ch->group && ch->group->leader != ch && !ch->following) ch->leave_group(); ch->room->echo(ch->name + " leaves " + dir_name[dir] + ".\n\r", ch); ch->to(ch->to_room); ch->following = NULL; do_look(ch); ch->room->echo(ch->name + " arrives from the " + dir_name[rev_dir[dir]] + ".\n\r", ch); if(ch->group && ch->group->leader == ch) { for(CH *pers = ch->group->people; pers; pers = pers->next_in_group) { if(pers != ch) { pers->following = ch; do_move(pers, argument); } } } // if((!ch->group || ch->group->leader == ch) && ch->area->battle_area && num_percent() < 50) // ch->load_battle(); return; } if(ch->battle->turn == ch && !ch->orig_room) { if(!ch->temp_action.action) ch->temp_action.action = do_move; ch->temp_action.range = (ch->temp_action.action == do_act ? ch->get_act_range(ch->action.id) : ch->get_move_range()); ch->orig_room = ch->battle_room; do_look(ch); ch->printf("Move to a location within the %s circle.\n\rType 'ok' when done or 'cancel' to go back.\n\r", ch->temp_action.action == do_act ? "red" : "blue"); ch->commands = "move ok cancel"; return; } string arg; split(argument, arg); if(arg.empty() || !find(arg, "n e s w", true)) { ch->printf("Usage: move [direction] -[distance]\n\r"); return; } short distance = argument.empty() || !is_num(argument) ? 1 : atoi(argument.c_str()); ch->to_room = ch->battle_room; short dir = dir_id(arg); for(short x = 0; x < distance; ++x) { if(!ch->move(dir)) { ch->printf("move: ERROR: Can't move %d %s.\n\r", distance, arg.c_str()); return; } } ch->to(ch->to_room); do_look(ch); ch->check_battle(); return; } const char *dir_name[] = { "north", "east", "south", "west", "northeast", "northwest", "southeast", "southwest" }; const char *sh_dir_name[] = { "n", "e", "s", "w", "ne", "nw", "se", "sw", "u", "d" }; const short rev_dir[] = { 2, 3, 0, 1, 7, 6, 5, 4 }; bool CH::move(const short dir) { BATTLE_ROOM *to_room = NULL, *room = this->to_room; long id = 0, size = battle->area->size(); if(dir == DIR_N) id = room->id - battle->area->width; else if(dir == DIR_S) id = room->id + battle->area->width; else if(dir == DIR_E) id = room->id + 1; else if(dir == DIR_W) id = room->id - 1; else if(dir == DIR_NW) id = room->id - battle->area->width - 1; else if(dir == DIR_NE) id = room->id - battle->area->width + 1; else if(dir == DIR_SW) id = room->id + battle->area->width - 1; else if(dir == DIR_SE) id = room->id + battle->area->width + 1; if(id > size) id -= size; else if(id < 1) id += size; to_room = battle->area->room[id]; if(to_room && ((abs)(to_room->x - room->x) > 22 || (abs)(to_room->y - room->y) > 22)) to_room = NULL; if(!to_room) return false; this->to_room = to_room; return true; } void CH::retreat() { CH *victim = get_nearest_target(false); if(victim) { short distance = this->distance(victim) + Mv + 1, x; while(distance--) { for(x = 1; battle->area->room[x]; ++x) { if(!battle->area->room[x]->people && battle->area->room[x]->distance(victim->battle_room) == distance && battle->area->room[x]->distance(battle_room) <= Mv) { to(battle->area->room[x]); return; } } } } return; } bool CH::move_within_range(CH *victim) { for(short x = 1; battle->area->room[x]; ++x) { if(!battle->area->room[x]->people && battle->area->room[x]->distance(victim->battle_room) <= temp_action.range) { battle->echo("{B" + name + " moved.{0\n\r"); to(battle->area->room[x]); return true; } } return false; } void CH::advance() { CH *victim = get_nearest_target(false); if(victim) { short distance, x, pdist = this->distance(victim), rdist; for(distance = MIN(pdist - Mv, 0); distance < pdist; ++distance) { for(x = 1; battle->area->room[x]; ++x) { if(!battle->area->room[x]->people && (rdist = battle->area->room[x]->distance(victim->battle_room)) == distance && rdist < pdist && battle->area->room[x]->distance(battle_room) <= Mv) { to(battle->area->room[x]); return; } } } } return; } void CH::to(ROOM *room) { from_battle_room(); from_room(); this->room = room; next_in_room = room->people; room->people = this; area = room->area; return; } void CH::from_room() { if(!room) return; if(this == room->people) room->people = next_in_room; else { for(CH *prev = room->people; prev; prev = prev->next_in_room) { if(prev->next_in_room == this) { prev->next_in_room = next_in_room; break; } } } room = NULL; next_in_room = NULL; return; } void CH::to(BATTLE_ROOM *room) { from_room(); from_battle_room(); battle_room = room; next_in_room = room->people; room->people = this; return; } void CH::from_battle_room() { if(!battle_room) return; if(this == battle_room->people) battle_room->people = next_in_room; else { for(CH *prev = battle_room->people; prev; prev = prev->next_in_room) { if(prev->next_in_room == this) { prev->next_in_room = next_in_room; break; } } } battle_room = NULL; next_in_room = NULL; return; } short CH::get_act_range(const short id) { if(skill_table[id].job == JOB_CHEMIST && skill_table[id].type == SK_ACTION) if(cjob == JOB_CHEMIST || has_skill("Throw Item", true)) return 4; if(skill_table[id].fun == do_attack || (skill_table[id].job == JOB_ARCHER && skill_table[id].type == SK_ACTION)) return (eq[LOC_RHAND] ? obj_table[eq[LOC_RHAND]->id].range : 1); return skill_table[id].range; } short CH::get_move_range() { short range = Mv; if(has_skill("Move +1", true)) ++range; return range; } void CH::check_battle() { if(room->area->battle()) room->area->battle()(this); return; }