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; }
/** * 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; }
/** 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; }