TbBool attempt_job_sleep_in_lair_near_pos(struct Thing *creatng, MapSubtlCoord stl_x, MapSubtlCoord stl_y, CreatureJob new_job) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); SYNCDBG(16,"Starting for %s (owner %d) and job %s",thing_model_name(creatng),(int)creatng->owner,creature_job_code_name(new_job)); struct Room *room; room = subtile_room_get(stl_x, stl_y); if (get_arrive_at_state_for_job(new_job) == CrSt_Unused) { ERRORLOG("No arrive at state for job %s in %s room",creature_job_code_name(new_job),room_code_name(room->kind)); return false; } cctrl->slap_turns = 0; cctrl->max_speed = calculate_correct_creature_maxspeed(creatng); if (creature_has_lair_room(creatng) && (room->index == cctrl->lair_room_id)) { if (creature_move_to_home_lair(creatng)) { creatng->continue_state = CrSt_CreatureGoingHomeToSleep; return 1; } } struct Coord3d pos; if (find_first_valid_position_for_thing_in_room(creatng, room, &pos) && setup_person_move_to_coord(creatng, &pos, NavRtF_Default)) { creatng->continue_state = CrSt_CreatureChangeLair; cctrl->target_room_id = room->index; return 1; } return 0; }
TbBool good_setup_loot_research_room(struct Thing *thing, long dngn_id) { struct CreatureControl *cctrl; struct Room *room; room = find_random_room_creature_can_navigate_to(thing, dngn_id, RoK_LIBRARY, NavRtF_Default); if (room_is_invalid(room)) { SYNCDBG(6,"No accessible player %d library found",(int)dngn_id); return false; } struct Coord3d pos; if (!find_random_valid_position_for_thing_in_room(thing, room, &pos)) { SYNCDBG(6,"No position for %s index %d in %s owned by player %d", thing_model_name(thing),(int)thing->index,room_code_name(room->kind),(int)room->owner); return false; } if (!setup_person_move_to_coord(thing, &pos, NavRtF_Default)) { SYNCDBG(6,"Cannot setup move %s index %d to %s owned by player %d", thing_model_name(thing),(int)thing->index,room_code_name(room->kind),(int)room->owner); return false; } cctrl = creature_control_get_from_thing(thing); thing->continue_state = CrSt_CreatureSearchForSpellToStealInRoom; cctrl->target_room_id = room->index; return true; }
TbBool attempt_job_work_in_room_for_player(struct Thing *creatng, PlayerNumber plyr_idx, CreatureJob new_job) { struct Coord3d pos; struct Room *room; RoomKind rkind; rkind = get_room_for_job(new_job); SYNCDBG(6,"Starting for %s (owner %d) and job %s in %s room",thing_model_name(creatng),(int)creatng->owner,creature_job_code_name(new_job),room_code_name(rkind)); if ((get_flags_for_job(new_job) & JoKF_NeedsCapacity) != 0) { room = find_nearest_room_for_thing_with_spare_capacity(creatng, creatng->owner, rkind, NavRtF_Default, 1); } else { room = find_nearest_room_for_thing(creatng, creatng->owner, rkind, NavRtF_Default); } if (room_is_invalid(room)) { return false; } if (!find_random_valid_position_for_thing_in_room(creatng, room, &pos)) { return false; } if (get_arrive_at_state_for_job(new_job) == CrSt_Unused) { ERRORLOG("No arrive at state for job %s in %s room",creature_job_code_name(new_job),room_code_name(room->kind)); return false; } if (!setup_person_move_to_coord(creatng, &pos, NavRtF_Default)) { return false; } struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); creatng->continue_state = get_arrive_at_state_for_job(new_job); cctrl->target_room_id = room->index; return true; }
TbBool creature_move_to_home_lair(struct Thing *creatng) { if (!creature_has_lair_room(creatng)) { return false; } struct CreatureControl *cctrl; struct Thing *lairtng; cctrl = creature_control_get_from_thing(creatng); lairtng = thing_get(cctrl->lairtng_idx); if (thing_is_invalid(lairtng)) { return false; } return setup_person_move_to_coord(creatng, &lairtng->mappos, NavRtF_Default); }
TbBool attempt_anger_job_damage_walls(struct Thing *creatng) { if (!can_change_from_state_to(creatng, creatng->active_state, CrSt_CreatureDamageWalls)) { return false; } struct Coord3d pos; if (!get_random_position_in_dungeon_for_creature(creatng->owner, 1, creatng, &pos)) { return false; } if (!external_set_thing_state(creatng, CrSt_CreatureAttemptToDamageWalls)) { return false; } setup_person_move_to_coord(creatng, &pos, NavRtF_Default); creatng->continue_state = CrSt_CreatureAttemptToDamageWalls; return true; }
TbBool good_setup_wander_to_exit(struct Thing *creatng) { struct Thing *gatetng; SYNCDBG(7,"Starting"); gatetng = find_hero_door_hero_can_navigate_to(creatng); if (thing_is_invalid(gatetng)) { SYNCLOG("Can't find any exit gate for hero %s.",thing_model_name(creatng)); return false; } if (!setup_person_move_to_coord(creatng, &gatetng->mappos, NavRtF_Default)) { WARNLOG("Hero %s index %d can't move to exit gate at (%d,%d).",thing_model_name(creatng), (int)gatetng->index, (int)gatetng->mappos.x.stl.num, (int)gatetng->mappos.y.stl.num); return false; } creatng->continue_state = CrSt_GoodLeaveThroughExitDoor; return true; }
TbBool process_job_causes_going_postal(struct Thing *creatng, struct Room *room, CreatureJob going_postal_job) { struct CreatureControl *cctrl; struct CreatureStats *crstat; cctrl = creature_control_get_from_thing(creatng); crstat = creature_stats_get_from_thing(creatng); CrInstance inst_use; inst_use = get_best_quick_range_instance_to_use(creatng); if (inst_use <= 0) { return false; } // Find a target unsigned long combt_dist; struct Thing *combt_thing; combt_dist = LONG_MAX; combt_thing = INVALID_THING; if (find_combat_target_passing_by_room_but_having_unrelated_job(creatng, going_postal_job, room, &combt_dist, &combt_thing)) { struct CreatureControl *combctrl; set_creature_instance(creatng, inst_use, 0, combt_thing->index, 0); external_set_thing_state(combt_thing, CrSt_CreatureEvacuateRoom); combctrl = creature_control_get_from_thing(combt_thing); combctrl->word_9A = room->index; anger_apply_anger_to_creature(creatng, crstat->annoy_going_postal, AngR_Other, 1); return true; } if (thing_is_invalid(combt_thing)) { return false; } if (!setup_person_move_to_coord(creatng, &combt_thing->mappos, NavRtF_Default)) { return false; } //TODO this is weak - going postal may be used in other rooms creatng->continue_state = CrSt_Researching; cctrl->field_82 = 0; cctrl->byte_9A = 3; return true; }
short good_returns_to_start(struct Thing *thing) { struct Thing *heartng; // Debug code to find incorrect states SYNCDBG(7,"Starting"); if (!is_hero_thing(thing)) { ERRORLOG("Non hero thing %ld, %s, owner %ld - reset",(long)thing->index,thing_model_name(thing),(long)thing->owner); set_start_state(thing); erstat_inc(ESE_BadCreatrState); return 0; } //return _DK_good_returns_to_start(thing); heartng = get_player_soul_container(thing->owner); TRACE_THING(heartng); //TODO CREATURE_AI Heroes don't usually have hearts; maybe they should also go back to hero gates, or any room? if (!setup_person_move_to_coord(thing, &heartng->mappos, NavRtF_Default)) { return 0; } thing->continue_state = CrSt_GoodBackAtStart; return 1; }
short creature_being_scavenged(struct Thing *creatng) { //return _DK_creature_being_scavenged(creatng); struct Thing *fellowtng; struct Dungeon *dungeon; SYNCDBG(8,"Starting"); //return _DK_make_all_players_creatures_angry(plyr_idx); dungeon = get_players_num_dungeon(creatng->owner); fellowtng = INVALID_THING; if (dungeon->num_active_creatrs <= 1) { SYNCDBG(19,"No other creatures"); return 0; } int n; n = ACTION_RANDOM(dungeon->num_active_creatrs-1); unsigned long k; int i; k = 0; i = dungeon->creatr_list_start; while (i != 0) { struct Thing *thing; thing = thing_get(i); TRACE_THING(thing); struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); if (thing_is_invalid(thing) || creature_control_invalid(cctrl)) { ERRORLOG("Jump to invalid creature detected"); break; } i = cctrl->players_next_creature_idx; // Thing list loop body if ((n <= 0) && (thing->index != creatng->index)) { fellowtng = thing; break; } n--; // Thing list loop body ends k++; if (k > CREATURES_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); break; } } if (thing_is_invalid(fellowtng)) { SYNCDBG(19,"Cannot get creature"); return 0; } if (setup_person_move_to_coord(creatng, &fellowtng->mappos, NavRtF_Default) <= 0) { SYNCDBG(19,"Cannot move to coord"); return 0; } creatng->continue_state = CrSt_CreatureBeingScavenged; if (!S3DEmitterIsPlayingSample(creatng->snd_emitter_id, 156, 0)) thing_play_sample(creatng, 156, NORMAL_PITCH, 0, 3, 1, 2, FULL_LOUDNESS); SYNCDBG(19,"Finished"); return 1; }
TbBool wander_to_specific_possible_target_in_list(long first_thing_idx, struct Thing *wanderer, long specific_target) { struct CreatureControl *cctrl; struct Thing *thing; long target_match; long matched_thing_idx; unsigned long k; long i; target_match = specific_target; // Find the target k = 0; i = first_thing_idx; matched_thing_idx = i; while (i != 0) { thing = thing_get(i); TRACE_THING(thing); cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) { ERRORLOG("Jump to invalid creature detected"); break; } i = cctrl->players_next_creature_idx; // Thing list loop body if (!thing_is_picked_up(thing) && !creature_is_kept_in_custody_by_enemy(thing)) { // If it's not the one we want, continue sweeping if (target_match > 0) { target_match--; // Store the last unmatched thing, so we know where to stop when wrapped matched_thing_idx = thing->index; } else // If it is the one, try moving to it if (setup_person_move_to_coord(wanderer, &thing->mappos, NavRtF_Default)) { SYNCDBG(8,"The %s wanders towards %s",thing_model_name(wanderer),thing_model_name(thing)); return true; } // If we've got the right creature, but moving failed for some reason, try next one. } // Wrap to first thing if reached end of list. if (i == 0) { i = first_thing_idx; if (target_match != 0) WARNLOG("Wrapping to start of the list shouldn't occur before target_match reaches 0!"); } // When wrapped, process things only to the start index if (i == matched_thing_idx) break; // Thing list loop body ends k++; if (k > CREATURES_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); break; } } return false; }