/*------------------------------------------------------------------------\ | mobact.c : Mobile AI Routines www.yourmud.org | | Copyright (C) 2006, Project Argila: Auroness | | | | All rights reserved. See Licensing documents included. | | | | Based upon Shadows of Isildur RPI Engine | | Copyright C. W. McHenry [Traithe], 2004 | | Derived under license from DIKU GAMMA (0.0). | \------------------------------------------------------------------------*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <signal.h> #include "structs.h" #include "protos.h" #include "utils.h" #include "decl.h" #define JAILBAG_DESC_PREPEND "Belongings for" int is_wanted_in_area (CHAR_DATA *ch) { if ( !ch || !ch->room ) return 0; if ( get_affect (ch, MAGIC_CRIM_BASE + ch->room->zone) ) return 1; if ( get_affect (ch, MAGIC_CRIM_HOODED + ch->room->zone) ) return 1; return 0; } int enforcer (CHAR_DATA *ch, CHAR_DATA *crim, int will_act, int witness) { OBJ_DATA *obj; /* Return values: -1 ch is unable to enforce anyone 0 ch is unable to enforce crim 1 ch will enforce crim will_act 0 ch won't do anything about the criminal act 1 ch will do something: stand or attack witness (can also mean guard just saw through disguise) 0 enforcer didn't see the act 1 enforcer saw the act, so MAY attack or react */ /* int db_on = 0; */ char buf [MAX_STRING_LENGTH]; if ( ch == crim ) return 0; if ( ch->pc ) return -1; if ( !IS_SET (ch->act, ACT_ENFORCER) ) return -1; if ( ch->fighting ) return -1; if ( ch->desc ) return -1; if ( is_room_affected (ch->room->affects, MAGIC_ROOM_CALM) ) return -1; if ( IS_SUBDUEE (ch) ) return -1; if ( !CAN_SEE (ch, crim) ) return 0; if ( IS_SUBDUEE (crim) ) return 0; if ( is_brother (ch, crim) ) return 0; /**ToDo this logicl is confusing. It needs to be cleaned up **/ if (!get_affect (crim, MAGIC_CRIM_HOODED + ch->room->zone ) && !(is_hooded (crim) && witness && get_affect (crim, MAGIC_CRIM_BASE + ch->room->zone)) && !(!is_hooded (crim) && get_affect (crim, MAGIC_CRIM_BASE + ch->room->zone))){ return 0; } /* A bad guy. Deal with him. */ if ( GET_POS (ch) == SIT || GET_POS (ch) == REST ) { if ( will_act ) add_second_affect (SPA_STAND, 4, ch, NULL, NULL, 0); return -1; } if ( !will_act ) return 1; if ( !ch->fighting && !ch->ranged_enemy && !ch->delay ) { do_say (ch, "Surrender, now, or pay the consequences!", 0); } if ( !IS_SET (crim->act, ACT_PARIAH) && !IS_SET (crim->act, ACT_AGGRESSIVE) && real_skill (ch, SKILL_SUBDUE) && zone_table [ch->mob->zone].jail_room && (GET_POS(crim) == UNCON || GET_POS(crim) == SLEEP) ) { name_to_ident (crim, buf); do_subdue (ch, buf, 0); return 1; } else { for ( obj = ch->equip; obj; obj = obj->next_content ) if ( obj->o.weapon.use_skill == SKILL_LONGBOW || obj->o.weapon.use_skill == SKILL_SHORTBOW || obj->o.weapon.use_skill == SKILL_CROSSBOW ) break; if ( ch->right_hand && (ch->right_hand->o.weapon.use_skill == SKILL_SHORTBOW || ch->right_hand->o.weapon.use_skill == SKILL_LONGBOW || ch->right_hand->o.weapon.use_skill == SKILL_CROSSBOW) ) { obj = ch->right_hand; } if ( ch->left_hand && (ch->left_hand->o.weapon.use_skill == SKILL_SHORTBOW || ch->left_hand->o.weapon.use_skill == SKILL_LONGBOW || ch->left_hand->o.weapon.use_skill == SKILL_CROSSBOW) ) { obj = ch->left_hand; } set_fighting (ch, crim); return 1; } return 0; } CHAR_DATA *mob_remembers_whom (CHAR_DATA *ch) { CHAR_DATA *tch; ROOM_DATA *room; struct memory_data *mem; room = ch->room; if ( !IS_SET (ch->act, ACT_MEMORY) ) return 0; for ( tch = room->people; tch; tch = tch->next_in_room ) { if ( IS_NPC (tch) || !CAN_SEE (ch, tch) ) continue; for ( mem = ch->remembers; mem; mem = mem->next ) if ( !strcmp (mem->name, GET_NAME (tch)) ) { if ( tch->fighting && IS_SET (tch->flags, FLAG_SUBDUING) ) continue; return tch; } } return NULL; } int mob_remembers (CHAR_DATA *ch) { CHAR_DATA *tch; if ( (tch = mob_remembers_whom (ch)) ) { set_fighting (ch, tch); return 1; } return 0; } #define MOB_IGNORES_DOORS -1 int mob_wander (CHAR_DATA *ch) { ROOM_DATA *room_exit = NULL; ROOM_DATA *room = NULL; int room_exit_zone = 0; int room_exit_virt = 0; int exit_tab [6]; int zone = 0; int num_exits = 0; int to_exit = 0; int i = 0; int door = MOB_IGNORES_DOORS; char buf[MAX_STRING_LENGTH] = {'\0'}; char buf2[MAX_STRING_LENGTH] = {'\0'}; if ( !IS_SET (ch->act, ACT_ENFORCER) && number (0, 5) ) return 0; else if ( IS_SET (ch->act, ACT_ENFORCER) && number (0, 2) ) return 0; room = ch->room; zone = room->zone; if ( IS_SET (ch->act, ACT_SENTINEL) ) return 0; if ( IS_SET (ch->act, ACT_VEHICLE) ) return 0; if ( (ch->following && ch->following->room == ch->room) || number (0, 9) ) return 0; if ( GET_POS (ch) != POSITION_STANDING ) return 0; if ( ch->desc && ch->desc->original ) return 0; if ( IS_RIDEE (ch) && (IS_SET (ch->mount->act, ACT_SENTINEL) || !IS_NPC (ch->mount)) ) return 0; if ( IS_HITCHEE (ch) && (IS_SET (ch->hitcher->act, ACT_SENTINEL) || !IS_NPC (ch->hitcher)) ) return 0; if ( IS_SUBDUEE (ch) ) return 0; /* Decide here if we want to open a door */ door = ( ch->race > RACE_HUMAN || is_mounted(ch) ) ? MOB_IGNORES_DOORS : ( rand() % 6 ) ; for ( i = 0; i < 6; i++ ) { if ( ( ! PASSAGE(ch,i) ) || /* IF Dir not an exit */ ( PASSAGE(ch,i)->to_room == NOWHERE ) || /* OR Exit to nowhere */ ( IS_SET(PASSAGE(ch, i)->exit_info, PASSAGE_CLOSED) && /* OR closed doors AND */ ( ( i != door ) || /* -- IF ch is ignoring door */ ( PASSAGE(ch,i)->exit_info != (PASSAGE_ISDOOR | PASSAGE_CLOSED) ) /* -- OR they are complex */ ))) { continue; } room_exit = vtor (PASSAGE (ch, i)->to_room); if ( !room_exit ) { continue; } room_exit_zone = room_exit->zone; if ( !IS_SET (room_exit->room_flags, NO_MOB) && !IS_SET (ch->flags, FLAG_KEEPER) && IS_SET (room_exit->room_flags, NO_MERCHANT) && !(ch->mob->noaccess_flags && room_exit->room_flags) && (!ch->mob->access_flags || (ch->mob->access_flags && room_exit->room_flags)) && !IS_SET (ch->act, ACT_STAY_ZONE) && zone != room_exit_zone) exit_tab [num_exits++] = i; } if ( num_exits == 0 ) return 0; to_exit = number (1, num_exits) - 1; if ( vtor (PASSAGE (ch, exit_tab [to_exit])->to_room)->virtual == ch->last_room ) to_exit = (to_exit + 1) % num_exits; room_exit_virt = vtor (PASSAGE (ch, exit_tab [to_exit])->to_room)->virtual; ch->last_room = room_exit_virt; i = exit_tab [to_exit]; if ( IS_SET (ch->room->dir_option [i]->exit_info, PASSAGE_CLOSED) ) { (void)one_argument (ch->room->dir_option [i]->keyword, buf2); snprintf (buf, MAX_STRING_LENGTH, "%s %s", buf2, dirs [i]); do_open (ch, buf, 0); } if (IS_SET(ch->affected_by, AFF_SNEAK)) { ch->speed = 0; do_sneak (ch, NULL, exit_tab [to_exit]); } else do_move (ch, "", exit_tab [to_exit]); return 1; } void common_guard (CHAR_DATA *ch) { int dir; int knocked = 0; bool bleeding = FALSE; bool nodded = FALSE; char buf [MAX_STRING_LENGTH]; char buf2 [MAX_STRING_LENGTH]; char buf3 [MAX_STRING_LENGTH]; ROOM_DATA *room; WOUND_DATA *wound; CHAR_DATA *tch; for ( wound = ch->subdue->wounds; wound; wound = wound->next ) if ( wound->bleeding ) bleeding = TRUE; if ( bleeding ) { name_to_ident (ch->subdue, buf); do_bind (ch, buf, 0); return; } if ( !is_wanted_in_area (ch->subdue) && !IS_SET (ch->act, ACT_JAILER) ) { do_release (ch, "", 0); return; } if ( is_hooded(ch->subdue) ) { if ( get_equip (ch->subdue, WEAR_ABOUT) && IS_SET (get_equip (ch->subdue, WEAR_ABOUT)->obj_flags.extra_flags, ITEM_MASK) ) { (void)one_argument (get_equip (ch->subdue, WEAR_ABOUT)->name, buf); name_to_ident (ch->subdue, buf2); snprintf (buf3, MAX_STRING_LENGTH, "%s %s", buf, buf2); do_take (ch, buf3, 0); do_junk (ch, buf, 0); return; } if ( get_equip (ch->subdue, WEAR_HEAD) && IS_SET (get_equip (ch->subdue, WEAR_ABOUT)->obj_flags.extra_flags, ITEM_MASK) ) { (void)one_argument (get_equip (ch->subdue, WEAR_ABOUT)->name, buf); name_to_ident (ch->subdue, buf2); snprintf (buf3, MAX_STRING_LENGTH, "%s %s", buf, buf2); do_take (ch, buf3, 0); do_junk (ch, buf, 0); return; } if ( get_equip (ch->subdue, WEAR_FACE) && IS_SET (get_equip (ch->subdue, WEAR_ABOUT)->obj_flags.extra_flags, ITEM_MASK) ) { (void)one_argument (get_equip (ch->subdue, WEAR_ABOUT)->name, buf); name_to_ident (ch->subdue, buf2); snprintf (buf3, MAX_STRING_LENGTH, "%s %s", buf, buf2); do_take (ch, buf3, 0); do_junk (ch, buf, 0); return; } } room = ch->room; if ( ch->in_room == zone_table [ch->mob->zone].jail_room_num ) { if ( !zone_table [ch->mob->zone].jailer || !vtom (zone_table [ch->mob->zone].jailer) ) { printf ("Attempting to release to room.\n"); fflush (stdout); do_release (ch, "", 0); return; } strcpy (buf, "to "); (void)one_argument (GET_NAMES (vtom (zone_table [ch->mob->zone].jailer)), buf + 3); do_release (ch, buf, 0); if ( ch->mob->spawnpoint ) { act ("$n returns to duty.", TRUE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); char_from_room (ch); char_to_room (ch, ch->mob->spawnpoint); act ("$n arrives.", TRUE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); } return; } dir = track (ch, zone_table [ch->mob->zone].jail_room_num); if ( dir == -1 ) { snprintf (buf, MAX_STRING_LENGTH, "Couldn't track guard to jail: in room %d, guard %d", ch->in_room, ch->mob->virtual); system_log (buf, TRUE); do_release (ch, "", 0); return; } if ( !ch->room->dir_option [dir] ) { snprintf (buf, MAX_STRING_LENGTH, "NON-REV error, guard can't track: in room %d, guard %d", ch->in_room, ch->mob->virtual); system_log (buf, TRUE); do_release (ch, "", 0); return; } (void)one_argument (ch->room->dir_option [dir]->keyword, buf2); if ( IS_SET (ch->room->dir_option [dir]->exit_info, PASSAGE_LOCKED) ) { if ( ch->room->dir_option[dir]->key ) { for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( get_obj_in_list_num (ch->room->dir_option[dir]->key, tch->right_hand) || get_obj_in_list_num (ch->room->dir_option[dir]->key, tch->left_hand) ) { name_to_ident (tch, buf2); snprintf (buf, MAX_STRING_LENGTH, "%s", buf2); do_nod (ch, buf, 0); nodded = TRUE; break; } } } if ( !nodded ) { snprintf (buf, MAX_STRING_LENGTH, "%s %s", buf2, dirs [dir]); do_knock (ch, buf, 0); knocked = 1; } } else if ( IS_SET (ch->room->dir_option [dir]->exit_info, PASSAGE_CLOSED) ) { snprintf (buf, MAX_STRING_LENGTH, "%s %s", buf2, dirs [dir]); do_open (ch, buf, 0); } if ( !knocked && !CAN_GO (ch, dir) ) { send_to_room ("Hmmm, I can't take you any further.\n", ch->in_room); do_release (ch, "", 0); } else do_move (ch, "", dir); } void jailer_func (CHAR_DATA *ch) { CHAR_DATA *victim; OBJ_DATA *obj; OBJ_DATA *bag = NULL; int cells [] = { ch->cell_1, ch->cell_2, ch->cell_3 }; char buf [MAX_STRING_LENGTH]; char msg [MAX_STRING_LENGTH]; char *date = NULL; OBJ_DATA *temp_arg = NULL; if ( !IS_SUBDUER (ch) ) { /* How can this happen? Just release guy */ do_release (ch, "", 0); return; } victim = ch->subdue; if ( !is_wanted_in_area (victim) ) { do_release (ch, "", 0); return; } act ("$N brutally smashes you on the back of your head!", FALSE, victim, 0, ch, TO_CHAR); GET_POS (victim) = SLEEP; act ("$n smashes $N on the head and removes $s possessions.", FALSE, ch, 0, victim, TO_NOTVICT); bag = load_object (VNUM_JAILBAG); if ( bag && (victim->right_hand || victim->left_hand || victim->equip) ) { snprintf (buf, MAX_STRING_LENGTH, "A prison bag, labeled '%s %s' sits here.", JAILBAG_DESC_PREPEND, victim->short_descr); bag->description = str_dup (buf); snprintf (buf, MAX_STRING_LENGTH, "a bag labeled '%s %s'", JAILBAG_DESC_PREPEND, victim->short_descr); bag->short_description = str_dup (buf); if ( IS_NPC (victim) ) bag->obj_timer = 24 * 4; /* one rl day */ if ( victim->right_hand ) { obj = victim->right_hand; obj_from_char (&obj, 0); if ( bag ) obj_to_obj (obj, bag); } if ( victim->left_hand ) { obj = victim->left_hand; obj_from_char (&obj, 0); if ( bag ) obj_to_obj (obj, bag); } while ( victim->equip ) { obj = victim->equip; if ( bag ){ temp_arg = unequip_char (victim, obj->location); obj_to_obj (temp_arg, bag); } } obj_to_room (bag, ch->in_room); } do_release (ch, "", 0); char_from_room (victim); char_to_room (victim, cells [number (0, 2)]); send_to_room ("The jailer tosses his prisoner into a cell.\n\r", ch->in_room); act ("The jailer tosses $n into the cell with you.", FALSE, victim, 0, 0, TO_ROOM); date = timestr(date); snprintf (msg, MAX_STRING_LENGTH, "Imprisoned in cell VNUM %d until wanted time expires.\n", victim->in_room); snprintf (buf, MAX_STRING_LENGTH, "Jailed in %s.", zone_table[ch->room->zone].name); add_message (victim->tname, 3, "Server", date, buf, "", msg, 0); snprintf (msg, MAX_STRING_LENGTH, "Imprisoned in cell VNUM %d until wanted time expires.\n\nCheck %s playerfile notes for relevant charges.\n", victim->in_room, HSHR(victim)); snprintf (buf, MAX_STRING_LENGTH, "#1Jailed:#0 %s", victim->tname); add_message ("Prisoners", 2, "Server", date, buf, "", msg, 0); } int has_weapon (CHAR_DATA *ch) { OBJ_DATA *obj; if ( (obj = get_equip (ch, WEAR_BOTH)) ) { if ( GET_ITEM_TYPE (obj) == ITEM_WEAPON ) if ( obj->o.od.value[1] * obj->o.od.value[2] > 3 ) return 1; } if ( (obj = get_equip (ch, WEAR_PRIM)) ) { if ( GET_ITEM_TYPE (obj) == ITEM_WEAPON ) if ( obj->o.od.value[1] * obj->o.od.value[2] > 3 ) return 1; } if ( (obj = get_equip (ch, WEAR_SEC)) ) { if ( GET_ITEM_TYPE (obj) == ITEM_WEAPON ) if ( obj->o.od.value[1] * obj->o.od.value[2] > 3 ) return 1; } return 0; } int enforcer_weapon_check (CHAR_DATA *ch) { CHAR_DATA *tch; int weapon_count = 0; char buf [MAX_STRING_LENGTH]; char buf2 [MAX_STRING_LENGTH]; if ( !IS_SET (ch->act, ACT_ENFORCER) || !is_area_enforcer (ch) || !IS_SET (ch->room->room_flags, LAWFUL) ) return 0; if ( number (0, 1) ) { weapon_count = 0; for ( tch = ch->room->people; tch; tch = tch->next_in_room ) if ( !IS_NPC(tch) && has_weapon (tch) && !get_affect (tch, MAGIC_WARNED) && !is_area_enforcer(tch) ) weapon_count++; if ( weapon_count ) { weapon_count = number (1, weapon_count); for ( tch = ch->room->people; ; tch = tch->next_in_room ) { if ( !IS_NPC(tch) && has_weapon (tch) && !get_affect (tch, MAGIC_WARNED) && !is_area_enforcer (tch) ) weapon_count--; if ( weapon_count <= 0 ) break; } /* Prevent a guard for warning him for a bit */ magic_add_affect (tch, MAGIC_WARNED, 90, 0, 0, 0, 0); name_to_ident (tch, buf); if ( ch->room->zone == 5 || ch->room->zone == 6 ) snprintf (buf2, MAX_STRING_LENGTH, "%s (with a menacing scowl) Don't let me see that weapon out again, maggot.", buf); else snprintf (buf2, MAX_STRING_LENGTH, "%s (frowning) You'll need to stow that weapon here, citizen.", buf); do_tell (ch, buf2, 0); return 1; } } return 0; } int enforcer_hood_check (CHAR_DATA *ch) { CHAR_DATA *tch; char buf [MAX_STRING_LENGTH]; int hood_count; if ( !IS_SET (ch->act, ACT_ENFORCER) || !is_area_enforcer (ch) ) return 0; if ( number (0, 1) ) { hood_count = 0; for ( tch = ch->room->people; tch; tch = tch->next_in_room ) if ( is_hooded (tch) && !get_affect (tch, MAGIC_STARED) && !is_area_enforcer (tch) ) hood_count++; if ( hood_count ) { hood_count = number (1, hood_count); for ( tch = ch->room->people; ; tch = tch->next_in_room ) { if ( is_hooded (tch) && !get_affect (tch, MAGIC_STARED) && !is_area_enforcer(tch) ) hood_count--; if ( hood_count <= 0 ) break; } /* Prevent a guard for studying him for a second */ magic_add_affect (tch, MAGIC_STARED, 10, 0, 0, 0, 0); name_to_ident (tch, buf); do_study (ch, buf, 0); return 1; } } return 0; } int mob_weather_reaction (CHAR_DATA *ch) { AFFECTED_TYPE *af; if ( !get_equip (ch, WEAR_ABOUT) ) return 0; if ( !IS_SET (get_equip(ch, WEAR_ABOUT)->obj_flags.extra_flags, ITEM_MASK) ) return 0; af = get_affect (ch, MAGIC_RAISED_HOOD); if ( ch->room->sector_type == SECT_INSIDE || weather_info[ch->room->zone].state <= CHANCE_RAIN ) { if ( af && is_hooded(ch) ) { affect_remove (ch, af); do_hood (ch, "", 0); return 1; } else return 0; } if ( get_affect (ch, MAGIC_RAISED_HOOD) ) return 0; if ( !is_hooded(ch) && ch->room->sector_type != SECT_INSIDE && weather_info[ch->room->zone].state > CHANCE_RAIN ) { if ( !af ) { CREATE (af, AFFECTED_TYPE, 1); af->type = MAGIC_RAISED_HOOD; affect_to_char (ch, af); } do_hood (ch, "", 0); return 1; } return 0; } int miscellaneous_routine (CHAR_DATA *ch) { if ( enforcer_weapon_check (ch) ) return 1; if ( enforcer_hood_check (ch) ) return 1; return 0; } int combat_routine (CHAR_DATA *ch) { return 0; } void add_attacker (CHAR_DATA *victim, CHAR_DATA *threat) { ATTACKER_DATA *tmp_att, *tmp_next; CHAR_DATA *tch; int i = 0; if ( !IS_NPC (victim) ) return; if ( !victim->attackers ) { CREATE (victim->attackers, ATTACKER_DATA, 1); victim->attackers->attacker = threat; victim->attackers->next = NULL; } else { CREATE (tmp_att, ATTACKER_DATA, 1); tmp_att->next = victim->attackers; victim->attackers = tmp_att; } for ( tmp_att = victim->attackers, i = 1; tmp_att; tmp_att = tmp_next, i++ ) { tmp_next = tmp_att->next; tch = tmp_att->attacker; if ( i > 4 || !tch ) remove_attacker (victim, tmp_att->attacker); } } void add_threat (CHAR_DATA *victim, CHAR_DATA *threat, int amount) { THREAT_DATA *tmp; if ( !IS_NPC (victim) ) return; if ( !victim->threats ) { CREATE (victim->threats, THREAT_DATA, 1); victim->threats->source = threat; victim->threats->level = amount; victim->threats->next = NULL; } else { CREATE (tmp, THREAT_DATA, 1); tmp->next = victim->threats; victim->threats = tmp; } add_attacker (victim, threat); } int charge_archer (CHAR_DATA *ch, CHAR_DATA *archer) { int dir = 0, num = 0, i = 0; ROOM_DATA *room; char buf [MAX_STRING_LENGTH]; CHAR_DATA *tch; if ( ch->in_room == archer->in_room ) { ch->speed = 0; name_to_ident (archer, buf); if ( !is_area_enforcer(ch) ) SET_BIT (ch->flags, FLAG_KILL); set_fighting (ch, archer); return 1; } dir = track (ch, archer->in_room); if ( dir == -1 ) return -1; if ( !PASSAGE (ch, dir) ) return 0; ch->speed = 4; for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( !IS_NPC (tch) || !is_brother (tch, ch) ) continue; room = vtor (PASSAGE (tch, dir)->to_room); num++; tch->speed = 4; if ( room != archer->room ) { if ( !room->dir_option[dir] ) continue; room = vtor(room->dir_option[dir]->to_room); num++; if ( room != archer->room ) num++; } for ( i = 1; i <= num; i++ ) do_move (tch, "", dir); tch->speed = 0; add_attacker (tch, archer); } room = vtor (PASSAGE (ch, dir)->to_room); num++; if ( room && room != archer->room && room->dir_option[dir] ) { room = vtor(room->dir_option[dir]->to_room); num++; if ( room != archer->room ) num++; } for ( i = 1; i <= num; i++ ) do_move (ch, "", dir); ch->speed = 0; add_attacker (ch, archer); return 1; } int morale_broken (CHAR_DATA *ch) { WOUND_DATA *wound; float damage = 0, limit = 0; bool morale_broken = FALSE, morale_held = TRUE; if ( IS_SET (ch->act, ACT_WIMPY) || IS_SET (ch->act, ACT_PREY) ) return 1; for ( wound = ch->wounds; wound; wound = wound->next ) { if ( wound ) damage += wound->damage; } damage += ch->damage; limit = ch->max_hit * .25; if ( damage < limit && IS_SET (ch->plr_flags, MORALE_BROKEN) ) REMOVE_BIT (ch->plr_flags, MORALE_BROKEN); if ( IS_SET (ch->plr_flags, MORALE_BROKEN) ) return 1; if ( IS_SET (ch->plr_flags, MORALE_HELD) ) return 0; if ( IS_SET (ch->act, ACT_ENFORCER) && IS_SET (ch->act, ACT_SENTINEL) ) { /* Mob flagged as both re-evaluates at 15%. */ if ( damage > (limit = ch->max_hit * .85) ) { if ( number (1,25) > ch->wil ) { morale_broken = TRUE; } } else morale_held = TRUE; } if ( IS_SET (ch->act, ACT_ENFORCER) || IS_SET (ch->act, ACT_SENTINEL) ) { /* Mob flagged as one re-evaluates at 20%. */ if ( damage > (limit = ch->max_hit * .8) ) { if ( number (1,25) > ch->wil ) { morale_broken = TRUE; } } else morale_held = TRUE; } if ( IS_SET (ch->act, ACT_AGGRESSIVE) ) { /* Aggro mobs cop out at 25%. */ if ( damage > (limit = ch->max_hit * .75) ) { if ( number (1,25) > ch->wil ) { morale_broken = TRUE; } } else morale_held = TRUE; } if ( damage > (limit = ch->max_hit * .60) ) { /* All others reconsider at 40%. */ if ( number (1,25) > ch->wil ) { morale_broken = TRUE; } else morale_held = TRUE; } if ( morale_broken ) { if ( IS_SET (ch->act, ACT_MOUNT) && ch->mount ) { if ( skill_use (ch->mount, SKILL_RIDE, 15) ) morale_held = TRUE; } else { SET_BIT (ch->plr_flags, MORALE_BROKEN); return 1; } } if ( morale_held ) { SET_BIT (ch->plr_flags, MORALE_HELD); return 0; } return 0; } void threat_from_char (CHAR_DATA *ch, THREAT_DATA *att) { THREAT_DATA *tempatt; if ( !ch || !att ) return; if ( ch->threats == att ) ch->threats = ch->threats->next; else { for (tempatt = ch->threats; tempatt; tempatt = tempatt->next) if (tempatt->next == att) tempatt->next = tempatt->next->next; } mem_free (att); } void remove_threat (CHAR_DATA *victim, CHAR_DATA *threat) { THREAT_DATA *tmp, *targ_threat = NULL; if ( victim->threats && victim->threats->source == threat ) { targ_threat = victim->threats; victim->threats = victim->threats->next; } else if ( victim->threats ) { for ( tmp = victim->threats; tmp; tmp = tmp->next ) { if ( tmp->next && tmp->next->source && tmp->next->source == threat ) { targ_threat = tmp->next; tmp->next = tmp->next->next; } } } if ( targ_threat ) mem_free (targ_threat); } void attacker_from_char (CHAR_DATA *ch, ATTACKER_DATA *att) { ATTACKER_DATA *tempatt; if ( !ch || !att ) return; if ( ch->attackers == att ) ch->attackers = ch->attackers->next; else { for (tempatt = ch->attackers; tempatt; tempatt = tempatt->next) if (tempatt->next == att) tempatt->next = tempatt->next->next; } mem_free (att); } void remove_attacker (CHAR_DATA *victim, CHAR_DATA *threat) { ATTACKER_DATA *tmp, *targ_att = NULL; if ( victim->attackers && victim->attackers->attacker == threat ) { targ_att = victim->attackers; victim->attackers = victim->attackers->next; } else if ( victim->attackers ) { for ( tmp = victim->attackers; tmp; tmp = tmp->next ) { if ( tmp->next && tmp->next->attacker && tmp->next->attacker == threat ) { targ_att = tmp->next; tmp->next = tmp->next->next; } } } if ( targ_att ) mem_free (targ_att); } void evade_attacker (CHAR_DATA *ch, int dir) { int roll = 0; do_set (ch, "run", 0); roll = number(1,3); if ( dir == -1 ) { if ( roll == 1 ) { if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 2 ) { if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 3 ) { if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } } else if ( dir == 0 ) { if ( roll == 1 ) { if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 2 ) { if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 3 ) { if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } } else if ( dir == 1 ) { if ( roll == 1 ) { if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 2 ) { if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 3 ) { if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } } else if ( dir == 2 ) { if ( roll == 1 ) { if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 2 ) { if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 3 ) { if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } } else if ( dir == 3 ) { if ( roll == 1 ) { if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 2 ) { if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 3 ) { if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } } else if ( dir == 4 ) { if ( roll == 1 ) { if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); } else if ( roll == 2 ) { if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } else if ( roll == 3 ) { if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_DOWN) ) do_down (ch, "", 0); } } else { if ( roll == 1 ) { if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); } else if ( roll == 2 ) { if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); } else if ( roll == 3 ) { if ( CAN_GO (ch, DIR_SOUTH) ) do_south (ch, "", 0); else if ( CAN_GO (ch, DIR_NORTH) ) do_north (ch, "", 0); else if ( CAN_GO (ch, DIR_EAST) ) do_east (ch, "", 0); else if ( CAN_GO (ch, DIR_WEST) ) do_west (ch, "", 0); else if ( CAN_GO (ch, DIR_UP) ) do_up (ch, "", 0); } } } OBJ_DATA *get_bow (CHAR_DATA *ch) { OBJ_DATA *obj; if ( ch->right_hand && GET_ITEM_TYPE (ch->right_hand) == ITEM_WEAPON ) { if ( ch->right_hand->o.weapon.use_skill == SKILL_LONGBOW || ch->right_hand->o.weapon.use_skill == SKILL_SHORTBOW || ch->right_hand->o.weapon.use_skill == SKILL_CROSSBOW ) return ch->right_hand; } if ( ch->left_hand && GET_ITEM_TYPE (ch->left_hand) == ITEM_WEAPON ) { if ( ch->left_hand->o.weapon.use_skill == SKILL_LONGBOW || ch->left_hand->o.weapon.use_skill == SKILL_SHORTBOW || ch->left_hand->o.weapon.use_skill == SKILL_CROSSBOW ) return ch->left_hand; } for ( obj = ch->equip; obj; obj = obj->next_content ) { if ( GET_ITEM_TYPE (obj) != ITEM_WEAPON ) continue; if ( obj->o.weapon.use_skill == SKILL_LONGBOW || obj->o.weapon.use_skill == SKILL_SHORTBOW || obj->o.weapon.use_skill == SKILL_CROSSBOW ) return obj; } do_set (ch, "walk", 0); return NULL; } int is_bow (OBJ_DATA *bow) { if ( bow->o.weapon.use_skill != SKILL_LONGBOW && bow->o.weapon.use_skill != SKILL_SHORTBOW && bow->o.weapon.use_skill != SKILL_CROSSBOW ) return 0; return 1; } void ready_melee_weapons (CHAR_DATA *ch) { OBJ_DATA *obj; char buf [MAX_STRING_LENGTH]; if ( ch->right_hand && GET_ITEM_TYPE (ch->right_hand) == ITEM_WEAPON && !is_bow (ch->right_hand) ) { (void)one_argument (ch->right_hand->name, buf); do_wield (ch, buf, 0); } if ( ch->left_hand && GET_ITEM_TYPE (ch->left_hand) == ITEM_WEAPON && !is_bow (ch->left_hand) ) { (void)one_argument (ch->left_hand->name, buf); do_wield (ch, buf, 0); } if ( ch->right_hand && GET_ITEM_TYPE(ch->right_hand) != ITEM_WEAPON ) { if ( GET_ITEM_TYPE (ch->right_hand) == ITEM_KEY ) do_switch (ch, "", 0); else do_drop (ch, "all", 0); } unready_bow (ch); for ( obj = ch->equip; obj; obj = obj->next_content ) { if ( GET_ITEM_TYPE(obj) == ITEM_SHEATH ) { if ( obj->contains && GET_ITEM_TYPE (obj->contains) == ITEM_WEAPON && !is_bow(obj->contains) ) { (void)one_argument (obj->contains->name, buf); do_draw (ch, buf, 0); break; } } } do_remove (ch, "shield", 0); for ( obj = ch->equip; obj; obj = obj->next_content ) { if ( GET_ITEM_TYPE(obj) == ITEM_SHEATH ) { if ( obj->contains && GET_ITEM_TYPE (obj->contains) == ITEM_WEAPON && !is_bow(obj->contains) ) { (void)one_argument (obj->contains->name, buf); do_draw (ch, buf, 0); break; } } } } void unready_weapons (CHAR_DATA *ch) { char buf [MAX_STRING_LENGTH]; if ( !IS_NPC (ch) || ch->desc ) return; if ( ch->right_hand && (GET_ITEM_TYPE (ch->right_hand) == ITEM_WEAPON || GET_ITEM_TYPE (ch->right_hand) == ITEM_SHIELD) ) { (void)one_argument (ch->right_hand->name, buf); do_sheathe (ch, buf, 0); do_wear (ch, buf, 0); } if ( ch->left_hand && (GET_ITEM_TYPE (ch->left_hand) == ITEM_WEAPON || GET_ITEM_TYPE (ch->left_hand) == ITEM_SHIELD) ) { (void)one_argument (ch->left_hand->name, buf); do_sheathe (ch, buf, 0); do_wear (ch, buf, 0); } } void unready_bow (CHAR_DATA *ch) { char buf [MAX_STRING_LENGTH]; OBJ_DATA *bow; bow = get_equip (ch, WEAR_BOTH); if ( !bow ) bow = get_bow (ch); if ( !bow ) return; if ( GET_ITEM_TYPE(bow) != ITEM_WEAPON ) return; if ( !is_bow (bow) ) return; do_unload (ch, "", 0); (void)one_argument (bow->name, buf); do_wear (ch, buf, 0); } void ready_bow (CHAR_DATA *ch) { OBJ_DATA *bow; bow = get_equip (ch, WEAR_BOTH); if ( !bow ) { bow = get_bow (ch); if ( !bow ) return; do_remove (ch, bow->name, 0); do_wield (ch, bow->name, 0); } if ( !bow->loaded ) do_load (ch, "", 0); } int has_ammunition (CHAR_DATA *ch) { OBJ_DATA *bow, *quiver, *ammo; int i; bow = get_bow (ch); if ( !bow ) return 0; for ( i = 0; i < MAX_WEAR; i++ ) { if ( !(quiver = get_equip (ch, i)) ) continue; if ( GET_ITEM_TYPE (quiver) != ITEM_QUIVER ) continue; for ( ammo = quiver->contains; ammo; ammo = ammo->next_content ) { if ( bow->o.weapon.use_skill == SKILL_LONGBOW || bow->o.weapon.use_skill == SKILL_SHORTBOW ) { if ( !cmp_strn (ammo->name, "arrow", 5) ) { return 1; } } if ( bow->o.weapon.use_skill == SKILL_CROSSBOW ) { if ( !cmp_strn (ammo->name, "bolt", 4) ) { return 1; } } } } return 0; } int is_archer (CHAR_DATA *ch) { OBJ_DATA *bow; bow = get_bow (ch); if ( !bow ) return 0; if ( !has_ammunition (ch) ) return 0; if ( !ch->skills [bow->o.weapon.use_skill] ) return 0; if ( bow->o.od.value[1] == 0 ) return 3; /* Longbow; range of 3. */ if ( bow->o.od.value[1] == 1 || bow->o.od.value[1] == 2 ) return 2; /* Shortbow and crossbow. */ else return 1; /* Sling, eventually. */ } CHAR_DATA *acquire_archer_target (CHAR_DATA *ch, int i) { CHAR_DATA *tch; ROOM_DATA *troom; int j = 0, range = 0; if ( !is_archer (ch) ) return NULL; troom = ch->room; if ( !troom->dir_option[i] ) return NULL; troom = vtor (troom->dir_option[i]->to_room); if ( (range = is_archer (ch)) ) { for ( j = 1; j <= range; j++ ) { if ( IS_SET (troom->room_flags, INDOORS) ) continue; if ( IS_SET (troom->room_flags, STIFLING_FOG) ) return NULL; for ( tch = troom->people; tch; tch = tch->next_in_room ) { if ( ch->room == tch->room && CAN_SEE (tch, ch) && CAN_SEE (ch, tch) ) continue; if ( would_attack (ch, tch) || would_attack (tch, ch) ) { if ( !CAN_SEE (ch, tch) ) continue; if ( !skill_use (ch, SKILL_SCAN, 0) ) continue; if ( IS_SUBDUEE (tch) && (!IS_SET (ch->act, ACT_AGGRESSIVE) || is_brother (tch->subdue, ch)) ) continue; if ( tch->fighting ) { if ( is_brother (ch, tch->fighting) || (!would_attack (ch, tch->fighting) && !would_attack (tch->fighting, ch)) ) continue; } return tch; } } if ( !troom->dir_option[i] ) break; troom = vtor(troom->dir_option[i]->to_room); } } else return NULL; return NULL; } CHAR_DATA *acquire_distant_target (CHAR_DATA *ch, int i) { CHAR_DATA *tch; ROOM_DATA *troom; int j = 0, penalty = 0; troom = ch->room; if ( IS_SET (troom->room_flags, STIFLING_FOG) ) return NULL; if ( !troom->dir_option[i] ) return NULL; if ( IS_SET (troom->dir_option[i]->exit_info, PASSAGE_CLOSED) ) return NULL; troom = vtor (troom->dir_option[i]->to_room); if ( !troom || IS_SET (troom->room_flags, NO_MOB) ) return NULL; if ( (ch->mob->noaccess_flags & troom->room_flags) ) return NULL; for ( j = 1; j <= 3; j++ ) { if ( IS_SET (troom->room_flags, STIFLING_FOG) ) return NULL; for ( tch = troom->people; tch; tch = tch->next_in_room ) { if ( j == 2 ) penalty = 10; else if ( j == 3 ) penalty = 15; if ( would_attack (ch, tch) ) { if ( !CAN_SEE (ch, tch) ) continue; if ( !skill_use (ch, SKILL_SCAN, penalty) ) continue; if ( IS_SUBDUEE (tch) && (!IS_SET (ch->act, ACT_AGGRESSIVE) || is_brother (tch->subdue, ch)) ) continue; return tch; } } if ( !troom->dir_option[i] ) break; if ( IS_SET (troom->dir_option[i]->exit_info, PASSAGE_CLOSED) ) break; troom = vtor(troom->dir_option[i]->to_room); if ( !troom || IS_SET (troom->room_flags, NO_MOB) ) return NULL; if ( (ch->mob->noaccess_flags & troom->room_flags) ) return NULL; } return NULL; } int evaluate_threats (CHAR_DATA *ch) { THREAT_DATA *tmp; ATTACKER_DATA *tmp_att; WOUND_DATA *wound; CHAR_DATA *tch; int i = 0; int dir = 0; float damage = 0; bool safe = TRUE; bool bleeding = FALSE; if ( ch->fighting ) return 0; for ( tmp = ch->threats; tmp; tmp = tmp->next ) { if ( tmp->level <= 0 || !tmp->source ) { remove_threat (ch, tmp->source); return 1; } dir = track (ch, tmp->source->in_room); if ( morale_broken (ch) && CAN_SEE (tmp->source, ch) ) { if ( GET_POS (ch) != POSITION_STANDING ) do_stand (ch, "", 0); ch->speed = 4; evade_attacker (ch, dir); if ( tmp->source->in_room != ch->in_room ) { if ( ch->delay <= 0 && IS_SET (ch->affected_by, AFF_HIDE) && !get_affect (ch, MAGIC_HIDDEN) ) { do_hide (ch, "", 0); return 1; } tmp->level -= 1; } return 1; } } if ( ch->delay <= 0 && IS_SET (ch->affected_by, AFF_HIDE) && !get_affect (ch, MAGIC_HIDDEN) ) { do_hide (ch, "", 0); return 1; } for ( tmp_att = ch->attackers; tmp_att; tmp_att = tmp_att->next ) { if ( tmp_att && tmp_att->attacker && tmp_att->attacker->in_room && ch->in_room == tmp_att->attacker->in_room && CAN_SEE (ch, tmp_att->attacker) ) { if ( !GET_FLAG (tmp_att->attacker, FLAG_SUBDUEE) && GET_POS (tmp_att->attacker) != POSITION_UNCONSCIOUS ) safe = FALSE; if ( morale_broken (ch) ) { if ( GET_POS (ch) != POSITION_STANDING ) do_stand (ch, "", 0); ch->speed = 4; for ( i = 0; i <= 6; i++ ) { if ( CAN_GO (ch, i) ) { do_move (ch, "", i); return 1; } } } } for ( i = 0; i < 6; i++ ) { if ( PASSAGE (ch, i) && CAN_SEE (ch, tmp_att->attacker) && PASSAGE (ch, i)->to_room == tmp_att->attacker->in_room ) safe = FALSE; } } for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( would_attack (ch, tch) || would_attack (tch, ch) ) safe = FALSE; } for ( wound = ch->wounds; wound; wound = wound->next ) { if ( wound->bleeding ) bleeding = TRUE; damage += wound->damage; } damage += ch->damage; if ( safe && bleeding && !IS_SET (ch->act, ACT_NOBIND) ) { do_bind (ch, "", 0); return 1; } for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( !is_brother (ch, tch) ) continue; for ( wound = tch->wounds; wound; wound = wound->next ) if ( wound->bleeding ) bleeding = TRUE; if ( bleeding && !AWAKE (tch) ) { do_bind (ch, tch->tname, 0); return 1; } } return 0; } int survival_routine (CHAR_DATA *ch) { if ( evaluate_threats (ch) ) return 1; else return 0; } int predatory_mobile (CHAR_DATA *ch) { ROOM_DATA *troom; TRACK_DATA *track; if ( !ch->room->tracks ) return 0; if ( is_dark (ch->room) && IS_MORTAL (ch) && !get_affect (ch, MAGIC_AFFECT_INFRAVISION) && !IS_SET (ch->affected_by, AFF_INFRAVIS) ) { return 0; } for ( track = ch->room->tracks; track; track = track->next ) { if ( track->hours_passed > 0 ) continue; if ( !skill_use (ch, SKILL_TRACKING, 0) ) continue; if ( !ch->room->dir_option[track->to_dir] ) continue; if ( !(troom = vtor(ch->room->dir_option[track->to_dir]->to_room)) ) continue; if ( (ch->mob->noaccess_flags & troom->room_flags) ) return 0; if ( IS_SET (troom->room_flags, NO_MOB) ) continue; if ( track->to_dir == ch->from_dir ) continue; } return 0; } int target_acquisition (CHAR_DATA *ch) { CHAR_DATA *tch = NULL; OBJ_DATA *bow = NULL; char buf [MAX_STRING_LENGTH] = {'\0'}; int i = 0; if ( ch->fighting ) return 1; if ( ch->aiming_at ) return 1; for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( morale_broken (ch) ) break; if ( !CAN_SEE (ch, tch) ) continue; if ( IS_SUBDUEE (tch) ) continue; if ( would_attack (ch, tch) ) { if ( IS_SET (ch->act, ACT_AGGRESSIVE) || AWAKE(tch) ) { add_threat (ch, tch, 3); if ( IS_SET (ch->act, ACT_AGGRESSIVE) ) SET_BIT (ch->flags, FLAG_KILL); set_fighting (ch, tch); return 1; } } if ( tch->fighting && !tch->fighting->deleted && is_brother (ch, tch) && IS_SET (ch->act, ACT_ENFORCER) && !is_brother (ch, tch->fighting) ) { if ( IS_SET (ch->act, ACT_AGGRESSIVE) || AWAKE(tch) ) { add_threat (ch, tch->fighting, 3); if ( IS_SET (ch->act, ACT_AGGRESSIVE) ) SET_BIT (ch->flags, FLAG_KILL); set_fighting (ch, tch->fighting); return 1; } } } if ( is_archer (ch) ) { for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( would_attack (ch, tch) || would_attack (tch, ch) ) { if ( CAN_SEE (ch, tch) ) { if ( IS_SUBDUEE (tch) && (!IS_SET (ch->act, ACT_AGGRESSIVE) || is_brother (tch->subdue, ch)) ) continue; if ( is_area_enforcer (ch) && is_wanted_in_area (tch) ) /* Enforcers should rush in with melee weapons to subdue criminals, not shoot them full of arrows. */ continue; if ( tch->fighting ) { if ( is_brother (ch, tch) || is_brother (ch, tch->fighting) ) continue; } break; } } } if ( !tch ) { for ( i = 0; i < 6; i++ ) if ( (tch = acquire_archer_target (ch, i)) ) break; if ( is_area_enforcer (ch) && is_wanted_in_area (tch) ) tch = NULL; } if ( tch ) { bow = get_bow (ch); if ( bow && bow->loaded ) { *buf = '\0'; if ( tch->in_room != ch->in_room ) { if ( !IS_NPC (tch) ) snprintf (buf, MAX_STRING_LENGTH, "%s %s", dirs[i], tch->tname); else snprintf (buf, MAX_STRING_LENGTH, "%s %s", dirs[i], tch->name); } else{ snprintf (buf, MAX_STRING_LENGTH, "%s", tch->tname); } ready_bow (ch); do_aim (ch, buf, 0); return 1; } else if ( bow && !bow->loaded ) { ready_bow (ch); return 1; } } } /* end if ( is_archer (ch) ) */ if ( (IS_SET (ch->act, ACT_AGGRESSIVE) || IS_SET (ch->act, ACT_ENFORCER)) && !IS_SET (ch->act, ACT_SENTINEL) && !morale_broken (ch) ) { for ( i = 0; i < 6; i++ ) { if ( (tch = acquire_distant_target (ch, i)) ) { snprintf (buf, MAX_STRING_LENGTH, "%d", tch->in_room); ch->speed = tch->speed + 2; ch->speed = MIN (ch->speed, 4); do_track (ch, buf, 0); return 1; } } } if ( IS_SET (ch->act, ACT_AGGRESSIVE) && !IS_SET (ch->act, ACT_SENTINEL) && real_skill (ch, SKILL_TRACKING) && !morale_broken (ch) ) { if ( predatory_mobile (ch) ) return 1; } return 0; } void mobile_routines (int pulse) { int zone, dir = 0, jailer = 0; CHAR_DATA *ch, *tch; ROOM_DATA *room; char buf[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; for ( ch = character_list; ch; ch = ch->next ) { if ( ch->deleted ) continue; if ( IS_SET(ch->flags, FLAG_BINDING) ) continue; if ( ch->desc ) continue; if ( !ch->room ) continue; if ( ch->alarm > 0 ) { ch->alarm -= 2; if ( ch->alarm <= 0 && !trigger (ch, "", TRIG_ALARM) ) continue; } if ( ch->trigger_delay ) continue; if ( GET_FLAG (ch, FLAG_LEAVING) ) continue; /* close the door of the room we are coming from */ if ( GET_FLAG (ch, FLAG_ENTERING) ) { if ( PASSAGE(ch,ch->from_dir) && PASSAGE(ch,ch->from_dir)->exit_info == PASSAGE_ISDOOR && !ch->following ) { (void)one_argument (PASSAGE(ch,ch->from_dir)->keyword, buf2); snprintf (buf, MAX_STRING_LENGTH, "%s %s", buf2, dirs [ch->from_dir]); do_close (ch, buf, 0); } continue; } if ( ch->mount && (GET_FLAG (ch->mount, FLAG_ENTERING) || GET_FLAG (ch->mount, FLAG_LEAVING)) ) continue; if ( GET_FLAG (ch, FLAG_FLEE) ) continue; if ( ch->delay ) continue; if ( ch->aiming_at ) continue; if ( IS_SUBDUEE (ch) ) continue; room = ch->room; zone = room->zone; if ( !IS_NPC (ch) || IS_FROZEN (zone) || !AWAKE (ch) ) continue; if ( !trigger (ch, "", TRIG_MOBACT) ) continue; for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( enforcer (ch, tch, 1, 0) > 0 ) continue; } if ( IS_SET(ch->act, ACT_JAILER) && IS_SUBDUER (ch) ) { for ( dir=0; dir<=5; dir++ ) { if ( ch->room->dir_option[dir] ) { if ( (ch->room->dir_option[dir]->to_room == ch->cell_1) || (ch->room->dir_option[dir]->to_room == ch->cell_2) || (ch->room->dir_option[dir]->to_room == ch->cell_3)) { jailer = 1; } if ( jailer ){ jailer_func (ch); } } } } if ( IS_SUBDUER (ch) ) { common_guard (ch); continue; } if ( survival_routine (ch) ) continue; if ( target_acquisition (ch) ) continue; if ( miscellaneous_routine (ch) ) continue; if ( (rand()%40 == 0) && mob_weather_reaction (ch) ) continue; if ( !((pulse + 1) % PULSE_SMART_MOBS) && mob_wander (ch) ) continue; } /* for */ } int is_threat (CHAR_DATA *ch, CHAR_DATA *tch) { THREAT_DATA *tmp; ATTACKER_DATA *tmp_att; for ( tmp = ch->threats; tmp; tmp = tmp->next ) if ( tmp->source == tch ) return 1; for ( tmp_att = ch->attackers; tmp_att; tmp_att = tmp_att->next ) if ( tmp_att->attacker == tch ) return 1; return 0; } int would_attack (CHAR_DATA *ch, CHAR_DATA *tch) { if ( ch == tch ) return 0; if ( IS_SET (tch->act, ACT_VEHICLE) ) return 0; if ( IS_NPC (ch) && IS_NPC (tch) && IS_SET (ch->act, ACT_WILDLIFE) && IS_SET (tch->act, ACT_WILDLIFE) ) return 0; /* Wrestling */ if ( tch->fighting && GET_FLAG (tch, FLAG_SUBDUING) ) return 0; if ( IS_SUBDUEE (tch) ) return 0; if ( IS_SET (ch->act, ACT_ENFORCER) ) { if ( !is_area_enforcer (ch) ) /** do nothing in this case**/; else if ( IS_SUBDUEE (tch) ) return 0; else if ( !is_hooded (tch) && get_affect (tch, MAGIC_CRIM_BASE + ch->room->zone) ) return 1; else if ( is_hooded (tch) && get_affect (tch, MAGIC_CRIM_HOODED + ch->room->zone) ) return 1; else if ( ch->mob->zone == 1 ) { if ( get_affect (tch, MAGIC_CRIM_HOODED + 3) ) return 1; if ( !is_hooded (tch) && get_affect (tch, MAGIC_CRIM_BASE + 3) ) return 1; } } if (CAN_SEE (ch, tch) && IS_SET (ch->act, ACT_AGGRESSIVE) && (!IS_SET (ch->act, ACT_WIMPY) || !AWAKE (tch)) && !is_brother (ch, tch)) return 1; if ( is_threat (ch, tch) ) return 1; return 0; } void do_would (CHAR_DATA *ch, char *argument, int cmd) { CHAR_DATA *tch; char buf [MAX_STRING_LENGTH]; argument = one_argument (argument, buf); if ( !*buf || *buf == '?' ) { send_to_char ("Would determines if a mob would attack you.\n", ch); return; } if ( (tch = get_char_room (buf, ch->in_room)) ) { if ( would_attack (tch, ch) ) act ("$n would attack $N.", FALSE, tch, 0, ch, TO_VICT); if ( would_attack (ch, tch) ) act ("You would attack $N.", FALSE, ch, 0, tch, TO_CHAR); } else send_to_char ("Couldn't find that mob.\n", ch); } void activate_resets (CHAR_DATA *ch) { }