void increase_level(struct PlayerInfo *player) { struct Dungeon *dungeon; struct CreatureControl *cctrl; struct Thing *thing; unsigned long k; int i; dungeon = get_dungeon(player->id_number); // Increase level of normal creatures k = 0; i = dungeon->creatr_list_start; while (i != 0) { thing = thing_get(i); 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 creature_increase_level(thing); // Thing list loop body ends k++; if (k > CREATURES_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); erstat_inc(ESE_InfChainTngPerOwner); break; } } // Increase level of special workers k = 0; i = dungeon->digger_list_start; while (i != 0) { thing = thing_get(i); 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 creature_increase_level(thing); // Thing list loop body ends k++; if (k > CREATURES_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); erstat_inc(ESE_InfChainTngPerOwner); break; } } }
TbBool setup_person_move_close_to_position(struct Thing *thing, MapSubtlCoord stl_x, MapSubtlCoord stl_y, NaviRouteFlags flags) { struct CreatureControl *cctrl; struct Coord3d trgpos; struct Coord3d navpos; SYNCDBG(18,"Moving %s index %d to (%d,%d)",thing_model_name(thing),(int)thing->index,(int)stl_x,(int)stl_y); trgpos.x.val = subtile_coord_center(stl_x); trgpos.y.val = subtile_coord_center(stl_y); trgpos.z.val = thing->mappos.z.val; cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) { WARNLOG("Tried to move invalid creature to (%d,%d)",(int)stl_x,(int)stl_y); return false; } get_nearest_navigable_point_for_thing(thing, &trgpos, &navpos, flags); if (!creature_can_navigate_to_with_storage(thing, &navpos, flags)) { SYNCDBG(19,"The %s cannot reach subtile (%d,%d)",thing_model_name(thing),(int)stl_x,(int)stl_y); return false; } cctrl->move_flags = flags; internal_set_thing_state(thing, CrSt_MoveToPosition); cctrl->moveto_pos.x.val = navpos.x.val; cctrl->moveto_pos.y.val = navpos.y.val; cctrl->moveto_pos.z.val = navpos.z.val; return true; }
TbBool setup_person_move_to_position_f(struct Thing *thing, MapSubtlCoord stl_x, MapSubtlCoord stl_y, NaviRouteFlags flags, const char *func_name) { struct CreatureControl *cctrl; struct Coord3d locpos; SYNCDBG(18,"%s: Moving %s index %d to (%d,%d)",func_name,thing_model_name(thing),(int)thing->index,(int)stl_x,(int)stl_y); TRACE_THING(thing); locpos.x.val = subtile_coord_center(stl_x); locpos.y.val = subtile_coord_center(stl_y); locpos.z.val = thing->mappos.z.val; locpos.z.val = get_thing_height_at(thing, &locpos); cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) { WARNLOG("%s: Tried to move invalid creature to (%d,%d)",func_name,(int)stl_x,(int)stl_y); return false; } if (thing_in_wall_at(thing, &locpos)) { SYNCDBG(16,"%s: The %s would be trapped in wall at (%d,%d)",func_name,thing_model_name(thing),(int)stl_x,(int)stl_y); return false; } if (!creature_can_navigate_to_with_storage_f(thing, &locpos, flags, func_name)) { SYNCDBG(19,"%s: The %s cannot reach subtile (%d,%d)",func_name,thing_model_name(thing),(int)stl_x,(int)stl_y); return false; } cctrl->move_flags = flags; internal_set_thing_state(thing, CrSt_MoveToPosition); cctrl->moveto_pos.x.val = locpos.x.val; cctrl->moveto_pos.y.val = locpos.y.val; cctrl->moveto_pos.z.val = locpos.z.val; SYNCDBG(19,"%s: Done",func_name); return true; }
TbBool creature_control_exists(const struct CreatureControl *cctrl) { if (creature_control_invalid(cctrl)) return false; if ((cctrl->flgfield_1 & CCFlg_Exists) == 0) return false; return true; }
TbBool creature_instance_is_available(const struct Thing *thing, CrInstance inst_id) { struct CreatureControl *cctrl; TRACE_THING(thing); cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) return false; return cctrl->instance_available[inst_id]; }
void delete_all_control_structures(void) { long i; struct CreatureControl *cctrl; for (i=1; i < CREATURES_COUNT; i++) { cctrl = creature_control_get(i); if (!creature_control_invalid(cctrl)) { if ((cctrl->flgfield_1 & CCFlg_Exists) != 0) delete_control_structure(cctrl); } } }
TbBool set_creature_assigned_job(struct Thing *thing, CreatureJob new_job) { struct CreatureControl *cctrl; TRACE_THING(thing); cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) { ERRORLOG("The %s index %d has invalid control",thing_model_name(thing),(int)thing->index); return false; } cctrl->job_assigned = new_job; SYNCLOG("Assigned job %s for %s index %d owner %d",creature_job_code_name(new_job),thing_model_name(thing),(int)thing->index,(int)thing->owner); return true; }
long i_can_allocate_free_control_structure(void) { struct CreatureControl *cctrl; long i; for (i=1; i < CREATURES_COUNT; i++) { cctrl = game.persons.cctrl_lookup[i]; if (!creature_control_invalid(cctrl)) { if ((cctrl->flgfield_1 & CCFlg_Exists) == 0) return i; } } return 0; }
TbBool action_point_is_creature_from_list_within(const struct ActionPoint *apt, long first_thing_idx) { unsigned long k; int i; SYNCDBG(8,"Starting"); k = 0; i = first_thing_idx; 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 // Range of 0 means activate when on the same subtile if (apt->range <= 0) { if ((apt->mappos.x.stl.num == thing->mappos.x.stl.num) && (apt->mappos.y.stl.num == thing->mappos.y.stl.num)) { return true; } } else { long dist; dist = get_distance_xy(thing->mappos.x.val, thing->mappos.y.val, apt->mappos.x.val, apt->mappos.y.val); if (apt->range > dist) { return true; } } // Thing list loop body ends k++; if (k > CREATURES_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); break; } } return false; }
struct Thing *computer_check_creatures_in_room_for_accelerate(struct Computer2 *comp, struct Room *room) { struct Dungeon *dungeon; struct StateInfo *stati; struct CreatureControl *cctrl; struct Thing *thing; unsigned long k; long i,n; dungeon = comp->dungeon; i = room->creatures_list; k = 0; while (i != 0) { thing = thing_get(i); cctrl = creature_control_get_from_thing(thing); if (thing_is_invalid(thing) || creature_control_invalid(cctrl)) { ERRORLOG("Jump to invalid creature %ld detected",i); break; } i = cctrl->next_in_room; // Per creature code if (!thing_affected_by_spell(thing, SplK_Speed)) { n = get_creature_state_besides_move(thing); stati = get_thing_state_info_num(n); if (stati->state_type == 1) { if (try_game_action(comp, dungeon->owner, GA_UsePwrSpeedUp, SPELL_MAX_LEVEL, 0, 0, thing->index, 0) > Lb_OK) { return thing; } } } // Per creature code ends k++; if (k > THINGS_COUNT) { ERRORLOG("Infinite loop detected when sweeping things list"); break; } } return INVALID_THING; }
void delete_thing_structure_f(struct Thing *thing, long a2, const char *func_name) { TRACE_THING(thing); if ((thing->alloc_flags & TAlF_InDungeonList) != 0) { remove_first_creature(thing); } if (!a2) { if (thing->light_id != 0) { light_delete_light(thing->light_id); thing->light_id = 0; } } struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); if (!creature_control_invalid(cctrl)) { if ( !a2 ) { remove_creature_lair(thing); if (creature_is_group_member(thing)) { remove_creature_from_group(thing); } } delete_control_structure(cctrl); } if (thing->snd_emitter_id != 0) { S3DDestroySoundEmitterAndSamples(thing->snd_emitter_id); thing->snd_emitter_id = 0; } remove_thing_from_its_class_list(thing); remove_thing_from_mapwho(thing); if (thing->index > 0) { game.free_things_start_index--; game.free_things[game.free_things_start_index] = thing->index; } else { #if (BFDEBUG_LEVEL > 0) ERRORMSG("%s: Performed deleting of thing with bad index %d!",func_name,(int)thing->index); #endif } LbMemorySet(thing, 0, sizeof(struct Thing)); }
struct CreatureControl *allocate_free_control_structure(void) { struct CreatureControl *cctrl; long i; for (i=1; i < CREATURES_COUNT; i++) { cctrl = game.persons.cctrl_lookup[i]; if (!creature_control_invalid(cctrl)) { if ((cctrl->flgfield_1 & CCFlg_Exists) == 0) { LbMemorySet(cctrl, 0, sizeof(struct CreatureControl)); cctrl->flgfield_1 |= CCFlg_Exists; cctrl->index = i; return cctrl; } } } return NULL; }
long get_wanderer_possible_targets_count_in_list(long first_thing_idx, struct Thing *wanderer) { struct CreatureControl *cctrl; struct Thing *thing; long victims_count; unsigned long k; long i; victims_count = 0; // Get the amount of possible targets k = 0; i = first_thing_idx; 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)) { // Don't check for being navigable - it's too CPU-expensive to check all creatures //if ( creature_can_navigate_to(wanderer, &thing->mappos, NavTF_Default) ) { victims_count++; } } // Thing list loop body ends k++; if (k > CREATURES_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); break; } } return victims_count; }
void multiply_creatures_in_dungeon_list(struct Dungeon *dungeon, long list_start) { struct Thing *thing; struct Thing *tncopy; struct CreatureControl *cctrl; unsigned long k; int i; k = 0; i = list_start; while (i != 0) { thing = thing_get(i); 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 tncopy = create_creature(&thing->mappos, thing->model, dungeon->owner); if (thing_is_invalid(tncopy)) { WARNLOG("Can't create a copy of creature"); break; } set_creature_level(tncopy, cctrl->explevel); tncopy->health = thing->health; // Thing list loop body ends k++; if (k > CREATURES_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); erstat_inc(ESE_InfChainTngPerOwner); break; } } }
struct Thing * find_imp_for_pickup(struct Computer2 *comp, MapSubtlCoord stl_x, MapSubtlCoord stl_y) { struct Dungeon *dungeon; int pick1_dist; struct Thing *pick1_tng; int pick2_dist; struct Thing *pick2_tng; //return _DK_find_imp_for_pickup(comp, stl_x, stl_y); dungeon = comp->dungeon; pick1_dist = INT_MAX; pick2_dist = INT_MAX; pick2_tng = INVALID_THING; pick1_tng = INVALID_THING; long i; unsigned long k; k = 0; i = dungeon->digger_list_start; while (i != 0) { struct Thing *thing; struct CreatureControl *cctrl; thing = thing_get(i); 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 (cctrl->combat_flags == 0) { if (!creature_is_being_unconscious(thing) && !creature_affected_by_spell(thing, SplK_Chicken)) { if (!creature_is_being_dropped(thing) && can_thing_be_picked_up_by_player(thing, dungeon->owner)) { MapSubtlDelta dist; long state_type; dist = abs(stl_x - (MapSubtlDelta)thing->mappos.x.stl.num) + abs(stl_y - (MapSubtlDelta)thing->mappos.y.stl.num); state_type = get_creature_state_type(thing); if (state_type == CrStTyp_Work) { if (dist < pick1_dist) { pick1_dist = dist; pick1_tng = thing; } } else { if (dist < pick2_dist) { pick2_dist = dist; pick2_tng = thing; } } } } } // Thing list loop body ends k++; if (k > CREATURES_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); break; } } if (!thing_is_invalid(pick2_tng)) { return pick2_tng; } else { return pick1_tng; } }
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; }
short good_doing_nothing(struct Thing *creatng) { struct CreatureControl *cctrl; struct PlayerInfo *player; long nturns; PlayerNumber target_plyr_idx; //return _DK_good_doing_nothing(creatng); SYNCDBG(18,"Starting"); TRACE_THING(creatng); // Debug code to find incorrect states if (!is_hero_thing(creatng)) { ERRORLOG("Non hero %s index %d owned by player %d - reset", thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); set_start_state(creatng); return 0; } cctrl = creature_control_get_from_thing(creatng); if (creature_control_invalid(cctrl)) { ERRORLOG("Invalid creature control; no action"); return 0; } // Respect the idle time - just wander around some time nturns = game.play_gameturn - cctrl->idle.start_gameturn; if (nturns <= 1) { return 1; } // Do some wandering also if can't find any task to do if (cctrl->field_5 > (long)game.play_gameturn) { if (creature_choose_random_destination_on_valid_adjacent_slab(creatng)) { creatng->continue_state = CrSt_GoodDoingNothing; } return 1; } // Done wandering - find a target player target_plyr_idx = cctrl->party.target_plyr_idx; if (target_plyr_idx != -1) { player = get_player(target_plyr_idx); if (player_invalid(player)) { ERRORLOG("Invalid target player in %s index %d owned by player %d - reset", thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); cctrl->party.target_plyr_idx = -1; return 0; } if (player->victory_state != VicS_LostLevel) { nturns = game.play_gameturn - cctrl->long_91; if (nturns > 400) { // Go to the previously chosen dungeon if (!creature_can_get_to_dungeon(creatng,target_plyr_idx)) { // Cannot get to the originally selected dungeon - reset it cctrl->party.target_plyr_idx = -1; } } else if (nturns >= 0) { // Waiting - move around a bit if (creature_choose_random_destination_on_valid_adjacent_slab(creatng)) { creatng->continue_state = CrSt_GoodDoingNothing; return 0; } } else { // Value lower than 0 would mean it is invalid WARNLOG("Invalid wait time detected for %s, value %ld",thing_model_name(creatng),(long)cctrl->long_91); cctrl->long_91 = 0; } } else { // The player we've chosen has lost - we'll have to find other target cctrl->party.target_plyr_idx = -1; } } target_plyr_idx = cctrl->party.target_plyr_idx; if (target_plyr_idx == -1) { nturns = game.play_gameturn - cctrl->long_91; if (nturns > 400) { cctrl->long_91 = game.play_gameturn; cctrl->byte_8C = 1; } nturns = game.play_gameturn - cctrl->long_8D; if (nturns > 64) { cctrl->long_8D = game.play_gameturn; cctrl->party.target_plyr_idx = good_find_enemy_dungeon(creatng); } target_plyr_idx = cctrl->party.target_plyr_idx; if (target_plyr_idx == -1) { SYNCDBG(4,"No enemy dungeon to perform %s index %d task", thing_model_name(creatng),(int)creatng->index); if (creature_choose_random_destination_on_valid_adjacent_slab(creatng)) { creatng->continue_state = CrSt_GoodDoingNothing; return 1; } cctrl->field_5 = game.play_gameturn + 16; } return 1; } if (good_creature_setup_task_in_dungeon(creatng, target_plyr_idx)) { return 1; } // If there are problems with the task, do a break before re-trying cctrl->field_5 = game.play_gameturn + 200; return 0; }
TbBool steal_hero(struct PlayerInfo *player, struct Coord3d *pos) { //TODO CONFIG creature models dependency; put them in config files static ThingModel skip_steal_models[] = {6, 7}; static ThingModel prefer_steal_models[] = {3, 12}; struct Thing *herotng; herotng = INVALID_THING; int heronum; struct Dungeon *herodngn; struct CreatureControl *cctrl; unsigned long k; int i; SYNCDBG(8,"Starting"); herodngn = get_players_num_dungeon(game.hero_player_num); k = 0; if (herodngn->num_active_creatrs > 0) { heronum = ACTION_RANDOM(herodngn->num_active_creatrs); i = herodngn->creatr_list_start; SYNCDBG(4,"Selecting random creature %d out of %d heroes",(int)heronum,(int)herodngn->num_active_creatrs); } else { heronum = 0; i = 0; SYNCDBG(4,"No heroes on map, skipping selection"); } while (i != 0) { struct Thing *thing; thing = thing_get(i); TRACE_THING(thing); 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 TbBool heroallow; heroallow = true; ThingModel skipidx; for (skipidx=0; skipidx < sizeof(skip_steal_models)/sizeof(skip_steal_models[0]); skipidx++) { if (thing->model == skip_steal_models[skipidx]) { heroallow = false; } } if (heroallow) { herotng = thing; } // If we've reached requested hero number, return either current hero on previously selected one if ((heronum <= 0) && thing_is_creature(herotng)) { break; } heronum--; if (i == 0) { i = herodngn->creatr_list_start; } // Thing list loop body ends k++; if (k > CREATURES_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); erstat_inc(ESE_InfChainTngPerOwner); break; } } if (!thing_is_invalid(herotng)) { move_thing_in_map(herotng, pos); change_creature_owner(herotng, player->id_number); SYNCDBG(3,"Converted %s to owner %d",thing_model_name(herotng),(int)player->id_number); } else { i = ACTION_RANDOM(sizeof(prefer_steal_models)/sizeof(prefer_steal_models[0])); struct Thing *creatng; creatng = create_creature(pos, prefer_steal_models[i], player->id_number); if (thing_is_invalid(creatng)) return false; SYNCDBG(3,"Created %s owner %d",thing_model_name(creatng),(int)player->id_number); } return true; }