long creature_turn_to_face(struct Thing *thing, const struct Coord3d *pos) { //TODO enable when issue in pathfinding is solved /*if (get_2d_box_distance(&thing->mappos, pos) <= 0) return -1;*/ struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(thing); long angle; angle = get_angle_xy_to(&thing->mappos, pos); long angle_diff, angle_sign, angle_delta; angle_diff = get_angle_difference(thing->move_angle_xy, angle); angle_sign = get_angle_sign(thing->move_angle_xy, angle); angle_delta = crstat->max_angle_change; if (angle_delta < 1) { angle_delta = 1; } if (angle_delta > angle_diff) { angle_delta = angle_diff; } if (angle_sign < 0) { angle_delta = -angle_delta; } long i; i = (thing->move_angle_xy + angle_delta); thing->move_angle_xy = i & LbFPMath_AngleMask; return get_angle_difference(thing->move_angle_xy, angle); }
long process_lair_enemy(struct Thing *thing, struct Room *room) { struct CreatureControl *cctrl; struct CreatureStats *crstat; struct Thing *enemytng; long combat_factor; cctrl = creature_control_get_from_thing(thing); // Shouldn't be possible. But just for sure. if (room_is_invalid(room)) { return 0; } // If the room changed during creature's journey, end if ((room->kind != RoK_LAIR) || (room->owner != thing->owner) || (room->index != cctrl->lair_room_id)) { return 0; } crstat = creature_stats_get_from_thing(thing); // End if the creature has no lair enemy if (crstat->lair_enemy == 0) { return 0; } // Search for enemies no often than every 64 turns if (((game.play_gameturn + thing->index) & 0x3F) != 0) { return 0; } combat_factor = find_fellow_creature_to_fight_in_room(thing,room,crstat->lair_enemy,&enemytng); if (combat_factor < 1) return 0; if (!set_creature_in_combat_to_the_death(thing, enemytng, combat_factor)) return 0; return 1; }
CrCheckRet process_scavenge_function(struct Thing *calltng) { SYNCDBG(18,"Starting for %s owner %d",thing_model_name(calltng),(int)calltng->owner); //return _DK_process_scavenge_function(thing); struct CreatureControl *callctrl; callctrl = creature_control_get_from_thing(calltng); struct Dungeon *calldngn; struct Room *room; calldngn = get_dungeon(calltng->owner); room = get_room_creature_works_in(calltng); if ( !room_still_valid_as_type_for_thing(room, RoK_SCAVENGER, calltng) ) { WARNLOG("Room %s owned by player %d is bad work place for %s owned by played %d",room_code_name(room->kind),(int)room->owner,thing_model_name(calltng),(int)calltng->owner); set_start_state(calltng); return CrCkRet_Continue; } struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(calltng); if (!player_can_afford_to_scavenge_creature(calltng)) { if (is_my_player_number(calltng->owner)) output_message(SMsg_NoGoldToScavenge, 500, 1); set_start_state(calltng); return CrCkRet_Continue; } if (calldngn->scavenge_counters_turn != game.play_gameturn) { reset_scavenge_counts(calldngn); } long work_value; work_value = compute_creature_work_value(crstat->scavenge_value*256, room->efficiency, callctrl->explevel); work_value = process_work_speed_on_work_value(calltng, work_value); SYNCDBG(9,"The %s index %d owner %d produced %d scavenge points",thing_model_name(calltng),(int)calltng->index,(int)calltng->owner,(int)work_value); struct Thing *scavtng; scavtng = get_scavenger_target(calltng); if (!thing_is_invalid(scavtng)) { process_scavenge_creature_from_level(scavtng, calltng, work_value); } else if (can_scavenge_creature_from_pool(calldngn, calltng->model)) { process_scavenge_creature_from_pool(calltng, work_value); } else { if (crstat->entrance_force) { calldngn->field_1485++; } return 0; } callctrl->field_82++; if (callctrl->field_82 > game.scavenge_cost_frequency) { callctrl->field_82 -= game.scavenge_cost_frequency; if (take_money_from_dungeon(calltng->owner, crstat->scavenger_cost, 1) < 0) { ERRORLOG("Cannot take %d gold from dungeon %d",(int)crstat->scavenger_cost,(int)calltng->owner); } create_price_effect(&calltng->mappos, calltng->owner, crstat->scavenger_cost); } return 0; }
short at_scavenger_room(struct Thing *thing) { struct CreatureControl *cctrl; struct CreatureStats *crstat; struct Dungeon *dungeon; struct Room *room; //return _DK_at_scavenger_room(thing); room = get_room_thing_is_on(thing); if (!room_initially_valid_as_type_for_thing(room, RoK_SCAVENGER, thing)) { WARNLOG("Room %s owned by player %d is invalid for %s index %d",room_code_name(room->kind),(int)room->owner,thing_model_name(thing),(int)thing->index); set_start_state(thing); return 0; } cctrl = creature_control_get_from_thing(thing); crstat = creature_stats_get_from_thing(thing); dungeon = get_dungeon(thing->owner); if (crstat->scavenger_cost >= dungeon->total_money_owned) { if (is_my_player_number(thing->owner)) output_message(SMsg_NoGoldToScavenge, MESSAGE_DELAY_TREASURY, true); set_start_state(thing); return 0; } if (!add_creature_to_work_room(thing, room)) { set_start_state(thing); return 0; } internal_set_thing_state(thing, CrSt_Scavengering); cctrl->field_82 = 0; return 1; }
struct Thing *create_and_control_creature_as_controller(struct PlayerInfo *player, long breed, struct Coord3d *pos) { struct CreatureStats *crstat; struct CreatureControl *cctrl; struct Dungeon *dungeon; struct Thing *thing; struct Camera *cam; struct InitLight ilght; SYNCDBG(6,"Request for model %ld at (%d,%d,%d)",breed,(int)pos->x.val,(int)pos->y.val,(int)pos->z.val); //return _DK_create_and_control_creature_as_controller(player, a2, pos); thing = create_creature(pos, breed, player->id_number); if (thing_is_invalid(thing)) return INVALID_THING; dungeon = get_dungeon(thing->owner); dungeon->num_active_creatrs--; dungeon->owned_creatures_of_model[thing->model]--; if (is_my_player(player)) { toggle_status_menu(0); turn_off_roaming_menus(); } cam = player->acamera; player->controlled_thing_idx = thing->index; player->field_31 = thing->creation_turn; player->field_4B5 = cam->field_6; thing->alloc_flags |= TAlF_IsControlled; thing->field_4F |= 0x01; cctrl = creature_control_get_from_thing(thing); cctrl->flgfield_2 |= 0x02; cctrl->max_speed = calculate_correct_creature_maxspeed(thing); set_player_mode(player, PVT_CreatureContrl); set_start_state(thing); // Preparing light object LbMemorySet(&ilght, 0, sizeof(struct InitLight)); ilght.mappos.x.val = thing->mappos.x.val; ilght.mappos.y.val = thing->mappos.y.val; ilght.mappos.z.val = thing->mappos.z.val; ilght.field_2 = 36; ilght.field_3 = 1; ilght.is_dynamic = 1; ilght.field_0 = 2560; thing->light_id = light_create_light(&ilght); if (thing->light_id != 0) { light_set_light_never_cache(thing->light_id); } else { ERRORLOG("Cannot allocate light to new hero"); } if (is_my_player_number(thing->owner)) { if (thing->class_id == TCls_Creature) { crstat = creature_stats_get_from_thing(thing); setup_eye_lens(crstat->eye_effect); } } return thing; }
/** * Returns if a creature can currently travel over lava. * @param thing * @return */ TbBool creature_can_travel_over_lava(const struct Thing *creatng) { const struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); // Check if a creature can fly in this moment - we don't care if it's natural ability // or temporary spell effect return (crstat->hurt_by_lava <= 0) || ((creatng->movement_flags & TMvF_Flying) != 0); }
/** * Returns if a player to whom the creature belongs can afford the creature to go scavenging. * @param creatng * @return */ TbBool player_can_afford_to_scavenge_creature(const struct Thing *creatng) { struct Dungeon *dungeon; dungeon = get_dungeon(creatng->owner); struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); return (crstat->scavenger_cost < dungeon->total_money_owned); }
/** * * @param creatng * @param plyr_idx * @param rkind * @return * @deprecated Room does not correspond to single job anymore, this should be avoided. */ TbBool creature_can_do_job_for_computer_player_in_room(const struct Thing *creatng, PlayerNumber plyr_idx, RoomKind rkind) { struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); CreatureJob jobpref; jobpref = get_job_for_room(rkind, JoKF_AssignComputerDropInRoom, crstat->job_primary|crstat->job_secondary); return creature_can_do_job_for_player(creatng, plyr_idx, jobpref, JobChk_None); }
short creature_sleep(struct Thing *thing) { //return _DK_creature_sleep(thing); struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); if ((cctrl->slap_turns > 0) || !creature_will_sleep(thing)) { set_start_state(thing); return 0; } struct Room *room; room = get_room_thing_is_on(thing); if (room_is_invalid(room) || (room->kind != RoK_LAIR) || (cctrl->lair_room_id != room->index) || (room->owner != thing->owner)) { set_start_state(thing); return 0; } thing->movement_flags &= ~0x0020; struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(thing); if (((game.play_gameturn + thing->index) % game.recovery_frequency) == 0) { HitPoints recover; recover = compute_creature_max_health(crstat->sleep_recovery, cctrl->explevel); apply_health_to_thing_and_display_health(thing, recover); } anger_set_creature_anger(thing, 0, AngR_NoLair); anger_apply_anger_to_creature(thing, crstat->annoy_sleeping, AngR_Other, 1); if (cctrl->field_82 > 0) { cctrl->field_82--; } if (((game.play_gameturn + thing->index) & 0x3F) == 0) { if (ACTION_RANDOM(100) < 5) { struct Dungeon *dungeon; dungeon = get_dungeon(thing->owner); dungeon->lvstats.backs_stabbed++; } } if (crstat->sleep_exp_slab != SlbT_ROCK) { if (creature_can_gain_experience(thing) && room_has_slab_adjacent(room, crstat->sleep_exp_slab)) { cctrl->exp_points += crstat->sleep_experience; check_experience_upgrade(thing); } } { HitPoints health_max; health_max = compute_creature_max_health(crstat->health, cctrl->explevel); if ((crstat->heal_threshold * health_max / 256 <= thing->health) && (!cctrl->field_82)) { set_start_state(thing); return 1; } } process_lair_enemy(thing, room); return 0; }
long creature_add_lair_to_room(struct Thing *creatng, struct Room *room) { struct Thing *lairtng; if (!room_has_enough_free_capacity_for_creature(room, creatng)) return 0; //return _DK_creature_add_lair_to_room(thing, room); // Make sure we don't already have a lair on that position lairtng = find_creature_lair_at_subtile(creatng->mappos.x.stl.num, creatng->mappos.y.stl.num, 0); if (!thing_is_invalid(lairtng)) return 0; struct CreatureStats *crstat; struct CreatureControl *cctrl; crstat = creature_stats_get_from_thing(creatng); cctrl = creature_control_get_from_thing(creatng); room->content_per_model[creatng->model]++; room->used_capacity += crstat->lair_size; if ((cctrl->lair_room_id > 0) && (cctrl->lairtng_idx > 0)) { struct Room *room; room = room_get(cctrl->lair_room_id); creature_remove_lair_from_room(creatng, room); } cctrl->lair_room_id = room->index; // Create the lair thing struct CreatureData *crdata; struct Coord3d pos; pos.x.val = creatng->mappos.x.val; pos.y.val = creatng->mappos.y.val; pos.z.val = creatng->mappos.z.val; crdata = creature_data_get_from_thing(creatng); lairtng = create_object(&pos, crdata->field_1, creatng->owner, -1); if (thing_is_invalid(lairtng)) { ERRORLOG("Could not create lair totem"); remove_thing_from_mapwho(creatng); place_thing_in_mapwho(creatng); return 1; // Return that so we won't try to redo the action over and over } lairtng->mappos.z.val = get_thing_height_at(lairtng, &lairtng->mappos); // Associate creature with the lair cctrl->lairtng_idx = lairtng->index; lairtng->word_13 = creatng->index; lairtng->word_15 = 1; // Lair size depends on creature level lairtng->word_17 = 300 * cctrl->explevel / 20 + 300; lairtng->field_52 = ACTION_RANDOM(0x800); struct Objects *objdat; unsigned long i; objdat = get_objects_data_for_thing(lairtng); i = convert_td_iso(objdat->field_5); set_thing_draw(lairtng, i, objdat->field_7, lairtng->word_15, 0, -1, objdat->field_11); thing_play_sample(creatng, 158, NORMAL_PITCH, 0, 3, 1, 2, FULL_LOUDNESS); create_effect(&pos, imp_spangle_effects[creatng->owner], creatng->owner); anger_set_creature_anger(creatng, 0, AngR_NoLair); remove_thing_from_mapwho(creatng); place_thing_in_mapwho(creatng); return 1; }
TbBool player_can_afford_to_train_creature(const struct Thing *thing) { struct Dungeon *dungeon; struct CreatureStats *crstat; //return _DK_player_can_afford_to_train_creature(thing); dungeon = get_dungeon(thing->owner); crstat = creature_stats_get_from_thing(thing); return (dungeon->total_money_owned >= crstat->training_cost); }
TbBool creature_can_do_scavenging(const struct Thing *creatng) { if (is_neutral_thing(creatng)) { return false; } struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); return (crstat->scavenge_value > 0); }
/** * Returns if given creature is able to heal by sleeping. * Does not take into consideration if the creature has a lair, checks only if * the creature model is able to heal in its lair in general. * @param creatng * @return */ TbBool creature_can_do_healing_sleep(const struct Thing *creatng) { if (is_neutral_thing(creatng)) { return false; } struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); return ((crstat->heal_requirement > 0) && (crstat->lair_size > 0)); }
TbBool creature_can_do_research(const struct Thing *creatng) { if (is_neutral_thing(creatng)) { return false; } struct CreatureStats *crstat; struct Dungeon *dungeon; crstat = creature_stats_get_from_thing(creatng); dungeon = get_dungeon(creatng->owner); return (crstat->research_value > 0) && (dungeon->current_research_idx >= 0); }
/** Returns if the creature meets conditions to be trained. * * @param thing The creature thing to be tested. * @return */ TbBool creature_can_be_trained(const struct Thing *thing) { struct CreatureStats *crstat; //return _DK_creature_can_be_trained(thing); crstat = creature_stats_get_from_thing(thing); // Creatures without training value can't be trained if (crstat->training_value <= 0) return false; // If its model can train, check if this one can gain more experience return creature_can_gain_experience(thing); }
TbBool creature_try_doing_secondary_job(struct Thing *creatng) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); if (game.play_gameturn - cctrl->job_secondary_check_turn <= 128) { return false; } cctrl->job_secondary_check_turn = game.play_gameturn; struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); return attempt_job_secondary_preference(creatng, crstat->job_secondary); }
TbBool creature_requires_healing(const struct Thing *thing) { struct CreatureControl *cctrl; struct CreatureStats *crstat; cctrl = creature_control_get_from_thing(thing); crstat = creature_stats_get_from_thing(thing); long maxhealth, minhealth; maxhealth = compute_creature_max_health(crstat->health,cctrl->explevel); minhealth = crstat->heal_requirement * maxhealth / 256; if ((long)thing->health <= minhealth) return true; return false; }
TbBool process_prisoner_skelification(struct Thing *thing, struct Room *room) { struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(thing); if ((thing->health >= 0) || (!crstat->humanoid_creature)) { return false; } //TODO [config] Allow skeletification only if spent specific amount of turns in prison (set low value) if (ACTION_RANDOM(101) > game.prison_skeleton_chance) return false; if (is_my_player_number(room->owner)) output_message(SMsg_PrisonMadeSkeleton, 0, true); prison_convert_creature_to_skeleton(room,thing); return true; }
void setup_move_to_new_training_position(struct Thing *thing, struct Room *room, unsigned long restart) { struct CreatureControl *cctrl; struct CreatureStats *crstat; struct Thing *prtng; struct CreatureControl *prctrl; struct Coord3d pos; long i; SYNCDBG(8,"Starting for %s",thing_model_name(thing)); //_DK_setup_move_to_new_training_position(thing, room, a3); cctrl = creature_control_get_from_thing(thing); crstat = creature_stats_get_from_thing(thing); if ( restart ) cctrl->training.search_timeout = 50; // Try partner training if ((crstat->partner_training > 0) && (ACTION_RANDOM(100) < crstat->partner_training)) { prtng = get_creature_in_training_room_which_could_accept_partner(room, thing); if (!thing_is_invalid(prtng)) { SYNCDBG(7,"The %s found %s as training partner.",thing_model_name(thing),thing_model_name(prtng)); prctrl = creature_control_get_from_thing(prtng); prctrl->training.mode = CrTrMd_PartnerTraining; prctrl->training.train_timeout = 75; prctrl->training.partner_idx = thing->index; prctrl->training.partner_creation = thing->creation_turn; cctrl->training.mode = CrTrMd_PartnerTraining; cctrl->training.train_timeout = 75; cctrl->training.partner_idx = prtng->index; cctrl->training.partner_creation = prtng->creation_turn; return; } } // No partner - train at some random position cctrl->training.mode = CrTrMd_SearchForTrainPost; if (find_random_valid_position_for_thing_in_room(thing, room, &pos)) { SYNCDBG(8,"Going to train at (%d,%d)",(int)pos.x.stl.num,(int)pos.y.stl.num); i = get_subtile_number(pos.x.stl.num,pos.y.stl.num); setup_training_move(thing, i); } else { SYNCDBG(8,"No new position found, staying at (%d,%d)",(int)cctrl->moveto_pos.x.stl.num,(int)cctrl->moveto_pos.x.stl.num); } if (cctrl->instance_id == CrInst_NULL) { set_creature_instance(thing, CrInst_SWING_WEAPON_SWORD, 1, 0, 0); } }
TbBool creature_can_gain_experience(const struct Thing *thing) { struct Dungeon *dungeon; struct CreatureStats *crstat; struct CreatureControl *cctrl; dungeon = get_dungeon(thing->owner); cctrl = creature_control_get_from_thing(thing); // Creatures which reached players max level can't be trained if (cctrl->explevel >= dungeon->creature_max_level[thing->model]) return false; // Creatures which reached absolute max level and have no grow up creature crstat = creature_stats_get_from_thing(thing); if ((cctrl->explevel >= (CREATURE_MAX_LEVEL-1)) && (crstat->grow_up == 0)) return false; return true; }
short manufacturing(struct Thing *creatng) { struct Room *room; //return _DK_manufacturing(creatng); TRACE_THING(creatng); room = get_room_thing_is_on(creatng); if (creature_work_in_room_no_longer_possible(room, RoK_WORKSHOP, creatng)) { remove_creature_from_work_room(creatng); set_start_state(creatng); return CrStRet_ResetFail; } if (room->used_capacity > room->total_capacity) { if (is_my_player_number(creatng->owner)) output_message(SMsg_WorkshopTooSmall, 500, true); remove_creature_from_work_room(creatng); set_start_state(creatng); return CrStRet_ResetOk; } struct Dungeon *dungeon; dungeon = get_dungeon(creatng->owner); if (dungeon->manufacture_class) { struct CreatureControl *cctrl; struct CreatureStats *crstat; cctrl = creature_control_get_from_thing(creatng); crstat = creature_stats_get_from_thing(creatng); long work_value; work_value = compute_creature_work_value(crstat->manufacture_value*256, room->efficiency, cctrl->explevel); work_value = process_work_speed_on_work_value(creatng, work_value); SYNCDBG(9,"The %s index %d produced %d manufacture points",thing_model_name(creatng),(int)creatng->index,(int)work_value); dungeon->manufacture_progress += work_value; dungeon->field_1181 += work_value; } else { WARNDBG(9,"The %s index %d owner %d is manufacturing nothing",thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); // This may be cause by a creature taking up place in workshop where crate should be created; the creature should take a break if (room->used_capacity >= room->total_capacity) { external_set_thing_state(creatng, CrSt_CreatureGoingHomeToSleep); return CrStRet_Modified; } } process_creature_in_workshop(creatng, room); return CrStRet_Modified; }
void creature_increase_available_instances(struct Thing *thing) { struct CreatureStats *crstat; struct CreatureControl *cctrl; crstat = creature_stats_get_from_thing(thing); cctrl = creature_control_get_from_thing(thing); int i,k; for (i=0; i < CREATURE_MAX_LEVEL; i++) { k = crstat->instance_spell[i]; if (k > 0) { if (crstat->instance_level[i] <= cctrl->explevel+1) { cctrl->instance_available[k] = true; } } } }
TbBool creature_find_and_perform_anger_job(struct Thing *creatng) { //return _DK_creature_find_and_perform_anger_job(creatng); struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); int i, k, n; // Count the amount of jobs set i = 0; k = crstat->jobs_anger; while (k != 0) { if ((k & 1) != 0) i++; k >>= 1; } if (i <= 0) { return false; } // Select a random job as a starting point n = ACTION_RANDOM(i) + 1; i = 0; for (k = 0; k < crtr_conf.angerjobs_count; k++) { if ((crstat->jobs_anger & (1 << k)) != 0) { n--; } if (n <= 0) { i = k; break; } } // Go through all jobs, starting at randomly selected one, attempting to start each one for (k = 0; k < crtr_conf.angerjobs_count; k++) { if ((crstat->jobs_anger & (1 << i)) != 0) { if (attempt_anger_job(creatng, 1 << i)) return 1; } i = (i+1) % crtr_conf.angerjobs_count; } return 0; }
short at_training_room(struct Thing *thing) { struct CreatureControl *cctrl; struct CreatureStats *crstat; struct Dungeon *dungeon; struct Room *room; //return _DK_at_training_room(thing); cctrl = creature_control_get_from_thing(thing); cctrl->target_room_id = 0; if (!creature_can_be_trained(thing)) { SYNCDBG(9,"Ending training of %s level %d; creature is not trainable",thing_model_name(thing),(int)cctrl->explevel); set_start_state(thing); return 0; } crstat = creature_stats_get_from_thing(thing); dungeon = get_dungeon(thing->owner); if (dungeon->total_money_owned < crstat->training_cost) { if (is_my_player_number(thing->owner)) output_message(SMsg_NoGoldToTrain, MESSAGE_DELAY_TREASURY, true); set_start_state(thing); return 0; } room = get_room_thing_is_on(thing); if (!room_initially_valid_as_type_for_thing(room, RoK_TRAINING, thing)) { WARNLOG("Room %s owned by player %d is invalid for %s",room_code_name(room->kind),(int)room->owner,thing_model_name(thing)); set_start_state(thing); return 0; } if ( !add_creature_to_work_room(thing, room) ) { set_start_state(thing); return 0; } internal_set_thing_state(thing, CrSt_Training); setup_move_to_new_training_position(thing, room, 1); cctrl->field_82 = 0; return 1; }
/** * Given instance ID, returns its position in compacted list of instances. * Compacted list of instances is a list of available creature instances without holes. * @param thing * @param req_inst_id * @return */ int creature_instance_get_available_pos_for_id(struct Thing *thing, CrInstance req_inst_id) { struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(thing); int avail_pos; avail_pos = 0; int avail_num; for (avail_num = 0; avail_num < CREATURE_MAX_SPELL; avail_num++) { CrInstance inst_id; inst_id = crstat->instance_spell_id[avail_num]; if (creature_instance_is_available(thing, inst_id)) { if (inst_id == req_inst_id) { return avail_pos; } avail_pos++; } } return -1; }
/** * For position in compacted list of instances, gives instance ID from availability list. * Compacted list of instances is a list of available creature instances without holes. * @param thing * @param req_avail_pos * @return */ CrInstance creature_instance_get_available_id_for_pos(struct Thing *thing, int req_avail_pos) { struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(thing); int avail_pos; avail_pos = 0; int avail_num; for (avail_num=0; avail_num < CREATURE_MAX_LEVEL; avail_num++) { CrInstance inst_id; inst_id = crstat->instance_spell[avail_num]; if (creature_instance_is_available(thing, inst_id)) { if (avail_pos == req_avail_pos) { return inst_id; } avail_pos++; } } return CrInst_NULL; }
TbBool creature_choose_first_available_instance(struct Thing *thing) { struct CreatureStats *crstat; struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); crstat = creature_stats_get_from_thing(thing); long i,k; for (i=0; i < CREATURE_MAX_LEVEL; i++) { k = crstat->instance_spell[i]; if (k > 0) { if (cctrl->instance_available[k]) { cctrl->field_1E8 = k; return true; } } } cctrl->field_1E8 = 0; return false; }
/** * Processes job stress and going postal due to annoying co-workers. * Creatures which aren't performing their primary jobs can be attacked by creatures * going postal. * Creature doing primary job in room may go postal and attack other creatures walking * through the same room which aren't performing the same job (ie. are just passing by), * or other workers in that room who does not have the job as primary job. * * @param creatng The thing being affected by job stress or going postal. * @param room The room where target creature should be searched for. * @return */ TbBool process_job_stress_and_going_postal(struct Thing *creatng, struct Room *room) { struct CreatureControl *cctrl; struct CreatureStats *crstat; cctrl = creature_control_get_from_thing(creatng); crstat = creature_stats_get_from_thing(creatng); if (cctrl->instance_id != CrInst_NULL) { return false; } // Process the stress once per 20 turns //TODO CONFIG export amount of turns to config file if (((game.play_gameturn + creatng->index) % 20) != 0) { return false; } // Process the job stress if (crstat->annoy_job_stress != 0) { // Note that this kind of code won't allow one-time jobs, or jobs not related to rooms, to be stressful CreatureJob stressful_job; stressful_job = get_creature_job_causing_stress(crstat->job_stress,room->kind); if (stressful_job != Job_NULL) { anger_apply_anger_to_creature(creatng, crstat->annoy_job_stress, AngR_Other, 1); } } // Process going postal if (crstat->annoy_going_postal != 0) { // Make sure we really should go postal in that room CreatureJob going_postal_job; going_postal_job = get_creature_job_causing_going_postal(crstat->job_primary,room->kind); if (going_postal_job != Job_NULL) { if (process_job_causes_going_postal(creatng, room, going_postal_job)) { return true; } } } return false; }
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; }
TbBool attempt_anger_job_steal_gold(struct Thing *creatng) { //return _DK_attempt_anger_job_steal_gold(creatng); if (!can_change_from_state_to(creatng, creatng->active_state, CrSt_CreatureStealGold)) { return false; } struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); if (creatng->creature.gold_carried >= crstat->gold_hold) { return false; } struct Room *room; struct Coord3d pos; room = find_nearest_room_for_thing_with_used_capacity(creatng, creatng->owner, RoK_TREASURE, NavRtF_NoOwner, 1); if (room_is_invalid(room)) { return false; } if (!find_random_valid_position_for_thing_in_room(creatng, room, &pos)) { return false; } if (!creature_can_navigate_to_with_storage(creatng, &pos, NavRtF_NoOwner)) { return false; } if (!external_set_thing_state(creatng, CrSt_CreatureStealGold)) { return false; } if (!setup_random_head_for_room(creatng, room, NavRtF_NoOwner)) { ERRORLOG("Cannot setup head for treasury."); return false; } struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); creatng->continue_state = CrSt_CreatureSearchForGoldToStealInRoom1; cctrl->target_room_id = room->index; return true; }