TbBool attempt_anger_job_destroy_rooms(struct Thing *creatng) { //return _DK_attempt_anger_job_destroy_rooms(creatng); if (!can_change_from_state_to(creatng, creatng->active_state, CrSt_CreatureVandaliseRooms)) { return false; } struct Room *room; struct Coord3d pos; room = find_nearest_room_for_thing_excluding_two_types(creatng, creatng->owner, 7, 1, 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_CreatureVandaliseRooms)) { return false; } if (!setup_random_head_for_room(creatng, room, NavRtF_NoOwner)) { return false; } struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); creatng->continue_state = CrSt_CreatureVandaliseRooms; cctrl->target_room_id = room->index; return true; }
TbBool attempt_anger_job_kill_creatures(struct Thing *creatng) { if (!can_change_from_state_to(creatng, creatng->active_state, CrSt_CreatureKillCreatures)) { return false; } if (!external_set_thing_state(creatng, CrSt_CreatureKillCreatures)) { return false; } return true; }
TbBool attempt_anger_job_mad_psycho(struct Thing *creatng) { TRACE_THING(creatng); if (!external_set_thing_state(creatng, CrSt_MadKillingPsycho)) { return false; } struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); cctrl->spell_flags |= CSAfF_MadKilling; cctrl->byte_9A = 0; return true; }
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; }
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; }
TbBool attempt_anger_job_leave_dungeon(struct Thing *creatng) { if (!can_change_from_state_to(creatng, creatng->active_state, CrSt_CreatureLeaves)) { return false; } struct Room *room; room = find_nearest_room_for_thing(creatng, creatng->owner, RoK_ENTRANCE, NavRtF_Default); if (room_is_invalid(room)) { return false; } if (!external_set_thing_state(creatng, CrSt_CreatureLeaves)) { return false; } if (!setup_random_head_for_room(creatng, room, NavRtF_Default)) { return false; } creatng->continue_state = CrSt_CreatureLeaves; 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; }
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; }
TbBool attempt_anger_job_persuade(struct Thing *creatng) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); if (cctrl->explevel <= 5) { return false; } if (!can_change_from_state_to(creatng, creatng->active_state, CrSt_CreaturePersuade)) { return false; } struct Dungeon *dungeon; dungeon = get_players_num_dungeon(creatng->owner); int persuade_count; persuade_count = min(dungeon->num_active_creatrs-1, 5); if (persuade_count <= 0) { return false; } persuade_count = ACTION_RANDOM(persuade_count) + 1; if (!external_set_thing_state(creatng, CrSt_CreaturePersuade)) { return false; } cctrl->byte_9A = persuade_count; return true; }
/** Returns if a creature can do specific job at given map position. * * @param creatng The creature which is planned for the job. * @param stl_x Target map position, x coord. * @param stl_y Target map position, y coord. * @param new_job Job selection with single job flag set. * @return True if the creature can do the job specified, false otherwise. * @see creature_can_do_job_for_player() similar function for use when only target player is known */ TbBool creature_can_do_job_near_position(struct Thing *creatng, MapSubtlCoord stl_x, MapSubtlCoord stl_y, CreatureJob new_job, unsigned long flags) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); SYNCDBG(6,"Starting for %s (owner %d) and job %s",thing_model_name(creatng),(int)creatng->owner,creature_job_code_name(new_job)); struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); if (creature_will_reject_job(creatng, new_job)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; in not-do-jobs list",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); if ((flags & JobChk_SetStateOnFail) != 0) { anger_apply_anger_to_creature(creatng, crstat->annoy_will_not_do_job, AngR_Other, 1); external_set_thing_state(creatng, CrSt_CreatureMoan); cctrl->field_282 = 50; } return false; } // Don't allow creatures changed to chickens to have any job assigned, besides those specifically marked if (creature_affected_by_spell(creatng, SplK_Chicken) && ((get_flags_for_job(new_job) & JoKF_AllowChickenized) == 0)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; under chicken spell",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } // Check if the job is related to correct map place (room,slab) if (!is_correct_position_to_perform_job(creatng, stl_x, stl_y, new_job)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; not correct place for job",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } struct CreatureJobConfig *jobcfg; jobcfg = get_config_for_job(new_job); if (jobcfg->func_cord_check == NULL) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; job has no coord check function",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } if (!jobcfg->func_cord_check(creatng, stl_x, stl_y, new_job, flags)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; coord check not passed",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } // If other tests pass, check if related room (if is needed) has capacity to be used for that job if ((get_flags_for_job(new_job) & JoKF_NeedsCapacity) != 0) { struct Room *room; room = subtile_room_get(stl_x, stl_y); if (!room_has_enough_free_capacity_for_creature(room, creatng)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; not enough room capacity",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); if ((flags & JobChk_PlayMsgOnFail) != 0) { const struct RoomConfigStats *roomst; roomst = get_room_kind_stats(room->kind); if (is_my_player_number(room->owner) && (roomst->msg_too_small > 0)) { output_message_room_related_from_computer_or_player_action(roomst->msg_too_small); } } return false; } } return true; }
TbBool process_scavenge_creature_from_level(struct Thing *scavtng, struct Thing *calltng, long work_value) { struct Dungeon *calldngn; long num_prayers; calldngn = get_dungeon(calltng->owner); if (dungeon_invalid(calldngn)) { ERRORLOG("The %s owner %d can't do scavenging - has no dungeon",thing_model_name(calltng),(int)calltng->owner); return false; } // Compute amount of creatures praying against the scavenge if (!is_neutral_thing(scavtng)) { struct Dungeon *scavdngn; scavdngn = get_dungeon(scavtng->owner); num_prayers = scavdngn->creatures_praying[scavtng->model]; } else { num_prayers = 0; } // Increase scavenging counter, used to break the prayers counter calldngn->creatures_scavenging[scavtng->model]++; // If scavenge is blocked by prayers, return if (calldngn->creatures_scavenging[calltng->model] < 2 * num_prayers) { SYNCDBG(8, "Player %d prayers (%d) are blocking player %d scavenging (%d) of %s", (int)scavtng->owner, (int)num_prayers, (int)calltng->owner, (int)calldngn->creatures_scavenging[calltng->model], thing_model_name(calltng)); return false; } SYNCDBG(18,"The %s index %d scavenges %s index %d",thing_model_name(calltng),(int)calltng->index,thing_model_name(scavtng),(int)scavtng->index); // If we're starting to scavenge a new creature, do the switch if (calldngn->scavenge_targets[calltng->model] != scavtng->index) { calldngn->scavenge_turn_points[calltng->model] = work_value; if (calldngn->scavenge_targets[calltng->model] > 0) { // Stop scavenging old creature struct Thing *thing; thing = thing_get(calldngn->scavenge_targets[calltng->model]); if (thing_is_creature(thing) && (thing->model == calltng->model)) { if (creature_is_being_scavenged(thing)) { set_start_state(thing); } } } // Start the new scavenging calldngn->scavenge_targets[calltng->model] = scavtng->index; if (is_my_player_number(scavtng->owner)) { output_message(SMsg_CreatureScanvenged, 500, 1); } event_create_event(scavtng->mappos.x.val, scavtng->mappos.y.val, EvKind_CreatrScavenged, scavtng->owner, scavtng->index); } else { calldngn->scavenge_turn_points[calltng->model] += work_value; } // Make sure the scavenged creature is in correct state if (!creature_is_being_scavenged(scavtng)) { if (!is_neutral_thing(scavtng)) { external_set_thing_state(scavtng, CrSt_CreatureBeingScavenged); } } long scavpts; scavpts = calculate_correct_creature_scavenge_required(scavtng, calltng->owner); if ((scavpts << 8) < calldngn->scavenge_turn_points[calltng->model]) { SYNCDBG(8,"The %s index %d owner %d accumulated enough points to turn to scavenger",thing_model_name(scavtng),(int)scavtng->index,(int)scavtng->owner); turn_creature_to_scavenger(scavtng, calltng); calldngn->scavenge_turn_points[calltng->model] -= (scavpts << 8); return true; } return false; }
CrStateRet training(struct Thing *thing) { struct CreatureControl *cctrl; TRACE_THING(thing); SYNCDBG(18,"Starting"); //return _DK_training(thing); cctrl = creature_control_get_from_thing(thing); // Check if we should finish training 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); remove_creature_from_work_room(thing); set_start_state(thing); return CrStRet_ResetOk; } if (!player_can_afford_to_train_creature(thing)) { SYNCDBG(19,"Ending training %s index %d; cannot afford",thing_model_name(thing),(int)thing->index); if (is_my_player_number(thing->owner)) output_message(SMsg_NoGoldToTrain, MESSAGE_DELAY_TREASURY, true); remove_creature_from_work_room(thing); set_start_state(thing); return CrStRet_ResetFail; } // Check if we're in correct room struct Room *room; room = get_room_thing_is_on(thing); if (creature_work_in_room_no_longer_possible(room, RoK_TRAINING, thing)) { remove_creature_from_work_room(thing); set_start_state(thing); return CrStRet_ResetFail; } struct Dungeon *dungeon; struct CreatureStats *crstat; dungeon = get_dungeon(thing->owner); crstat = creature_stats_get_from_thing(thing); // Pay for the training cctrl->field_82++; if (cctrl->field_82 >= game.train_cost_frequency) { cctrl->field_82 -= game.train_cost_frequency; if (take_money_from_dungeon(thing->owner, crstat->training_cost, 1) < 0) { ERRORLOG("Cannot take %d gold from dungeon %d",(int)crstat->training_cost,(int)thing->owner); } create_price_effect(&thing->mappos, thing->owner, crstat->training_cost); } if ((cctrl->instance_id != CrInst_NULL) || !check_experience_upgrade(thing)) { long work_value; // Training speed does not grow with experience - otherwise it would be too fast work_value = compute_creature_work_value(crstat->training_value*256, room->efficiency, 0); work_value = process_work_speed_on_work_value(thing, work_value); SYNCDBG(19,"The %s index %d produced %d training points",thing_model_name(thing),(int)thing->index,(int)work_value); cctrl->exp_points += work_value; dungeon->total_experience_creatures_gained += work_value; process_creature_in_training_room(thing, room); } else { if (external_set_thing_state(thing, CrSt_CreatureBeHappy)) { cctrl->field_282 = 50; } dungeon->lvstats.creatures_trained++; } return CrStRet_Modified; }
short researching(struct Thing *thing) { struct Dungeon *dungeon; long i; TRACE_THING(thing); dungeon = get_dungeon(thing->owner); if (is_neutral_thing(thing)) { ERRORLOG("Neutral %s index %d cannot do research",thing_model_name(thing),(int)thing->index); remove_creature_from_work_room(thing); set_start_state(thing); return CrStRet_Unchanged; } if (!creature_can_do_research(thing)) { if (!is_neutral_thing(thing) && (dungeon->current_research_idx < 0)) { if (is_my_player_number(dungeon->owner)) output_message(SMsg_NoMoreReseach, 500, true); } remove_creature_from_work_room(thing); set_start_state(thing); return CrStRet_Unchanged; } // Get and verify working room struct Room *room; room = get_room_thing_is_on(thing); if (creature_work_in_room_no_longer_possible(room, RoK_LIBRARY, thing)) { remove_creature_from_work_room(thing); set_start_state(thing); return CrStRet_ResetFail; } if (room->used_capacity > room->total_capacity) { output_message_room_related_from_computer_or_player_action(room->owner, room->kind, OMsg_RoomTooSmall); remove_creature_from_work_room(thing); set_start_state(thing); return CrStRet_ResetOk; } process_research_function(thing); struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); if ( (game.play_gameturn - dungeon->field_AE5 < 50) && ((game.play_gameturn + thing->index) & 0x03) == 0) { external_set_thing_state(thing, CrSt_CreatureBeHappy); cctrl->countdown_282 = 50; cctrl->long_9A = 0; return CrStRet_Modified; } if (cctrl->instance_id != CrInst_NULL) return 1; cctrl->field_82++; // Shall we do some "Standing and thinking" if (cctrl->field_82 <= 128) { if (cctrl->byte_9A == 3) { // Do some random thinking if ((cctrl->field_82 % 16) == 0) { i = ACTION_RANDOM(LbFPMath_PI) - LbFPMath_PI/2; cctrl->long_9B = ((long)thing->move_angle_xy + i) & LbFPMath_AngleMask; cctrl->byte_9A = 4; } } else { // Look at different direction while thinking if (creature_turn_to_face_angle(thing, cctrl->long_9B) < LbFPMath_PI/18) { cctrl->byte_9A = 3; } } return 1; } // Finished "Standing and thinking" - make "new idea" effect and go to next position if (!setup_random_head_for_room(thing, room, NavRtF_Default)) { ERRORLOG("Cannot move %s index %d in %s room", thing_model_name(thing),(int)thing->index,room_code_name(room->kind)); set_start_state(thing); return 1; } thing->continue_state = CrSt_Researching; cctrl->field_82 = 0; cctrl->byte_9A = 3; if (cctrl->explevel < 3) { create_effect(&thing->mappos, TngEff_Unknown54, thing->owner); } else if (cctrl->explevel < 6) { create_effect(&thing->mappos, TngEff_Unknown55, thing->owner); } else { create_effect(&thing->mappos, TngEff_Unknown56, thing->owner); } return 1; }