short move_to_position(struct Thing *creatng) { CreatureStateCheck callback; struct CreatureControl *cctrl; struct StateInfo *stati; long move_result; CrCheckRet state_check; long speed; TRACE_THING(creatng); cctrl = creature_control_get_from_thing(creatng); speed = get_creature_speed(creatng); SYNCDBG(18,"Starting to move %s index %d into (%d,%d)",thing_model_name(creatng),(int)creatng->index,(int)cctrl->moveto_pos.x.stl.num,(int)cctrl->moveto_pos.y.stl.num); // Try teleporting the creature if (creature_move_to_using_teleport(creatng, &cctrl->moveto_pos, speed)) { SYNCDBG(8,"Teleporting %s index %d owner %d into (%d,%d) for %s",thing_model_name(creatng),(int)creatng->index,(int)creatng->owner, (int)cctrl->moveto_pos.x.stl.num,(int)cctrl->moveto_pos.y.stl.num,creature_state_code_name(creatng->continue_state)); return 1; } move_result = creature_move_to(creatng, &cctrl->moveto_pos, speed, cctrl->move_flags, 0); state_check = CrCkRet_Available; stati = get_thing_continue_state_info(creatng); if (!state_info_invalid(stati)) { callback = stati->move_check; if (callback != NULL) { SYNCDBG(18,"Doing move check callback for continue state %s",creature_state_code_name(creatng->continue_state)); state_check = callback(creatng); } } if (state_check == CrCkRet_Available) { // If moving was successful if (move_result == 1) { // Back to "main state" internal_set_thing_state(creatng, creatng->continue_state); return CrStRet_Modified; } // If moving failed, do a reset if (move_result == -1) { CrtrStateId cntstat; cntstat = creatng->continue_state; internal_set_thing_state(creatng, cntstat); set_start_state(creatng); SYNCDBG(8,"Couldn't move %s to place required for state %s; reset to state %s",thing_model_name(creatng),creature_state_code_name(cntstat),creatrtng_actstate_name(creatng)); return CrStRet_ResetOk; } // If continuing the job, check for job stress process_job_stress_and_going_postal(creatng); } switch (state_check) { case CrCkRet_Deleted: return CrStRet_Deleted; case CrCkRet_Available: return CrStRet_Modified; default: return CrStRet_ResetOk; } }
CrCheckRet process_scavenge_function(struct Thing *calltng) { SYNCDBG(18,"Starting for %s owner %d",thing_model_name(calltng),(int)calltng->owner); //return _DK_process_scavenge_function(thing); struct CreatureControl *callctrl; callctrl = creature_control_get_from_thing(calltng); struct Dungeon *calldngn; struct Room *room; calldngn = get_dungeon(calltng->owner); room = get_room_creature_works_in(calltng); if ( !room_still_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); set_start_state(calltng); return CrCkRet_Continue; } struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(calltng); if (!player_can_afford_to_scavenge_creature(calltng)) { if (is_my_player_number(calltng->owner)) output_message(SMsg_NoGoldToScavenge, 500, 1); set_start_state(calltng); return CrCkRet_Continue; } if (calldngn->scavenge_counters_turn != game.play_gameturn) { reset_scavenge_counts(calldngn); } long work_value; work_value = compute_creature_work_value(crstat->scavenge_value*256, room->efficiency, callctrl->explevel); work_value = process_work_speed_on_work_value(calltng, work_value); SYNCDBG(9,"The %s index %d owner %d produced %d scavenge points",thing_model_name(calltng),(int)calltng->index,(int)calltng->owner,(int)work_value); struct Thing *scavtng; scavtng = get_scavenger_target(calltng); if (!thing_is_invalid(scavtng)) { process_scavenge_creature_from_level(scavtng, calltng, work_value); } else if (can_scavenge_creature_from_pool(calldngn, calltng->model)) { process_scavenge_creature_from_pool(calltng, work_value); } else { if (crstat->entrance_force) { calldngn->field_1485++; } return 0; } callctrl->field_82++; if (callctrl->field_82 > game.scavenge_cost_frequency) { callctrl->field_82 -= game.scavenge_cost_frequency; if (take_money_from_dungeon(calltng->owner, crstat->scavenger_cost, 1) < 0) { ERRORLOG("Cannot take %d gold from dungeon %d",(int)crstat->scavenger_cost,(int)calltng->owner); } create_price_effect(&calltng->mappos, calltng->owner, crstat->scavenger_cost); } return 0; }
TbBool setup_person_move_to_position_f(struct Thing *thing, MapSubtlCoord stl_x, MapSubtlCoord stl_y, NaviRouteFlags flags, const char *func_name) { struct CreatureControl *cctrl; struct Coord3d locpos; SYNCDBG(18,"%s: Moving %s index %d to (%d,%d)",func_name,thing_model_name(thing),(int)thing->index,(int)stl_x,(int)stl_y); TRACE_THING(thing); locpos.x.val = subtile_coord_center(stl_x); locpos.y.val = subtile_coord_center(stl_y); locpos.z.val = thing->mappos.z.val; locpos.z.val = get_thing_height_at(thing, &locpos); cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) { WARNLOG("%s: Tried to move invalid creature to (%d,%d)",func_name,(int)stl_x,(int)stl_y); return false; } if (thing_in_wall_at(thing, &locpos)) { SYNCDBG(16,"%s: The %s would be trapped in wall at (%d,%d)",func_name,thing_model_name(thing),(int)stl_x,(int)stl_y); return false; } if (!creature_can_navigate_to_with_storage_f(thing, &locpos, flags, func_name)) { SYNCDBG(19,"%s: The %s cannot reach subtile (%d,%d)",func_name,thing_model_name(thing),(int)stl_x,(int)stl_y); return false; } cctrl->move_flags = flags; internal_set_thing_state(thing, CrSt_MoveToPosition); cctrl->moveto_pos.x.val = locpos.x.val; cctrl->moveto_pos.y.val = locpos.y.val; cctrl->moveto_pos.z.val = locpos.z.val; SYNCDBG(19,"%s: Done",func_name); return true; }
long instf_attack_room_slab(struct Thing *creatng, long *param) { TRACE_THING(creatng); struct Room *room; room = get_room_thing_is_on(creatng); if (room_is_invalid(room)) { ERRORLOG("The %s index %d is not on room",thing_model_name(creatng),(int)creatng->index); return 0; } SYNCDBG(8,"Executing for %s index %d",thing_model_name(creatng),(int)creatng->index); 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 index %d",room_code_name(room->kind),thing_model_name(creatng),(int)creatng->index); return 0; } create_effect(&creatng->mappos, TngEff_Unknown03, creatng->owner); thing_play_sample(creatng, 47, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); return 1; }
TbBool good_setup_wander_to_dungeon_heart(struct Thing *creatng, PlayerNumber plyr_idx) { struct PlayerInfo *player; SYNCDBG(18,"Starting"); TRACE_THING(creatng); if (creatng->owner == plyr_idx) { ERRORLOG("The %s tried to wander to own (%d) heart", thing_model_name(creatng), (int)plyr_idx); return false; } player = get_player(plyr_idx); if (!player_exists(player)) { WARNLOG("The %s tried to wander to inactive player (%d) heart", thing_model_name(creatng), (int)plyr_idx); return false; } struct Thing *heartng; heartng = get_player_soul_container(plyr_idx); TRACE_THING(heartng); if (thing_is_invalid(heartng)) { WARNLOG("The %s tried to wander to player %d which has no heart", thing_model_name(creatng), (int)plyr_idx); return false; } set_creature_object_combat(creatng, heartng); return true; }
TbBool good_setup_loot_research_room(struct Thing *thing, long dngn_id) { struct CreatureControl *cctrl; struct Room *room; room = find_random_room_creature_can_navigate_to(thing, dngn_id, RoK_LIBRARY, NavRtF_Default); if (room_is_invalid(room)) { SYNCDBG(6,"No accessible player %d library found",(int)dngn_id); return false; } struct Coord3d pos; if (!find_random_valid_position_for_thing_in_room(thing, room, &pos)) { SYNCDBG(6,"No position for %s index %d in %s owned by player %d", thing_model_name(thing),(int)thing->index,room_code_name(room->kind),(int)room->owner); return false; } if (!setup_person_move_to_coord(thing, &pos, NavRtF_Default)) { SYNCDBG(6,"Cannot setup move %s index %d to %s owned by player %d", thing_model_name(thing),(int)thing->index,room_code_name(room->kind),(int)room->owner); return false; } cctrl = creature_control_get_from_thing(thing); thing->continue_state = CrSt_CreatureSearchForSpellToStealInRoom; cctrl->target_room_id = room->index; return true; }
TbBool setup_person_move_close_to_position(struct Thing *thing, MapSubtlCoord stl_x, MapSubtlCoord stl_y, NaviRouteFlags flags) { struct CreatureControl *cctrl; struct Coord3d trgpos; struct Coord3d navpos; SYNCDBG(18,"Moving %s index %d to (%d,%d)",thing_model_name(thing),(int)thing->index,(int)stl_x,(int)stl_y); trgpos.x.val = subtile_coord_center(stl_x); trgpos.y.val = subtile_coord_center(stl_y); trgpos.z.val = thing->mappos.z.val; cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) { WARNLOG("Tried to move invalid creature to (%d,%d)",(int)stl_x,(int)stl_y); return false; } get_nearest_navigable_point_for_thing(thing, &trgpos, &navpos, flags); if (!creature_can_navigate_to_with_storage(thing, &navpos, flags)) { SYNCDBG(19,"The %s cannot reach subtile (%d,%d)",thing_model_name(thing),(int)stl_x,(int)stl_y); return false; } cctrl->move_flags = flags; internal_set_thing_state(thing, CrSt_MoveToPosition); cctrl->moveto_pos.x.val = navpos.x.val; cctrl->moveto_pos.y.val = navpos.y.val; cctrl->moveto_pos.z.val = navpos.z.val; return true; }
struct Thing *select_scavenger_target(const struct Thing *calltng) { long weakpts; struct Thing *weaktng; weaktng = INVALID_THING; weakpts = LONG_MAX; struct Thing *thing; unsigned long k; int i; SYNCDBG(18,"Starting"); const struct StructureList *slist; slist = get_list_for_thing_class(TCls_Creature); k = 0; i = slist->index; while (i != 0) { thing = thing_get(i); if (thing_is_invalid(thing)) { ERRORLOG("Jump to invalid thing detected"); break; } i = thing->next_of_class; // Per-thing code if (thing_is_valid_scavenge_target(calltng, thing)) { SYNCDBG(18,"The %s index %d owner %d is valid target for %s index %d owner %d", thing_model_name(thing),(int)thing->index,(int)thing->owner, thing_model_name(calltng),(int)calltng->index,(int)calltng->owner); struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); if (game.play_gameturn - cctrl->temple_cure_gameturn > game.temple_scavenge_protection_turns) { long thingpts; thingpts = calculate_correct_creature_scavenge_required(thing, calltng->owner); if (weakpts > thingpts) { weakpts = thingpts; weaktng = thing; } } } // Per-thing code ends k++; if (k > slist->count) { ERRORLOG("Infinite loop detected when sweeping things list"); break; } } SYNCDBG(18,"The weakest valid target for %s index %d owner %d is %s index %d owner %d", thing_model_name(calltng),(int)calltng->index,(int)calltng->owner, thing_model_name(weaktng),(int)weaktng->index,(int)weaktng->owner); return weaktng; }
void setup_move_to_new_training_position(struct Thing *thing, struct Room *room, unsigned long restart) { struct CreatureControl *cctrl; struct CreatureStats *crstat; struct Thing *prtng; struct CreatureControl *prctrl; struct Coord3d pos; long i; SYNCDBG(8,"Starting for %s",thing_model_name(thing)); //_DK_setup_move_to_new_training_position(thing, room, a3); cctrl = creature_control_get_from_thing(thing); crstat = creature_stats_get_from_thing(thing); if ( restart ) cctrl->training.search_timeout = 50; // Try partner training if ((crstat->partner_training > 0) && (ACTION_RANDOM(100) < crstat->partner_training)) { prtng = get_creature_in_training_room_which_could_accept_partner(room, thing); if (!thing_is_invalid(prtng)) { SYNCDBG(7,"The %s found %s as training partner.",thing_model_name(thing),thing_model_name(prtng)); prctrl = creature_control_get_from_thing(prtng); prctrl->training.mode = CrTrMd_PartnerTraining; prctrl->training.train_timeout = 75; prctrl->training.partner_idx = thing->index; prctrl->training.partner_creation = thing->creation_turn; cctrl->training.mode = CrTrMd_PartnerTraining; cctrl->training.train_timeout = 75; cctrl->training.partner_idx = prtng->index; cctrl->training.partner_creation = prtng->creation_turn; return; } } // No partner - train at some random position cctrl->training.mode = CrTrMd_SearchForTrainPost; if (find_random_valid_position_for_thing_in_room(thing, room, &pos)) { SYNCDBG(8,"Going to train at (%d,%d)",(int)pos.x.stl.num,(int)pos.y.stl.num); i = get_subtile_number(pos.x.stl.num,pos.y.stl.num); setup_training_move(thing, i); } else { SYNCDBG(8,"No new position found, staying at (%d,%d)",(int)cctrl->moveto_pos.x.stl.num,(int)cctrl->moveto_pos.x.stl.num); } if (cctrl->instance_id == CrInst_NULL) { set_creature_instance(thing, CrInst_SWING_WEAPON_SWORD, 1, 0, 0); } }
struct Thing *create_crate_in_workshop(struct Room *room, ThingModel cratngmodel, MapSubtlCoord stl_x, MapSubtlCoord stl_y) { struct Coord3d pos; struct Thing *cratetng; if (!room_role_matches(room->kind, RoRoF_CratesStorage)) { SYNCDBG(4,"Crate %s cannot be created in a %s owned by player %d, wrong room",object_code_name(cratngmodel),room_code_name(room->kind),(int)room->owner); return INVALID_THING; } pos.x.val = subtile_coord_center(stl_x); pos.y.val = subtile_coord_center(stl_y); pos.z.val = 0; cratetng = create_object(&pos, cratngmodel, room->owner, -1); if (thing_is_invalid(cratetng)) { return INVALID_THING; } // Neutral thing do not need any more processing if (is_neutral_thing(cratetng) || !player_exists(get_player(room->owner))) { return cratetng; } if (!add_workshop_object_to_workshop(room, cratetng)) { ERRORLOG("Could not fit %s in %s index %d", thing_model_name(cratetng),room_code_name(room->kind),(int)room->index); //remove_item_from_room_capacity(room); -- no need, it was not added destroy_object(cratetng); return INVALID_THING; } ThingClass tngclass; ThingModel tngmodel; tngclass = crate_thing_to_workshop_item_class(cratetng); tngmodel = crate_thing_to_workshop_item_model(cratetng); add_workshop_item_to_amounts(cratetng->owner, tngclass, tngmodel); return cratetng; }
struct Room * find_nearest_navigable_room_for_thing_with_capacity_and_closer_than(struct Thing *thing, PlayerNumber owner, RoomKind rkind, unsigned char nav_flags, long used, long *neardistance) { struct Dungeon *dungeon; struct Room *nearoom; long distance; int i; SYNCDBG(18,"Searching for %s navigable by %s index %d",room_code_name(rkind),thing_model_name(thing),(int)thing->index); dungeon = get_dungeon(owner); nearoom = INVALID_ROOM; distance = *neardistance; i = dungeon->room_kind[rkind]; while (i != 0) { struct Room *room; room = find_next_navigable_room_for_thing_with_capacity_and_closer_than(thing, i, nav_flags, used, &distance); if (room_is_invalid(room)) { break; } // Found closer room i = room->next_of_owner; nearoom = room; } *neardistance = distance; return nearoom; }
TbBool send_creature_to_job_near_position(struct Thing *creatng, MapSubtlCoord stl_x, MapSubtlCoord stl_y, CreatureJob new_job) { SYNCDBG(6,"Starting for %s (owner %d) and job %s",thing_model_name(creatng),(int)creatng->owner,creature_job_code_name(new_job)); struct CreatureJobConfig *jobcfg; jobcfg = get_config_for_job(new_job); if (jobcfg->func_cord_assign != NULL) { if (jobcfg->func_cord_assign(creatng, stl_x, stl_y, new_job)) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); // Set computer control accordingly to job flags if ((get_flags_for_job(new_job) & JoKF_NoSelfControl) != 0) { cctrl->flgfield_1 |= CCFlg_NoCompControl; } else { cctrl->flgfield_1 &= ~CCFlg_NoCompControl; } // If a new task isn't a work-in-group thing, remove the creature from group if ((get_flags_for_job(new_job) & JoKF_NoGroups) != 0) { if (creature_is_group_member(creatng)) { remove_creature_from_group(creatng); } } return true; } } else { ERRORLOG("Cannot start %s for %s (owner %d); job has no coord-based assign",creature_job_code_name(new_job),thing_model_name(creatng),(int)creatng->owner); } return false; }
short good_drops_gold(struct Thing *thing) { // Debug code to find incorrect states if (!is_hero_thing(thing)) { ERRORLOG("Non hero thing %ld, %s, owner %ld - reset",(long)thing->index,thing_model_name(thing),(long)thing->owner); set_start_state(thing); erstat_inc(ESE_BadCreatrState); return 0; } //return _DK_good_drops_gold(thing); GoldAmount amount; amount = game.pot_of_gold_holds; if (thing->creature.gold_carried <= game.pot_of_gold_holds) amount = thing->creature.gold_carried; struct Thing *gldtng; gldtng = create_object(&thing->mappos, 6, thing->owner, -1); if (thing_is_invalid(gldtng)) { return 0; } gldtng->valuable.gold_stored = amount; thing->creature.gold_carried -= amount; // Update size of the gold object add_gold_to_pile(gldtng, 0); internal_set_thing_state(thing, CrSt_GoodBackAtStart); return 1; }
TbBool attempt_job_work_in_room_for_player(struct Thing *creatng, PlayerNumber plyr_idx, CreatureJob new_job) { struct Coord3d pos; struct Room *room; RoomKind rkind; rkind = get_room_for_job(new_job); SYNCDBG(6,"Starting for %s (owner %d) and job %s in %s room",thing_model_name(creatng),(int)creatng->owner,creature_job_code_name(new_job),room_code_name(rkind)); if ((get_flags_for_job(new_job) & JoKF_NeedsCapacity) != 0) { room = find_nearest_room_for_thing_with_spare_capacity(creatng, creatng->owner, rkind, NavRtF_Default, 1); } else { room = find_nearest_room_for_thing(creatng, creatng->owner, rkind, NavRtF_Default); } if (room_is_invalid(room)) { return false; } if (!find_random_valid_position_for_thing_in_room(creatng, room, &pos)) { return false; } if (get_arrive_at_state_for_job(new_job) == CrSt_Unused) { ERRORLOG("No arrive at state for job %s in %s room",creature_job_code_name(new_job),room_code_name(room->kind)); return false; } if (!setup_person_move_to_coord(creatng, &pos, NavRtF_Default)) { return false; } struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); creatng->continue_state = get_arrive_at_state_for_job(new_job); cctrl->target_room_id = room->index; return true; }
TbBool good_setup_attack_rooms(struct Thing *creatng, long dngn_id) { struct Room *room; struct CreatureControl *cctrl; struct Coord3d pos; room = find_nearest_room_for_thing_excluding_two_types(creatng, dngn_id, 7, 1, 1); if (room_is_invalid(room)) { return false; } if (!find_random_valid_position_for_thing_in_room(creatng, room, &pos) || !creature_can_navigate_to_with_storage(creatng, &pos, NavRtF_NoOwner) ) { ERRORLOG("The %s cannot destroy %s because it can't reach position within it",thing_model_name(creatng),room_code_name(room->kind)); return false; } if (!setup_random_head_for_room(creatng, room, NavRtF_NoOwner)) { ERRORLOG("The %s cannot destroy %s because it can't head for it",thing_model_name(creatng),room_code_name(room->kind)); return false; } cctrl = creature_control_get_from_thing(creatng); creatng->continue_state = CrSt_GoodArrivedAtAttackRoom; cctrl->target_room_id = room->index; return true; }
short good_leave_through_exit_door(struct Thing *thing) { struct CreatureControl *cctrl; struct Thing *tmptng; // Debug code to find incorrect states if (!is_hero_thing(thing)) { ERRORLOG("Non hero thing %ld, %s, owner %ld - reset",(long)thing->index,thing_model_name(thing),(long)thing->owner); set_start_state(thing); erstat_inc(ESE_BadCreatrState); return false; } //return _DK_good_leave_through_exit_door(thing); tmptng = find_base_thing_on_mapwho(TCls_Object, 49, thing->mappos.x.stl.num, thing->mappos.y.stl.num); if (thing_is_invalid(tmptng)) { return 0; } cctrl = creature_control_get_from_thing(thing); thing->creature.gold_carried = 0; cctrl->field_282 = game.hero_door_wait_time; cctrl->byte_8A = tmptng->creation_turn; place_thing_in_creature_controlled_limbo(thing); internal_set_thing_state(thing, CrSt_GoodWaitInExitDoor); return 1; }
long creature_move_direct_line_backwards(struct Thing *thing, struct Coord3d *nextpos, MoveSpeed speed) { if (creature_turn_to_face_backwards(thing, nextpos) > 0) { // Creature is turning - don't let it move creature_set_speed(thing, 0); return 2; } struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); creature_set_speed(thing, -speed); cctrl->flgfield_2 |= TF2_Unkn01; if (get_2d_box_distance(&thing->mappos, nextpos) > -2*cctrl->move_speed) { ERRORDBG(3,"The %s index %d tried to reach (%d,%d) from (%d,%d) with excessive backward speed", thing_model_name(thing),(int)thing->index,(int)nextpos->x.stl.num,(int)nextpos->y.stl.num, (int)thing->mappos.x.stl.num,(int)thing->mappos.y.stl.num); cctrl->moveaccel.x.val = distance_with_angle_to_coord_x(cctrl->move_speed, thing->move_angle_xy); cctrl->moveaccel.y.val = distance_with_angle_to_coord_y(cctrl->move_speed, thing->move_angle_xy); cctrl->moveaccel.z.val = 0; return 1; } else { cctrl->moveaccel.x.val = nextpos->x.val - (MapCoordDelta)thing->mappos.x.val; cctrl->moveaccel.y.val = nextpos->y.val - (MapCoordDelta)thing->mappos.y.val; cctrl->moveaccel.z.val = 0; return 0; } }
void process_creature_instance(struct Thing *thing) { struct CreatureControl *cctrl; struct InstanceInfo *inst_inf; SYNCDBG(19,"Starting for %s index %d instance %d",thing_model_name(thing),(int)thing->index,(int)cctrl->instance_id); TRACE_THING(thing); cctrl = creature_control_get_from_thing(thing); if (cctrl->instance_id != CrInst_NULL) { cctrl->inst_turn++; if (cctrl->inst_turn == cctrl->inst_action_turns) { inst_inf = creature_instance_info_get(cctrl->instance_id); if (inst_inf->func_cb != NULL) { SYNCDBG(18,"Executing instance %d for %s index %d.",(int)cctrl->instance_id,thing_model_name(thing),(int)thing->index); inst_inf->func_cb(thing, inst_inf->func_params); } } if (cctrl->inst_turn >= cctrl->inst_total_turns) { if (cctrl->inst_repeat) { cctrl->inst_turn--; cctrl->inst_repeat = 0; return; } cctrl->instance_use_turn[cctrl->instance_id] = game.play_gameturn; cctrl->instance_id = CrInst_NULL; } cctrl->inst_repeat = 0; } }
TbBool attempt_job_sleep_in_lair_near_pos(struct Thing *creatng, MapSubtlCoord stl_x, MapSubtlCoord stl_y, CreatureJob new_job) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); SYNCDBG(16,"Starting for %s (owner %d) and job %s",thing_model_name(creatng),(int)creatng->owner,creature_job_code_name(new_job)); struct Room *room; room = subtile_room_get(stl_x, stl_y); if (get_arrive_at_state_for_job(new_job) == CrSt_Unused) { ERRORLOG("No arrive at state for job %s in %s room",creature_job_code_name(new_job),room_code_name(room->kind)); return false; } cctrl->slap_turns = 0; cctrl->max_speed = calculate_correct_creature_maxspeed(creatng); if (creature_has_lair_room(creatng) && (room->index == cctrl->lair_room_id)) { if (creature_move_to_home_lair(creatng)) { creatng->continue_state = CrSt_CreatureGoingHomeToSleep; return 1; } } struct Coord3d pos; if (find_first_valid_position_for_thing_in_room(creatng, room, &pos) && setup_person_move_to_coord(creatng, &pos, NavRtF_Default)) { creatng->continue_state = CrSt_CreatureChangeLair; cctrl->target_room_id = room->index; return 1; } return 0; }
long instf_creature_fire_shot(struct Thing *creatng, long *param) { struct CreatureControl *cctrl; struct Thing *target; int i; TRACE_THING(creatng); cctrl = creature_control_get_from_thing(creatng); if (cctrl->targtng_idx <= 0) { if ((creatng->alloc_flags & TAlF_IsControlled) == 0) i = 4; else i = 1; } else if ((creatng->alloc_flags & TAlF_IsControlled) != 0) { target = thing_get(cctrl->targtng_idx); TRACE_THING(target); if (target->class_id == TCls_Object) i = 1; else i = 2; } else { target = thing_get(cctrl->targtng_idx); TRACE_THING(target); if (target->class_id == TCls_Object) i = 1; else if (target->owner == creatng->owner) i = 2; else i = 4; } if (cctrl->targtng_idx > 0) { target = thing_get(cctrl->targtng_idx); SYNCDBG(8,"The %s index %d fires %s at %s index %d",thing_model_name(creatng),(int)creatng->index,shot_code_name(*param),thing_model_name(target),(int)target->index); TRACE_THING(target); } else { target = NULL; SYNCDBG(8,"The %s index %d fires %s",thing_model_name(creatng),(int)creatng->index,shot_code_name(*param)); } creature_fire_shot(creatng, target, *param, 1, i); return 0; }
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; }
/** * Setups a wanderer creature to move to a random thing in given list. * @param first_thing_idx * @param wanderer * @return */ TbBool setup_wanderer_move_to_random_creature_from_list(long first_thing_idx, struct Thing *wanderer) { long possible_targets,target_match; possible_targets = get_wanderer_possible_targets_count_in_list(first_thing_idx,wanderer); // Select random target if (possible_targets < 1) { SYNCDBG(4,"The %s cannot wander to creature, there are no targets",thing_model_name(wanderer)); return false; } target_match = ACTION_RANDOM(possible_targets); if ( wander_to_specific_possible_target_in_list(first_thing_idx, wanderer, target_match) ) { return true; } WARNLOG("The %s index %d cannot wander to creature, it seem all %d creatures were not navigable", thing_model_name(wanderer),(int)wanderer->index,(int)possible_targets); return false; }
TbBool creature_can_navigate_to_with_storage_f(const struct Thing *creatng, const struct Coord3d *pos, NaviRouteFlags flags, const char *func_name) { AriadneReturn aret; NAVIDBG(8,"%s: Route for %s index %d from %3d,%3d to %3d,%3d", func_name, thing_model_name(creatng),(int)creatng->index, (int)creatng->mappos.x.stl.num, (int)creatng->mappos.y.stl.num, (int)pos->x.stl.num, (int)pos->y.stl.num); aret = ariadne_initialise_creature_route_f((struct Thing *)creatng, pos, get_creature_speed(creatng), flags, func_name); NAVIDBG(18,"Ariadne returned %d",(int)aret); return (aret == AridRet_OK); }
long creature_move_to_using_gates(struct Thing *thing, struct Coord3d *pos, MoveSpeed speed, long a4, NaviRouteFlags flags, TbBool backward) { struct Coord3d nextpos; AriadneReturn follow_result; long i; SYNCDBG(18,"Starting to move %s index %d from (%d,%d) to (%d,%d) with speed %d",thing_model_name(thing), (int)thing->index,(int)thing->mappos.x.stl.num,(int)thing->mappos.y.stl.num,(int)pos->x.stl.num,(int)pos->y.stl.num,(int)speed); TRACE_THING(thing); if ( backward ) { // Rotate the creature 180 degrees to trace route with forward move i = (thing->move_angle_xy + LbFPMath_PI); thing->move_angle_xy = i & LbFPMath_AngleMask; } follow_result = creature_follow_route_to_using_gates(thing, pos, &nextpos, speed, flags); SYNCDBG(18,"The %s index %d route result: %d, next pos (%d,%d)",thing_model_name(thing),(int)thing->index,(int)follow_result,(int)nextpos.x.stl.num,(int)nextpos.y.stl.num); if ( backward ) { // Rotate the creature back i = (thing->move_angle_xy + LbFPMath_PI); thing->move_angle_xy = i & LbFPMath_AngleMask; } if ((follow_result == AridRet_PartOK) || (follow_result == AridRet_Val2)) { creature_set_speed(thing, 0); return -1; } if (follow_result == AridRet_FinalOK) { return 1; } struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); if ( backward ) { creature_move_direct_line_backwards(thing, &nextpos, speed); SYNCDBG(18,"Backward target set, speed %d, accel (%d,%d)",(int)cctrl->move_speed,(int)cctrl->moveaccel.x.val,(int)cctrl->moveaccel.y.val); } else { creature_move_direct_line(thing, &nextpos, speed); SYNCDBG(18,"Forward target set, speed %d, accel (%d,%d)",(int)cctrl->move_speed,(int)cctrl->moveaccel.x.val,(int)cctrl->moveaccel.y.val); } return 0; }
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)); } }
short tunnelling(struct Thing *creatng) { struct SlabMap *slb; long speed; SYNCDBG(7,"Move %s from (%d,%d)",thing_model_name(creatng),(int)creatng->mappos.x.stl.num,(int)creatng->mappos.y.stl.num); //return _DK_tunnelling(creatng); speed = get_creature_speed(creatng); slb = get_slabmap_for_subtile(creatng->mappos.x.stl.num,creatng->mappos.y.stl.num); struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); struct Coord3d *pos; pos = &cctrl->moveto_pos; if (slabmap_owner(slb) == cctrl->party.target_plyr_idx) { internal_set_thing_state(creatng, CrSt_GoodDoingNothing); return 1; } long move_result; move_result = creature_tunnel_to(creatng, pos, speed); if (move_result == 1) { internal_set_thing_state(creatng, CrSt_TunnellerDoingNothing); return 1; } if (move_result == -1) { ERRORLOG("Bad place to tunnel to!"); set_start_state(creatng); creatng->continue_state = CrSt_Unused; return 0; } // Once per 128 turns, check if we've done digging and can now walk to the place if (((game.play_gameturn + creatng->index) & 0x7F) == 0) { if (creature_can_navigate_to(creatng, pos, NavRtF_Default)) { SYNCDBG(7,"The %s can now walk to (%d,%d), no need to tunnel",thing_model_name(creatng),(int)pos->x.stl.num,(int)pos->y.stl.num); return 1; } } SYNCDBG(7,"The %s cannot reach (%d,%d) by walk",thing_model_name(creatng),(int)pos->x.stl.num,(int)pos->y.stl.num); return 0; }
TbBool send_tunneller_to_point_in_dungeon(struct Thing *creatng, PlayerNumber plyr_idx, struct Coord3d *pos) { SYNCDBG(17,"Move %s to (%d,%d)",thing_model_name(creatng),(int)pos->x.stl.num,(int)pos->y.stl.num); struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); cctrl->party.target_plyr_idx = plyr_idx; setup_person_tunnel_to_position(creatng, pos->x.stl.num, pos->y.stl.num, 0); creatng->continue_state = CrSt_TunnellerDoingNothing; return true; }
TbBool good_setup_wander_to_exit(struct Thing *creatng) { struct Thing *gatetng; SYNCDBG(7,"Starting"); gatetng = find_hero_door_hero_can_navigate_to(creatng); if (thing_is_invalid(gatetng)) { SYNCLOG("Can't find any exit gate for hero %s.",thing_model_name(creatng)); return false; } if (!setup_person_move_to_coord(creatng, &gatetng->mappos, NavRtF_Default)) { WARNLOG("Hero %s index %d can't move to exit gate at (%d,%d).",thing_model_name(creatng), (int)gatetng->index, (int)gatetng->mappos.x.stl.num, (int)gatetng->mappos.y.stl.num); return false; } creatng->continue_state = CrSt_GoodLeaveThroughExitDoor; return true; }
short good_attack_room(struct Thing *thing) { // Debug code to find incorrect states if (!is_hero_thing(thing)) { ERRORLOG("Non hero %s index %d owner %d - reset",thing_model_name(thing),(int)thing->index,(int)thing->owner); set_start_state(thing); return 0; } //return _DK_good_attack_room(thing); MapSlabCoord base_slb_x,base_slb_y; base_slb_x = subtile_slab_fast(thing->mappos.x.stl.num); base_slb_y = subtile_slab_fast(thing->mappos.y.stl.num); struct Room *room; room = slab_room_get(base_slb_x, base_slb_y); // If the current tile can be destroyed if (room_exists(room) && (room->owner != thing->owner) && !room_cannot_vandalise(room->kind)) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); if (cctrl->instance_id == CrInst_NULL) { set_creature_instance(thing, CrInst_ATTACK_ROOM_SLAB, 1, 0, 0); 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; } // Otherwise, search around for a tile to destroy long m,n; m = ACTION_RANDOM(SMALL_AROUND_SLAB_LENGTH); for (n=0; n < SMALL_AROUND_SLAB_LENGTH; n++) { MapSlabCoord slb_x,slb_y; slb_x = base_slb_x + (long)small_around[m].delta_x; slb_y = base_slb_y + (long)small_around[m].delta_y; room = slab_room_get(slb_x, slb_y); if (room_exists(room) && (room->owner != thing->owner)) { if (setup_person_move_to_position(thing, slb_x, slb_y, NavRtF_Default)) { thing->continue_state = CrSt_GoodAttackRoom1; return 1; } } m = (m+1) % SMALL_AROUND_SLAB_LENGTH; } set_start_state(thing); return 0; }
/** * Returns any room of given kind and owner to which the thing can navigate. * * @param thing The thing to navigate into room. * @param owner Owner of the rooms to be checked. * @param rkind Room kind to be returned. * @param nav_flags Navigation flags, for checking if creature can reach the room. * @return Nearest room of given kind and owner, or invalid room if none found. */ struct Room *find_any_navigable_room_for_thing_closer_than(struct Thing *thing, PlayerNumber owner, RoomKind rkind, unsigned char nav_flags, long max_distance) { struct Dungeon *dungeon; dungeon = get_dungeon(owner); SYNCDBG(18,"Searching for %s navigable by %s index %d",room_code_name(rkind),thing_model_name(thing),(int)thing->index); long neardistance; struct Room *nearoom; neardistance = max_distance; nearoom = INVALID_ROOM; nearoom = find_next_navigable_room_for_thing_with_capacity_and_closer_than(thing, dungeon->room_kind[rkind], nav_flags, 0, &neardistance); return nearoom; }