CrStateRet creature_in_prison(struct Thing *thing) { struct Room *room; TRACE_THING(thing); room = get_room_thing_is_on(thing); if (creature_work_in_room_no_longer_possible(room, RoK_PRISON, 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); set_start_state(thing); return CrStRet_ResetOk; } switch (process_prison_function(thing)) { case CrCkRet_Deleted: return CrStRet_Deleted; case CrCkRet_Available: process_prison_visuals(thing, room); return CrStRet_Modified; default: return CrStRet_ResetOk; } }
short creature_arrived_at_prison(struct Thing *creatng) { struct CreatureControl *cctrl; struct Room *room; TRACE_THING(creatng); cctrl = creature_control_get_from_thing(creatng); cctrl->target_room_id = 0; room = get_room_thing_is_on(creatng); if (!room_initially_valid_as_type_for_thing(room, RoK_PRISON, creatng)) { WARNLOG("Room %s owned by player %d is invalid for %s index %d",room_code_name(room->kind),(int)room->owner,thing_model_name(creatng),(int)creatng->index); set_start_state(creatng); return 0; } if (!add_creature_to_work_room(creatng, room)) { output_message_room_related_from_computer_or_player_action(room->owner, room->kind, OMsg_RoomTooSmall); cctrl->flgfield_1 &= ~CCFlg_NoCompControl; set_start_state(creatng); return 0; } cctrl->field_82 = game.play_gameturn; cctrl->flgfield_1 |= CCFlg_NoCompControl; internal_set_thing_state(creatng, CrSt_CreatureInPrison); if (creature_affected_by_spell(creatng, SplK_Speed)) { terminate_thing_spell_effect(creatng, SplK_Speed); } if (creature_affected_by_spell(creatng, SplK_Invisibility)) { terminate_thing_spell_effect(creatng, SplK_Invisibility); } if (creatng->light_id != 0) { light_delete_light(creatng->light_id); creatng->light_id = 0; } return 1; }
/** 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; }
/** Returns if a creature can do specific job for the player. * * @param creatng The creature which is planned for the job. * @param plyr_idx Player for whom the job is to be done. * @param new_job Job selection with single job flag set. * @param flags Function behavior adjustment flags. * @return True if the creature can do the job specified, false otherwise. * @note this should be used instead of person_will_do_job_for_room() * @note this function will never change state of the input thing, even if appropriate flags are set * @see creature_can_do_job_near_position() similar function for use when target position is known */ TbBool creature_can_do_job_for_player(const struct Thing *creatng, PlayerNumber plyr_idx, CreatureJob new_job, unsigned long flags) { SYNCDBG(16,"Starting for %s (owner %d) and job %s",thing_model_name(creatng),(int)creatng->owner,creature_job_code_name(new_job)); if (creature_will_reject_job(creatng, new_job)) { SYNCDBG(13,"Cannot assign %s for %s index %d owner %d; in not do jobs list",creature_job_code_name(new_job),thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } if (!is_correct_owner_to_perform_job(creatng, plyr_idx, new_job)) { SYNCDBG(13,"Cannot assign %s for %s index %d owner %d; not correct owner for job",creature_job_code_name(new_job),thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); 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(13,"Cannot assign %s for %s index %d owner %d; under chicken spell",creature_job_code_name(new_job),thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } // Check if the job is related to correct player struct CreatureJobConfig *jobcfg; jobcfg = get_config_for_job(new_job); if (jobcfg->func_plyr_check == NULL) { return false; } if (!jobcfg->func_plyr_check(creatng, plyr_idx, new_job)) { return false; } RoomKind job_rkind; job_rkind = get_room_for_job(new_job); if (job_rkind != RoK_NONE) { if (!player_has_room(plyr_idx, job_rkind)) { SYNCDBG(3,"Cannot assign %s in player %d room for %s index %d owner %d; no required room built",creature_job_code_name(new_job),(int)plyr_idx,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); if ((flags & JobChk_PlayMsgOnFail) != 0) { const struct RoomConfigStats *roomst; roomst = get_room_kind_stats(get_room_for_job(new_job)); if (is_my_player_number(plyr_idx) && (roomst->msg_needed > 0)) { output_message_room_related_from_computer_or_player_action(roomst->msg_needed); } } return false; } if ((get_flags_for_job(new_job) & JoKF_NeedsCapacity) != 0) { struct Room *room; room = find_room_with_spare_capacity(plyr_idx, job_rkind, 1); if (room_is_invalid(room)) { SYNCDBG(3,"Cannot assign %s in player %d room for %s index %d owner %d; not enough room capacity",creature_job_code_name(new_job),(int)plyr_idx,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); if ((flags & JobChk_PlayMsgOnFail) != 0) { const struct RoomConfigStats *roomst; roomst = get_room_kind_stats(get_room_for_job(new_job)); if (is_my_player_number(plyr_idx) && (roomst->msg_too_small > 0)) { output_message_room_related_from_computer_or_player_action(roomst->msg_too_small); } } return false; } } } return true; }
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; }