CrStateRet creature_at_changed_lair(struct Thing *creatng) { struct Room *room; TRACE_THING(creatng); //return _DK_creature_at_changed_lair(thing); if (!thing_is_on_own_room_tile(creatng)) { set_start_state(creatng); return CrStRet_ResetFail; } room = get_room_thing_is_on(creatng); if (!room_initially_valid_as_type_for_thing(room, RoK_LAIR, creatng)) { WARNLOG("Room %s owned by player %d is invalid for %s",room_code_name(room->kind),(int)room->owner,thing_model_name(creatng)); set_start_state(creatng); return CrStRet_ResetFail; } if (!creature_add_lair_to_room(creatng, room)) { internal_set_thing_state(creatng, CrSt_CreatureChooseRoomForLairSite); return CrStRet_Modified; } // All done - finish the state set_start_state(creatng); return CrStRet_ResetOk; }
short at_guard_post_room(struct Thing *thing) { struct CreatureControl *cctrl; struct Room *room; cctrl = creature_control_get_from_thing(thing); cctrl->target_room_id = 0; room = get_room_thing_is_on(thing); if (!room_initially_valid_as_type_for_thing(room, get_room_for_job(Job_GUARD), 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; } if (!add_creature_to_work_room(thing, room, Job_GUARD)) { set_start_state(thing); return 0; } internal_set_thing_state(thing, get_continue_state_for_job(Job_GUARD)); if (!person_get_somewhere_adjacent_in_room(thing, room, &cctrl->moveto_pos)) { cctrl->moveto_pos.x.val = thing->mappos.x.val; cctrl->moveto_pos.y.val = thing->mappos.y.val; cctrl->moveto_pos.z.val = thing->mappos.z.val; } return 1; }
CrStateRet guarding(struct Thing *thing) { struct Room *room; TRACE_THING(thing); room = get_room_thing_is_on(thing); if (creature_job_in_room_no_longer_possible(room, Job_GUARD, thing)) { remove_creature_from_work_room(thing); set_start_state(thing); return CrStRet_ResetFail; } struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); if (creature_move_to(thing, &cctrl->moveto_pos, cctrl->max_speed, 0, 0) == 0) { return CrStRet_Unchanged; } if (!person_get_somewhere_adjacent_in_room(thing, room, &cctrl->moveto_pos)) { cctrl->moveto_pos.x.val = thing->mappos.x.val; cctrl->moveto_pos.y.val = thing->mappos.y.val; cctrl->moveto_pos.z.val = thing->mappos.z.val; } return CrStRet_Modified; }
long instf_attack_room_slab(struct Thing *creatng, long *param) { TRACE_THING(creatng); //return _DK_instf_attack_room_slab(creatng, param); struct Room *room; room = get_room_thing_is_on(creatng); if (room_is_invalid(room)) { ERRORLOG("The %s is not on room",thing_model_name(creatng)); return 0; } struct SlabMap *slb; slb = get_slabmap_thing_is_on(creatng); if (slb->health > 2) { //TODO CONFIG damage made to room slabs is constant - doesn't look good slb->health -= 2; thing_play_sample(creatng, 128 + UNSYNC_RANDOM(3), NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); return 1; } if (room->owner != game.neutral_player_num) { struct Dungeon *dungeon; dungeon = get_dungeon(room->owner); dungeon->rooms_destroyed++; } if (!delete_room_slab(coord_slab(creatng->mappos.x.val), coord_slab(creatng->mappos.y.val), 1)) { ERRORLOG("Cannot delete %s room tile destroyed by %s",room_code_name(room->kind),thing_model_name(creatng)); return 0; } create_effect(&creatng->mappos, 3, creatng->owner); thing_play_sample(creatng, 47, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); return 1; }
short at_workshop_room(struct Thing *thing) { struct CreatureControl *cctrl; struct Room *room; //return _DK_at_workshop_room(thing); cctrl = creature_control_get_from_thing(thing); cctrl->target_room_id = 0; room = get_room_thing_is_on(thing); if (!room_initially_valid_as_type_for_thing(room, RoK_WORKSHOP, 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 (room->total_capacity <= room->used_capacity) { 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_Manufacturing); setup_move_to_new_workshop_position(thing, room, 1); return 1; }
struct Thing *get_workshop_box_thing(PlayerNumber owner, ThingModel objmodel) { struct Thing *thing; int i,k; k = 0; i = game.thing_lists[TngList_Objects].index; while (i > 0) { thing = thing_get(i); if (thing_is_invalid(thing)) break; i = thing->next_of_class; // Per-thing code if ( ((thing->alloc_flags & TAlF_Exists) != 0) && (thing->model == objmodel) && (thing->owner == owner) ) { struct Room *room; room = get_room_thing_is_on(thing); if (!thing_is_picked_up(thing) && room_role_matches(room->kind, RoRoF_CratesStorage) && (room->owner == owner)) return thing; } // Per-thing code ends k++; if (k > THINGS_COUNT) { ERRORLOG("Infinite loop detected when sweeping things list"); break; } } return INVALID_THING; }
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_drop_body_in_prison(struct Thing *thing) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); struct Thing *dragtng; dragtng = thing_get(cctrl->dragtng_idx); if (!thing_exists(dragtng) || !creature_is_being_unconscious(dragtng)) { set_start_state(thing); return 0; } if (!subtile_is_room(thing->mappos.x.stl.num, thing->mappos.y.stl.num)) { set_start_state(thing); return 0; } struct Room *room; room = get_room_thing_is_on(thing); if ((room->owner != thing->owner) || (room->kind != RoK_PRISON)) { set_start_state(thing); return 0; } make_creature_conscious(dragtng); initialise_thing_state(dragtng, CrSt_CreatureArrivedAtPrison); struct CreatureControl *dragctrl; dragctrl = creature_control_get_from_thing(dragtng); dragctrl->flgfield_1 |= CCFlg_NoCompControl; set_start_state(thing); return 1; }
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; }
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; }
short barracking(struct Thing *creatng) { struct Room *room; room = get_room_thing_is_on(creatng); if (!room_still_valid_as_type_for_thing(room, RoK_BARRACKS, creatng)) { WARNLOG("Room %s owned by player %d is bad work place for %s index %d owner %d",room_code_name(room->kind),(int)room->owner,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); remove_creature_from_work_room(creatng); set_start_state(creatng); return CrStRet_ResetFail; } if (person_move_somewhere_adjacent_in_room(creatng, room)) { creatng->continue_state = CrSt_Barracking; } return CrStRet_Modified; }
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 setup_workshop_search_for_post(struct Thing *creatng) { struct Room *room; struct Thing *postng; postng = INVALID_THING; room = get_room_thing_is_on(creatng); // Find a random slab in the room to be used as our starting point long i; unsigned long n; i = ACTION_RANDOM(room->slabs_count); n = room->slabs_list; while (i > 0) { n = get_next_slab_number_in_room(n); i--; } i = room->slabs_count; while (i > 0) { // Loop the slabs list if (n <= 0) { n = room->slabs_list; } MapSlabCoord slb_x, slb_y; slb_x = subtile_slab_fast(stl_num_decode_x(n)); slb_y = subtile_slab_fast(stl_num_decode_y(n)); struct Thing *objtng; objtng = get_workshop_equipment_to_work_with_on_subtile(creatng->owner, slab_subtile_center(slb_x), slab_subtile_center(slb_y)); if (!thing_is_invalid(objtng)) { postng = objtng; } n = get_next_slab_number_in_room(n); i--; } if (thing_is_invalid(postng)) { SYNCDBG(9,"Work in %s, the %s moves to new pos",room_code_name(room->kind),thing_model_name(creatng)); setup_move_to_new_workshop_position(creatng, room, 1); } else { SYNCDBG(9,"Work in %s, the %s found a post",room_code_name(room->kind),thing_model_name(creatng)); setup_workshop_move(creatng, get_subtile_number(postng->mappos.x.stl.num, postng->mappos.y.stl.num)); } }
TbBool remove_workshop_object_from_player(PlayerNumber owner, ThingModel objmodel) { struct Thing *cratetng; struct Room *room; cratetng = get_workshop_box_thing(owner, objmodel); if (thing_is_invalid(cratetng)) { WARNLOG("Crate %s could not be found",object_code_name(objmodel)); return false; } room = get_room_thing_is_on(cratetng); if (room_exists(room)) { remove_workshop_object_from_workshop(room,cratetng); } else { WARNLOG("Crate thing index %d isn't placed existing room; removing anyway",(int)cratetng->index); } create_effect(&cratetng->mappos, imp_spangle_effects[cratetng->owner], cratetng->owner); destroy_object(cratetng); return true; }
short good_arrived_at_attack_room(struct Thing *thing) { struct Room *room; room = get_room_thing_is_on(thing); // If the current tile can be destroyed if (room_exists(room) && (room->owner != thing->owner) && !room_cannot_vandalise(room->kind)) { internal_set_thing_state(thing, CrSt_GoodAttackRoom1); MapCoord ev_coord_x,ev_coord_y; ev_coord_x = subtile_coord_center(room->central_stl_x); ev_coord_y = subtile_coord_center(room->central_stl_y); event_create_event_or_update_nearby_existing_event(ev_coord_x, ev_coord_y, EvKind_RoomUnderAttack, room->owner, 0); if (is_my_player_number(room->owner)) output_message(SMsg_EnemyDestroyRooms, MESSAGE_DELAY_FIGHT, true); return 1; } set_start_state(thing); return 0; }
struct Thing *get_creature_in_training_room_which_could_accept_partner(struct Room *room, struct Thing *partnertng) { struct CreatureControl *cctrl; struct Thing *thing; unsigned long k; long i; TRACE_THING(partnertng); i = room->creatures_list; k = 0; while (i != 0) { thing = thing_get(i); TRACE_THING(thing); cctrl = creature_control_get_from_thing(thing); if (!creature_control_exists(cctrl)) { ERRORLOG("Jump to invalid creature %d detected",(int)i); break; } i = cctrl->next_in_room; // Per creature code if (thing != partnertng) { if ( (get_creature_state_besides_move(thing) == CrSt_Training) && (cctrl->training.partner_idx == 0) ) { if (get_room_thing_is_on(thing) == room) { return thing; } else { WARNLOG("The %s pretends to be in room but it's not.",thing_model_name(thing)); } } } // Per creature code ends k++; if (k > THINGS_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); break; } } return INVALID_THING; }
short at_research_room(struct Thing *thing) { struct CreatureControl *cctrl; struct Dungeon *dungeon; struct Room *room; cctrl = creature_control_get_from_thing(thing); cctrl->target_room_id = 0; dungeon = get_dungeon(thing->owner); 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); } set_start_state(thing); return 0; } room = get_room_thing_is_on(thing); if (!room_initially_valid_as_type_for_thing(room, RoK_LIBRARY, 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; } if (!add_creature_to_work_room(thing, room)) { set_start_state(thing); return 0; } if (!setup_random_head_for_room(thing, room, NavRtF_Default)) { ERRORLOG("The %s index %d can not move in research room", thing_model_name(thing),(int)thing->index); remove_creature_from_work_room(thing); set_start_state(thing); return 0; } thing->continue_state = CrSt_Researching; cctrl->field_82 = 0; cctrl->byte_9A = 3; return 1; }
short at_lair_to_sleep(struct Thing *thing) { struct CreatureControl *cctrl; struct Thing *lairtng; struct Room *room; TRACE_THING(thing); //return _DK_at_lair_to_sleep(thing); cctrl = creature_control_get_from_thing(thing); lairtng = thing_get(cctrl->lairtng_idx); TRACE_THING(lairtng); cctrl->target_room_id = 0; if (thing_is_invalid(lairtng) || (cctrl->slap_turns != 0)) { set_start_state(thing); return 0; } if (!creature_will_sleep(thing)) { set_start_state(thing); return 0; } room = get_room_thing_is_on(thing); if (!room_initially_valid_as_type_for_thing(room, RoK_LAIR, 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 ((cctrl->lair_room_id != room->index)) { set_start_state(thing); return 0; } if ( !creature_turn_to_face_angle(thing, lairtng->field_52) ) { internal_set_thing_state(thing, CrSt_CreatureSleep); cctrl->field_82 = 200; thing->movement_flags &= ~TMvF_Flying; } process_lair_enemy(thing, room); return 1; }
CrStateRet creature_at_new_lair(struct Thing *creatng) { struct Room *room; TRACE_THING(creatng); //return _DK_creature_at_new_lair(thing); room = get_room_thing_is_on(creatng); if ( !room_still_valid_as_type_for_thing(room, RoK_LAIR, creatng) ) { 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(creatng),(int)creatng->owner); set_start_state(creatng); return CrStRet_ResetFail; } if (!creature_add_lair_to_room(creatng, room)) { internal_set_thing_state(creatng, CrSt_CreatureChooseRoomForLairSite); return CrStRet_Modified; } set_start_state(creatng); return CrStRet_ResetOk; }
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; }
short at_barrack_room(struct Thing *creatng) { struct Room *room; struct CreatureControl *cctrl; 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_BARRACKS, 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)) { set_start_state(creatng); return 0; } internal_set_thing_state(creatng, CrSt_Barracking); return 1; }
CrStateRet scavengering(struct Thing *thing) { // 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_SCAVENGER, thing)) { remove_creature_from_work_room(thing); set_start_state(thing); return CrStRet_ResetFail; } //return _DK_scavengering(thing); if (process_scavenge_function(thing)) { return CrStRet_Modified; } if (setup_scavenger_move(thing, room)) { return CrStRet_Modified; } return CrStRet_Unchanged; }
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; }
TbBool creature_scavenge_from_creature_pool(struct Thing *calltng) { struct Room *room; struct Coord3d pos; room = get_room_thing_is_on(calltng); if (!room_initially_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); return false; } if (game.pool.crtr_kind[calltng->model] <= 0) { ERRORLOG("Tried to generate %s but it is not in pool",thing_model_name(calltng)); return false; } if ( !find_random_valid_position_for_thing_in_room(calltng, room, &pos) ) { ERRORLOG("Could not find valid position for thing to be generated"); return false; } struct Thing *scavtng; scavtng = create_creature(&pos, calltng->model, calltng->owner); if (thing_is_invalid(scavtng)) { ERRORLOG("Tried to generate %s but creation failed",thing_model_name(calltng)); return false; } if (!remove_creature_from_generate_pool(calltng->model)) { ERRORLOG("Could not remove %s from pool",thing_model_name(calltng)); return false; } { struct Dungeon *dungeon; dungeon = get_dungeon(calltng->owner); dungeon->creatures_scavenge_gain++; } internal_set_thing_state(scavtng, CrSt_CreatureScavengedReappear); return true; }
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; }
void process_creature_in_training_room(struct Thing *thing, struct Room *room) { static const struct Around corners[] = { {1, 2}, {0, 1}, {1, 0}, {2, 1}, }; struct CreatureControl *cctrl; struct CreatureStats *crstat; struct Thing *traintng; struct Thing *crtng; struct CreatureControl *cctrl2; struct Coord3d pos; long speed,dist; long i; cctrl = creature_control_get_from_thing(thing); SYNCDBG(8,"Starting %s mode %d",thing_model_name(thing),(int)cctrl->training.mode); //_DK_process_creature_in_training_room(thing, room); return; cctrl->field_4A = 0; switch (cctrl->training.mode) { case CrTrMd_SearchForTrainPost: // While we're in an instance, just wait if (cctrl->instance_id != CrInst_NULL) break; // On timeout, search for nearby training posts to start training ASAP if (cctrl->training.search_timeout < 1) { SYNCDBG(6,"Search timeout - selecting post nearest to (%d,%d)",(int)thing->mappos.x.stl.num, (int)thing->mappos.y.stl.num); setup_training_search_for_post(thing); cctrl->training.search_timeout = 100; break; } // Do a moving step cctrl->training.search_timeout--; speed = get_creature_speed(thing); i = creature_move_to(thing, &cctrl->moveto_pos, speed, 0, 0); if (i == 1) { // Move target is reached - find a training post which is supposed to be around here traintng = find_training_post_just_next_to_creature(thing); if (thing_is_invalid(traintng)) { SYNCDBG(6,"Reached (%d,%d) but there's no training post there",(int)thing->mappos.x.stl.num, (int)thing->mappos.y.stl.num); setup_move_to_new_training_position(thing, room, false); break; } // Found - go to next mode cctrl->training.mode = CrTrMd_SelectPositionNearTrainPost; cctrl->training.search_timeout = 50; } else if (i == -1) { ERRORLOG("Cannot get to (%d,%d) in the training room",(int)cctrl->moveto_pos.x.stl.num,(int)cctrl->moveto_pos.y.stl.num); set_start_state(thing); } break; case CrTrMd_SelectPositionNearTrainPost: for (i=0; i < 4; i++) { long slb_x,slb_y; long stl_x,stl_y; struct SlabMap *slb; slb_x = subtile_slab_fast(thing->mappos.x.stl.num) + (long)small_around[i].delta_x; slb_y = subtile_slab_fast(thing->mappos.y.stl.num) + (long)small_around[i].delta_y; slb = get_slabmap_block(slb_x,slb_y); if ((slb->kind != SlbT_TRAINING) || (slabmap_owner(slb) != thing->owner)) continue; stl_x = slab_subtile(slb_x,corners[i].delta_x); stl_y = slab_subtile(slb_y,corners[i].delta_y); traintng = INVALID_THING; // Check if any other creature is using that post; allow only unused posts crtng = get_creature_of_model_training_at_subtile_and_owned_by(stl_x, stl_y, -1, thing->owner, thing->index); if (thing_is_invalid(crtng)) { traintng = get_object_at_subtile_of_model_and_owned_by(slab_subtile_center(slb_x), slab_subtile_center(slb_y), 31, thing->owner); } if (!thing_is_invalid(traintng)) { cctrl->training.pole_stl_x = slab_subtile_center(subtile_slab_fast(thing->mappos.x.stl.num)); cctrl->training.pole_stl_y = slab_subtile_center(subtile_slab_fast(thing->mappos.y.stl.num)); cctrl->moveto_pos.x.stl.num = stl_x; cctrl->moveto_pos.y.stl.num = stl_y; cctrl->moveto_pos.x.stl.pos = 128; cctrl->moveto_pos.y.stl.pos = 128; cctrl->moveto_pos.z.val = get_thing_height_at(thing, &cctrl->moveto_pos); if (thing_in_wall_at(thing, &cctrl->moveto_pos)) { ERRORLOG("Illegal setup to (%d,%d)", (int)cctrl->moveto_pos.x.stl.num, (int)cctrl->moveto_pos.y.stl.num); break; } cctrl->training.mode = CrTrMd_MoveToTrainPost; break; } } if (cctrl->training.mode == CrTrMd_SelectPositionNearTrainPost) setup_move_to_new_training_position(thing, room, 1); break; case CrTrMd_MoveToTrainPost: speed = get_creature_speed(thing); i = creature_move_to(thing, &cctrl->moveto_pos, speed, 0, 0); if (i == 1) { // If there's already someone training at that position, go somewhere else crtng = get_creature_of_model_training_at_subtile_and_owned_by(thing->mappos.x.stl.num, thing->mappos.y.stl.num, -1, thing->owner, thing->index); if (!thing_is_invalid(crtng)) { setup_move_to_new_training_position(thing, room, 1); break; } // Otherwise, train at this position cctrl->training.mode = CrTrMd_TurnToTrainPost; } else if (i == -1) { ERRORLOG("Cannot get where we're going in the training room."); set_start_state(thing); } break; case CrTrMd_TurnToTrainPost: pos.x.val = subtile_coord_center(cctrl->training.pole_stl_x); pos.y.val = subtile_coord_center(cctrl->training.pole_stl_y); if (creature_turn_to_face(thing, &pos) < 56) { cctrl->training.mode = CrTrMd_DoTrainWithTrainPost; cctrl->training.train_timeout = 75; } break; case CrTrMd_PartnerTraining: if (cctrl->training.partner_idx == 0) { setup_move_to_new_training_position(thing, room, false); return; } crtng = thing_get(cctrl->training.partner_idx); TRACE_THING(crtng); if (!thing_exists(crtng) || (get_creature_state_besides_move(crtng) != CrSt_Training) || (crtng->creation_turn != cctrl->training.partner_creation)) { SYNCDBG(8,"The %s cannot start partner training - creature to train with is gone.",thing_model_name(thing)); setup_move_to_new_training_position(thing, room, false); return; } cctrl2 = creature_control_get_from_thing(crtng); if (cctrl2->training.partner_idx != thing->index) { SYNCDBG(6,"The %s cannot start partner training - %s changed the partner.",thing_model_name(thing),thing_model_name(crtng)); cctrl->training.partner_idx = 0; setup_move_to_new_training_position(thing, room, false); break; } if (get_room_thing_is_on(crtng) != room) { SYNCDBG(8,"The %s cannot start partner training - partner has left the room.",thing_model_name(thing)); cctrl->training.partner_idx = 0; cctrl2->training.partner_idx = 0; setup_move_to_new_training_position(thing, room, false); break; } crstat = creature_stats_get_from_thing(thing); dist = get_combat_distance(thing, crtng); if (dist > 284) { if (creature_move_to(thing, &crtng->mappos, get_creature_speed(thing), 0, 0) == -1) { WARNLOG("The %s cannot navigate to training partner",thing_model_name(thing)); setup_move_to_new_training_position(thing, room, false); cctrl->training.partner_idx = 0; } } else if (dist >= 156) { if (creature_turn_to_face(thing, &crtng->mappos) < 56) { cctrl->training.train_timeout--; if (cctrl->training.train_timeout > 0) { if ((cctrl->instance_id == CrInst_NULL) && ((cctrl->training.train_timeout % 8) == 0)) { set_creature_instance(thing, CrInst_SWING_WEAPON_SWORD, 1, 0, 0); } } else { if (cctrl->instance_id == CrInst_NULL) { setup_move_to_new_training_position(thing, room, false); cctrl->training.partner_idx = 0; } else { cctrl->training.train_timeout = 1; } cctrl->exp_points += (room->efficiency * crstat->training_value); } } } else { creature_retreat_from_combat(thing, crtng, 33, 0); } break; case CrTrMd_DoTrainWithTrainPost: if (cctrl->training.train_timeout > 0) { // While training timeout is positive, continue initiating the train instances cctrl->training.train_timeout--; if ((cctrl->instance_id == CrInst_NULL) && ((cctrl->training.train_timeout % 8) == 0)) { set_creature_instance(thing, CrInst_SWING_WEAPON_SWORD, 1, 0, 0); } } else { // Wait for the instance to end, then select new move position if (cctrl->instance_id != CrInst_NULL) { cctrl->training.train_timeout = 0; } else { cctrl->training.train_timeout = 0; setup_move_to_new_training_position(thing, room, true); } } break; default: WARNLOG("Invalid %s training mode %d; reset",thing_model_name(thing),(int)cctrl->training.mode); cctrl->training.mode = CrTrMd_SearchForTrainPost; cctrl->training.search_timeout = 0; break; } SYNCDBG(18,"End"); }
/** * Finds a random training post near to the current position of given creature. * Used when finding a training post seems to be taking too long; in that case, creature should start training with a nearest post. * Note that this routine does not always select the nearest post - it is enough if it's 3 subtiles away. * * @param creatng The creature who wish to train with training post. */ void setup_training_search_for_post(struct Thing *creatng) { struct Room *room; struct Thing *traintng; struct Thing *thing; long start_slab; long min_distance,dist; long slb_x,slb_y; long i,k; room = get_room_thing_is_on(creatng); // Let's start from a random slab slb_x = -1; slb_y = -1; min_distance = LONG_MAX; traintng = INVALID_THING; start_slab = ACTION_RANDOM(room->slabs_count); k = start_slab; i = room->slabs_list; while (i != 0) { slb_x = slb_num_decode_x(i); slb_y = slb_num_decode_y(i); i = get_next_slab_number_in_room(i); if (k <= 0) break; k--; } // Got random starting slab, now sweep room slabs from it thing = INVALID_THING; k = room->slabs_count; i = get_slab_number(slb_x,slb_y); while (k > 0) { slb_x = slb_num_decode_x(i); slb_y = slb_num_decode_y(i); i = get_next_slab_number_in_room(i); if (i == 0) i = room->slabs_list; // Per room tile code - find a nearest training post thing = get_object_at_subtile_of_model_and_owned_by(slab_subtile_center(slb_x), slab_subtile_center(slb_y), 31, creatng->owner); if (!thing_is_invalid(thing)) { dist = get_2d_distance(&creatng->mappos, &thing->mappos); if (dist < min_distance) { traintng = thing; min_distance = dist; if (min_distance < (3<<8)) break; } } // Per room tile code ends k--; } // Got trainer (or not...), now do the correct action if (thing_is_invalid(traintng)) { SYNCDBG(6,"Room no longer have training post, moving somewhere else."); setup_move_to_new_training_position(creatng, room, true); } else { i = get_subtile_number(traintng->mappos.x.stl.num,traintng->mappos.y.stl.num); setup_training_move_near(creatng, i); } }
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; }