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