TbBool prison_convert_creature_to_skeleton(struct Room *room, struct Thing *thing) { struct Dungeon *dungeon; struct CreatureControl *cctrl; struct Thing *crthing; long crmodel; cctrl = creature_control_get_from_thing(thing); crmodel = get_room_create_creature_model(room->kind); // That normally returns skeleton breed crthing = create_creature(&thing->mappos, crmodel, room->owner); if (thing_is_invalid(crthing)) { ERRORLOG("Couldn't create creature %s in prison", creature_code_name(crmodel)); return false; } init_creature_level(crthing, cctrl->explevel); set_start_state(crthing); if (creature_model_bleeds(thing->model)) create_effect_around_thing(thing, TngEff_Unknown10); kill_creature(thing, INVALID_THING, -1, CrDed_NoEffects); dungeon = get_dungeon(room->owner); if (!dungeon_invalid(dungeon)) { dungeon->lvstats.skeletons_raised++; } return true; }
PerPlayerFlags action_point_get_players_within(long apt_idx) { //return _DK_action_point_get_players_within(apt_idx); struct ActionPoint *apt; apt = action_point_get(apt_idx); PerPlayerFlags activated; activated = apt->activated; PlayerNumber plyr_idx; for (plyr_idx=0; plyr_idx < PLAYERS_COUNT; plyr_idx++) { struct PlayerInfo *player; player = get_player(plyr_idx); if (player_exists(player)) { if ((activated & (1 << plyr_idx)) == 0) { struct Dungeon *dungeon; dungeon = get_players_dungeon(player); if (dungeon_invalid(dungeon)) { continue; } SYNCDBG(16,"Checking player %d",(int)plyr_idx); if (action_point_is_creature_from_list_within(apt, dungeon->digger_list_start)) { activated |= (1 << plyr_idx); continue; } if (action_point_is_creature_from_list_within(apt, dungeon->creatr_list_start)) { activated |= (1 << plyr_idx); continue; } } } } return activated; }
long computer_check_for_expand_room(struct Computer2 *comp, struct ComputerCheck * check) { SYNCDBG(8,"Starting"); //return _DK_computer_check_for_expand_room(comp, check); struct Dungeon *dungeon; dungeon = comp->dungeon; if (dungeon_invalid(dungeon)) { ERRORLOG("Invalid computer players dungeon"); return 0; } long around_start; around_start = ACTION_RANDOM(119); // Don't work when placing rooms; we could place in an area for room by mistake if (is_task_in_progress(comp, CTT_PlaceRoom) || is_task_in_progress(comp, CTT_CheckRoomDug)) { SYNCDBG(8,"No rooms expansion - colliding task already in progress"); return 0; } if (4 * dungeon->creatures_total_pay / 3 >= dungeon->total_money_owned) { SYNCDBG(8,"No rooms expansion - we don't even have money for payday"); return 0; } const struct ExpandRooms *expndroom; for (expndroom = &expand_rooms[0]; expndroom->rkind != RoK_NONE; expndroom++) { if (computer_check_for_expand_room_kind(comp, check, expndroom->rkind, expndroom->max_slabs, around_start)) { return 1; } } SYNCDBG(8,"No rooms found for expansion"); return 0; }
TbBool placing_offmap_workshop_item(PlayerNumber plyr_idx, ThingClass tngclass, ThingModel tngmodel) { SYNCDBG(18,"Starting"); struct Dungeon *dungeon; dungeon = get_players_num_dungeon(plyr_idx); if (dungeon_invalid(dungeon)) { // Player with no dungeon has only on-map items // But this shouldn't really happen return true; } switch (tngclass) { case TCls_Trap: if (dungeon->trap_amount_stored[tngmodel] > 0) { return false; } if (dungeon->trap_amount_offmap[tngmodel] > 0) { return true; } break; case TCls_Door: if (dungeon->door_amount_stored[tngmodel] > 0) { return false; } if (dungeon->door_amount_offmap[tngmodel] > 0) { return true; } break; } return false; }
/** * Removes item from the amount of crates stored in workshops. * @param owner * @param tngclass * @param tngmodel * @return Gives WrkCrtS_None if no crate was found, WrkCrtS_Offmap if offmap crate was used, WrkCrtS_Stored if crate from workshop was used. * @note was named remove_workshop_item() */ int remove_workshop_item_from_amount_stored_f(PlayerNumber plyr_idx, ThingClass tngclass, ThingModel tngmodel, unsigned short flags, const char *func_name) { SYNCDBG(18,"%s: Starting",func_name); struct Dungeon *dungeon; dungeon = get_players_num_dungeon_f(plyr_idx,func_name); if (dungeon_invalid(dungeon)) { ERRORLOG("%s: Can't remove item; player %d has no dungeon.",func_name,(int)plyr_idx); return WrkCrtS_None; } long amount; amount = 0; switch (tngclass) { case TCls_Trap: if ((flags & WrkCrtF_NoStored) == 0) { amount = dungeon->trap_amount_stored[tngmodel]; } if (amount > 0) { SYNCDBG(8,"%s: Removing stored trap %s",func_name,trap_code_name(tngmodel)); dungeon->trap_amount_stored[tngmodel] = amount - 1; return WrkCrtS_Stored; } if ((flags & WrkCrtF_NoOffmap) == 0) { amount = dungeon->trap_amount_offmap[tngmodel]; } if (amount > 0) { SYNCDBG(8,"%s: Removing offmap trap %s",func_name,trap_code_name(tngmodel)); dungeon->trap_amount_offmap[tngmodel] = amount - 1; return WrkCrtS_Offmap; } ERRORLOG("%s: Trap %s not available",func_name,trap_code_name(tngmodel)); break; case TCls_Door: if ((flags & WrkCrtF_NoStored) == 0) { amount = dungeon->door_amount_stored[tngmodel]; } if (amount > 0) { SYNCDBG(8,"%s: Removing stored door %s",func_name,door_code_name(tngmodel)); dungeon->door_amount_stored[tngmodel] = amount - 1; return WrkCrtS_Stored; } if ((flags & WrkCrtF_NoOffmap) == 0) { amount = dungeon->door_amount_offmap[tngmodel]; } if (amount > 0) { SYNCDBG(8,"%s: Removing offmap door %s",func_name,door_code_name(tngmodel)); dungeon->door_amount_offmap[tngmodel] = amount - 1; return WrkCrtS_Offmap; } ERRORLOG("%s: Door %s not available",func_name,door_code_name(tngmodel)); break; default: ERRORLOG("%s: Can't remove item; illegal item class %d",func_name,(int)tngclass); break; } return WrkCrtS_None; }
/** Returns if given dungeon contains a room of given kind. * * @param dungeon Target dungeon. * @param rkind Room kind being checked. * @return */ TbBool dungeon_has_room(const struct Dungeon *dungeon, RoomKind rkind) { if (dungeon_invalid(dungeon)) { return false; } if ((rkind < 1) || (rkind >= ROOM_TYPES_COUNT)) { return false; } return (dungeon->room_kind[rkind] > 0); }
TbBool check_workshop_item_limit_reached(PlayerNumber plyr_idx, ThingClass tngclass, ThingModel tngmodel) { struct Dungeon *dungeon; dungeon = get_players_num_dungeon(plyr_idx); if (dungeon_invalid(dungeon)) return true; switch (tngclass) { case TCls_Trap: return (dungeon->trap_amount_stored[tngmodel] >= MANUFACTURED_ITEMS_LIMIT); case TCls_Door: return (dungeon->door_amount_stored[tngmodel] >= MANUFACTURED_ITEMS_LIMIT); } return true; }
TbBool set_script_flag(PlayerNumber plyr_idx, long flag_id, long value) { struct Dungeon *dungeon; if ( (flag_id < 0) || (flag_id >= SCRIPT_FLAGS_COUNT) ) { ERRORLOG("Can't set flag; invalid flag id %d.",(int)flag_id); return false; } dungeon = get_dungeon(plyr_idx); if (dungeon_invalid(dungeon)) { ERRORLOG("Can't set flag; player %d has no dungeon",(int)plyr_idx); return false; } dungeon->script_flags[flag_id] = value; return true; }
TbBool restart_script_timer(PlayerNumber plyr_idx, long timer_id) { struct Dungeon *dungeon; if ( (timer_id < 0) || (timer_id >= TURN_TIMERS_COUNT) ) { ERRORLOG("Can't restart timer; invalid timer id %d.",(int)timer_id); return false; } dungeon = get_dungeon(plyr_idx); if (dungeon_invalid(dungeon)) { ERRORLOG("Can't restart timer; player %d has no dungeon.",(int)plyr_idx); return false; } dungeon->turn_timers[timer_id].state = 1; dungeon->turn_timers[timer_id].count = game.play_gameturn; return true; }
/** * Adds item to the amount of crates in workshops, but also to the amount available to be placed. * @param owner * @param tngclass * @param tngmodel * @return * @note was named add_workshop_item() */ TbBool add_workshop_item_to_amounts_f(PlayerNumber plyr_idx, ThingClass tngclass, ThingModel tngmodel, const char *func_name) { struct Dungeon *dungeon; dungeon = get_players_num_dungeon_f(plyr_idx,func_name); if (dungeon_invalid(dungeon)) { ERRORLOG("%s: Can't add item; player %d has no dungeon.",func_name,(int)plyr_idx); return false; } switch (tngclass) { case TCls_Trap: SYNCDBG(8,"%s: Adding Trap %s",func_name,trap_code_name(tngmodel)); dungeon->trap_amount_stored[tngmodel]++; dungeon->trap_amount_placeable[tngmodel]++; dungeon->trap_build_flags[tngmodel] |= MnfBldF_Built; // In case the placeable amount lost it, do a fix if (dungeon->trap_amount_placeable[tngmodel] > dungeon->trap_amount_stored[tngmodel]+dungeon->trap_amount_offmap[tngmodel]) { WARNLOG("%s: Placeable %s traps amount for player %d was too large; fixed",func_name,trap_code_name(tngmodel),(int)plyr_idx); dungeon->trap_amount_placeable[tngmodel] = dungeon->trap_amount_stored[tngmodel]+dungeon->trap_amount_offmap[tngmodel]; } if (dungeon->trap_amount_placeable[tngmodel] < dungeon->trap_amount_offmap[tngmodel]) { WARNLOG("%s: Placeable %s traps amount for player %d was too small; fixed",func_name,trap_code_name(tngmodel),(int)plyr_idx); dungeon->trap_amount_placeable[tngmodel] = dungeon->trap_amount_offmap[tngmodel]; } break; case TCls_Door: SYNCDBG(8,"%s: Adding Door %s",func_name,door_code_name(tngmodel)); dungeon->door_amount_stored[tngmodel]++; dungeon->door_amount_placeable[tngmodel]++; dungeon->door_build_flags[tngmodel] |= MnfBldF_Built; // In case the placeable amount lost it, do a fix if (dungeon->door_amount_placeable[tngmodel] > dungeon->door_amount_stored[tngmodel]+dungeon->door_amount_offmap[tngmodel]) { WARNLOG("%s: Placeable %s doors amount for player %d was too large; fixed",func_name,door_code_name(tngmodel),(int)plyr_idx); dungeon->door_amount_placeable[tngmodel] = dungeon->door_amount_stored[tngmodel]+dungeon->door_amount_offmap[tngmodel]; } if (dungeon->door_amount_placeable[tngmodel] < dungeon->door_amount_offmap[tngmodel]) { WARNLOG("%s: Placeable %s doors amount for player %d was too small; fixed",func_name,door_code_name(tngmodel),(int)plyr_idx); dungeon->door_amount_placeable[tngmodel] = dungeon->door_amount_offmap[tngmodel]; } break; default: ERRORLOG("%s: Can't add item; illegal item class %d",func_name,(int)tngclass); return false; } return true; }
/** * Returns if the trap was at least one built by a player. */ TbBool is_trap_built(PlayerNumber plyr_idx, long tngmodel) { struct Dungeon *dungeon; dungeon = get_players_num_dungeon(plyr_idx); // Check if the player even have a dungeon if (dungeon_invalid(dungeon)) { return false; } if ((tngmodel <= 0) || (tngmodel >= TRAP_TYPES_COUNT)) { ERRORLOG("Incorrect trap %d (player %d)",(int)tngmodel, (int)plyr_idx); return false; } if ((dungeon->trap_build_flags[tngmodel] & MnfBldF_Built) != 0) { return true; } return false; }
struct Thing *computer_check_creatures_in_dungeon_rooms_of_kind_for_accelerate(struct Computer2 *comp, RoomKind rkind) { struct Dungeon *dungeon; struct Room *room; struct Thing *thing; long i; unsigned long k; if ((rkind < 1) || (rkind > ROOM_TYPES_COUNT)) { ERRORLOG("Invalid room kind %d",(int)rkind); return INVALID_THING; } dungeon = comp->dungeon; if (dungeon_invalid(dungeon)) { ERRORLOG("Invalid computer players dungeon"); return INVALID_THING; } i = dungeon->room_kind[rkind]; k = 0; while (i != 0) { room = room_get(i); if (room_is_invalid(room)) { ERRORLOG("Jump to invalid room detected"); break; } i = room->next_of_owner; // Per-room code thing = computer_check_creatures_in_room_for_accelerate(comp, room); if (!thing_is_invalid(thing)) return thing; // Per-room code ends k++; if (k > ROOMS_COUNT) { ERRORLOG("Infinite loop detected when sweeping rooms list"); break; } } return INVALID_THING; }
TbBool set_door_buildable_and_add_to_amount(PlayerNumber plyr_idx, ThingModel tngmodel, long buildable, long amount) { struct Dungeon *dungeon; if ( (tngmodel <= 0) || (tngmodel >= DOOR_TYPES_COUNT) ) { ERRORDBG(1,"Can't set door availability; invalid door kind %d.",(int)tngmodel); return false; } dungeon = get_dungeon(plyr_idx); if (dungeon_invalid(dungeon)) { ERRORDBG(11,"Can't set door availability; player %d has no dungeon.",(int)plyr_idx); return false; } if (buildable) dungeon->door_build_flags[tngmodel] |= MnfBldF_Manufacturable; dungeon->door_amount_offmap[tngmodel] += amount; dungeon->door_amount_placeable[tngmodel] += amount; if (amount > 0) dungeon->door_build_flags[tngmodel] |= MnfBldF_Built; return true; }
TbBool set_creature_tendencies(struct PlayerInfo *player, unsigned short tend_type, TbBool val) { struct Dungeon *dungeon; dungeon = get_dungeon(player->id_number); if (dungeon_invalid(dungeon)) { ERRORLOG("Can't set tendency; player %d has no dungeon.",(int)player->id_number); return false; } switch (tend_type) { case CrTend_Imprison: set_flag_byte(&dungeon->creature_tendencies, 0x01, val); return true; case CrTend_Flee: set_flag_byte(&dungeon->creature_tendencies, 0x02, val); return true; default: ERRORLOG("Can't set tendency; bad tendency type %d",(int)tend_type); return false; } }
/** * Returns if the trap can be manufactured by a player. * Checks only if it's set as buildable in level script. * Doesn't check if player has workshop or workforce for the task. */ TbBool is_trap_buildable(PlayerNumber plyr_idx, long tngmodel) { struct Dungeon *dungeon; dungeon = get_players_num_dungeon(plyr_idx); // Check if the player even have a dungeon if (dungeon_invalid(dungeon)) { return false; } // Player must have dungeon heart to build anything if (!player_has_heart(plyr_idx)) { return false; } if ((tngmodel <= 0) || (tngmodel >= TRAP_TYPES_COUNT)) { ERRORLOG("Incorrect trap %d (player %d)",(int)tngmodel, (int)plyr_idx); return false; } if ((dungeon->trap_build_flags[tngmodel] & MnfBldF_Manufacturable) != 0) { return true; } return false; }
/** * Returns if the trap can be placed by a player. * Checks only if it's available and if the player is 'alive'. * Doesn't check if map position is on correct spot. */ TbBool is_trap_placeable(PlayerNumber plyr_idx, long tngmodel) { struct Dungeon *dungeon; dungeon = get_players_num_dungeon(plyr_idx); // Check if the player even have a dungeon if (dungeon_invalid(dungeon)) { return false; } // Player must have dungeon heart to place traps if (!player_has_heart(plyr_idx)) { return false; } if ((tngmodel <= 0) || (tngmodel >= TRAP_TYPES_COUNT)) { ERRORLOG("Incorrect trap %d (player %d)",(int)tngmodel, (int)plyr_idx); return false; } if (dungeon->trap_amount_placeable[tngmodel] > 0) { return true; } return false; }
/** * Returns if the door was at least one built by a player. */ TbBool is_door_built(PlayerNumber plyr_idx, long door_idx) { struct Dungeon *dungeon; dungeon = get_players_num_dungeon(plyr_idx); // Check if the player even have a dungeon if (dungeon_invalid(dungeon)) { return false; } // Player must have dungeon heart to build anything if (!player_has_heart(plyr_idx)) { return false; } if ((door_idx <= 0) || (door_idx >= DOOR_TYPES_COUNT)) { ERRORLOG("Incorrect door %d (player %d)",(int)door_idx, (int)plyr_idx); return false; } if ((dungeon->door_build_flags[door_idx] & MnfBldF_Built) != 0) { return true; } return false; }
struct Room *get_opponent_room(struct Computer2 *comp, PlayerNumber plyr_idx) { static const RoomKind opponent_room_kinds[] = {RoK_DUNGHEART, RoK_PRISON, RoK_LIBRARY, RoK_TREASURE}; struct Dungeon *dungeon; struct Room *room; dungeon = get_players_num_dungeon(plyr_idx); if (dungeon_invalid(dungeon) || (slab_conf.room_types_count < 1)) { return INVALID_ROOM; } int i,n; n = opponent_room_kinds[ACTION_RANDOM(sizeof(opponent_room_kinds)/sizeof(opponent_room_kinds[0]))]; for (i=0; i < slab_conf.room_types_count; i++) { room = room_get(dungeon->room_kind[n]); if (room_exists(room)) { return room; } n = (n + 1) % slab_conf.room_types_count; } return INVALID_ROOM; }
void player_add_offmap_gold(PlayerNumber plyr_idx, GoldAmount value) { if (plyr_idx == game.neutral_player_num) { WARNLOG("Cannot give gold to neutral player %d",(int)plyr_idx); return; } struct Dungeon *dungeon; // note that we can't get_players_num_dungeon() because players // may be uninitialized yet when this is called. dungeon = get_dungeon(plyr_idx); if (dungeon_invalid(dungeon)) { WARNLOG("Cannot give gold player %d with no dungeon",(int)plyr_idx); return; } // If we're removing gold instead of adding, make sure we won't remove too much if ((value < 0) && (dungeon->offmap_money_owned < -value)) { value = -dungeon->offmap_money_owned; } dungeon->offmap_money_owned += value; dungeon->total_money_owned += value; }
/** * Removes item from the amount available to be placed on map. * @param owner * @param tngclass * @param tngmodel * @return */ TbBool remove_workshop_item_from_amount_placeable_f(PlayerNumber plyr_idx, ThingClass tngclass, ThingModel tngmodel, const char *func_name) { SYNCDBG(18,"%s: Starting",func_name); struct Dungeon *dungeon; dungeon = get_players_num_dungeon_f(plyr_idx,func_name); if (dungeon_invalid(dungeon)) { ERRORLOG("%s: Can't remove item; player %d has no dungeon.",func_name,(int)plyr_idx); return false; } long amount; switch (tngclass) { case TCls_Trap: amount = dungeon->trap_amount_placeable[tngmodel]; if (amount <= 0) { ERRORLOG("%s: Trap %s not available",func_name,trap_code_name(tngmodel)); break; } SYNCDBG(8,"%s: Removing Trap %s",func_name,trap_code_name(tngmodel)); dungeon->trap_amount_placeable[tngmodel] = amount - 1; dungeon->trap_build_flags[tngmodel] |= MnfBldF_Used; dungeon->lvstats.traps_used++; return true; case TCls_Door: amount = dungeon->door_amount_placeable[tngmodel]; if (amount <= 0) { ERRORLOG("%s: Door %s not available",func_name,door_code_name(tngmodel)); break; } SYNCDBG(8,"%s: Removing Door %s",func_name,door_code_name(tngmodel)); dungeon->door_amount_placeable[tngmodel] = amount - 1; dungeon->door_build_flags[tngmodel] |= MnfBldF_Used; dungeon->lvstats.doors_used++; return true; default: ERRORLOG("%s: Can't remove item; illegal item class %d",func_name,(int)tngclass); break; } return false; }
TbBool mark_creature_joined_dungeon(struct Thing *creatng) { if (creatng->owner == game.neutral_player_num) { // Neutral player has no dungeon return false; } struct Dungeon *dungeon; dungeon = get_dungeon(creatng->owner); if (dungeon_invalid(dungeon)) { ERRORLOG("Can't mark; player %d has no dungeon",(int)creatng->owner); return false; } if ((dungeon->owned_creatures_of_model[creatng->model] <= 1) && (dungeon->creature_models_joined[creatng->model] <= 0)) { event_create_event(creatng->mappos.x.val, creatng->mappos.y.val, EvKind_NewCreature, creatng->owner, creatng->index); } if (dungeon->creature_models_joined[creatng->model] < 255) { dungeon->creature_models_joined[creatng->model]++; } return true; }
/** * Counts amount of rooms of specific type owned by specific player. * @param plyr_idx The player number. Only specific player number is accepted. * @param rkind Room kind to count. Only specific kind is accepted. */ long count_player_rooms_of_type(PlayerNumber plyr_idx, RoomKind rkind) { struct Dungeon *dungeon; struct Room *room; long i; unsigned long k; // note that we can't get_players_num_dungeon() because players // may be uninitialized yet when this is called. dungeon = get_dungeon(plyr_idx); if (dungeon_invalid(dungeon)) return 0; i = dungeon->room_kind[rkind]; k = 0; while (i != 0) { room = room_get(i); if (room_is_invalid(room)) { ERRORLOG("Jump to invalid room detected"); break; } i = room->next_of_owner; // No Per-room code - we only want count SYNCDBG(19,"Player %d has %s at (%d,%d)",(int)plyr_idx, room_code_name(room->kind), (int)room->central_stl_x, (int)room->central_stl_y); if (room->owner != plyr_idx) { ERRORDBG(3,"Player %d has bad room in %s list; it's really %s index %d owned by player %d",(int)plyr_idx, room_code_name(rkind), room_code_name(room->kind), (int)room->index, (int)room->owner); break; } k++; if (k > ROOMS_COUNT) { ERRORLOG("Infinite loop detected when sweeping rooms list"); break; } } return k; }
long computer_check_for_expand_room(struct Computer2 *comp, struct ComputerCheck * check) { if (is_newdig_enabled(comp)) return 4; SYNCDBG(8,"Starting"); struct Dungeon *dungeon; dungeon = comp->dungeon; if (dungeon_invalid(dungeon) || !player_has_heart(dungeon->owner)) { SYNCDBG(7,"Computer players %d dungeon in invalid or has no heart",(int)dungeon->owner); return CTaskRet_Unk4; } long around_start; around_start = ACTION_RANDOM(119); // Don't work when placing rooms; we could place in an area for room by mistake if (is_task_in_progress(comp, CTT_PlaceRoom) || is_task_in_progress(comp, CTT_CheckRoomDug)) { SYNCDBG(8,"No rooms expansion - colliding task already in progress"); return CTaskRet_Unk0; } if (computer_player_in_emergency_state(comp)) { SYNCDBG(8,"No rooms expansion - emergency state"); return CTaskRet_Unk0; } if (get_computer_money_less_cost(comp) < dungeon->creatures_total_pay / 3) { SYNCDBG(8,"No rooms expansion - not enough money buffer"); return CTaskRet_Unk0; } const struct ExpandRooms *expndroom; for (expndroom = &expand_rooms[0]; expndroom->rkind != RoK_NONE; expndroom++) { if (computer_check_for_expand_room_kind(comp, check, expndroom->rkind, expndroom->max_slabs, around_start)) { return CTaskRet_Unk1; } } SYNCDBG(8,"No rooms found for expansion"); return CTaskRet_Unk0; }
/** * Does a step of researching. * Informs if the research cycle should end. * @param thing */ CrCheckRet process_research_function(struct Thing *creatng) { struct Dungeon *dungeon; struct Room *room; dungeon = get_dungeon(creatng->owner); if (dungeon_invalid(dungeon)) { SYNCDBG(9,"The %s index %d cannot work as player %d has no dungeon", thing_model_name(creatng), (int)creatng->index, (int)creatng->owner); set_start_state(creatng); return CrCkRet_Continue; } if (!creature_can_do_research(creatng)) { set_start_state(creatng); return CrCkRet_Continue; } room = get_room_creature_works_in(creatng); if ( !room_still_valid_as_type_for_thing(room, RoK_LIBRARY, 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); set_start_state(creatng); return CrCkRet_Continue; } long work_value; struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); work_value = compute_creature_work_value(crstat->research_value*256, room->efficiency, cctrl->explevel); work_value = process_work_speed_on_work_value(creatng, work_value); SYNCDBG(19,"The %s index %d produced %d research points",thing_model_name(creatng),(int)creatng->index,(int)work_value); dungeon->total_research_points += work_value; dungeon->research_progress += work_value; //TODO CREATURE_JOBS going postal should be possible for all jobs, not only research process_job_stress_and_going_postal(creatng, room); return CrCkRet_Available; }
long computer_check_neutral_places(struct Computer2 *comp, struct ComputerCheck * check) { if (is_newdig_enabled(comp)) return 4; SYNCDBG(8,"Starting"); struct Dungeon *dungeon; dungeon = comp->dungeon; if (dungeon_invalid(dungeon) || !player_has_heart(dungeon->owner)) { SYNCDBG(7,"Computer players %d dungeon in invalid or has no heart",(int)dungeon->owner); return CTaskRet_Unk4; } struct OpponentRelation *oprel; oprel = &comp->opponent_relations[game.neutral_player_num]; struct Room *near_room; struct Coord3d *near_pos; int near_dist; near_room = INVALID_ROOM; near_dist = LONG_MAX; near_pos = &oprel->pos_A[0]; int i; for (i=0; i < COMPUTER_SPARK_POSITIONS_COUNT; i++) { struct Coord3d *place; place = &oprel->pos_A[i]; if ((place->x.val == 0) || (place->y.val == 0)) { continue; } struct Room *room; room = INVALID_ROOM; if (computer_finds_nearest_room_to_pos(comp, &room, place)) { MapSubtlDelta dx,dy; dx = abs((int)room->central_stl_x - (MapSubtlDelta)place->x.stl.num); dy = abs((int)room->central_stl_y - (MapSubtlDelta)place->y.stl.num); if (near_dist > dx+dy) { near_room = room; near_pos = place; near_dist = dx+dy; } } } if (room_is_invalid(near_room)) { return CTaskRet_Unk4; } struct Coord3d endpos; struct Coord3d startpos; endpos.x.val = near_pos->x.val; endpos.y.val = near_pos->y.val; endpos.z.val = near_pos->z.val; startpos.x.val = subtile_coord_center(stl_slab_center_subtile(near_room->central_stl_x)); startpos.y.val = subtile_coord_center(stl_slab_center_subtile(near_room->central_stl_y)); startpos.z.val = subtile_coord(1,0); if (!create_task_dig_to_neutral(comp, startpos, endpos)) { return CTaskRet_Unk4; } near_pos->x.val = 0; near_pos->y.val = 0; near_pos->z.val = 0; return CTaskRet_Unk1; }
/** * Checks if a computer player has not enough imps. * @param comp * @param check The check structure; param1 is preferred amount of imps, param2 is minimal amount. */ long computer_check_no_imps(struct Computer2 *comp, struct ComputerCheck * check) { if (is_newdig_enabled(comp)) { //workaround for interval seeming to be ignored by from my reconfiguration. //modern computers can handle interval 1 and interval 200 is awfully passive and easy to kill //interval 20 means player-like imp swarms will form while not being excessive //consider making configurable again if *properly* reconfiguring to 20 for all levels except easy beginner levels if (check->turns_interval > 20) check->turns_interval = 20; if (check->param2 < 8) check->param2 = 8; } struct Dungeon *dungeon; SYNCDBG(8,"Starting"); dungeon = comp->dungeon; if (dungeon_invalid(dungeon) || !player_has_heart(dungeon->owner)) { SYNCDBG(7,"Computer players %d dungeon in invalid or has no heart",(int)dungeon->owner); return CTaskRet_Unk4; } long power_price, lowest_price; TbBool diggers_are_cheap; power_price = compute_power_price(dungeon->owner, PwrK_MKDIGGER, 0); lowest_price = compute_lowest_digger_price(dungeon->owner); diggers_are_cheap = power_price <= lowest_price; //see if we can sacrifice imps to reduce price if (gameadd.sacrifice_info.classic_imp_sacrifice) { SYNCDBG(18, "Imp creation power price: %d, lowest: %d", power_price, lowest_price); if (!diggers_are_cheap && dungeon->total_money_owned > power_price //TODO: might need to multiply for safety factor && dungeon_has_room(dungeon, RoK_TEMPLE)) { struct Thing* imp; imp = find_imp_for_sacrifice(comp->dungeon); if (!thing_is_invalid(imp)) { long dist; struct Room* room; room = find_room_nearest_to_position(dungeon->owner, RoK_TEMPLE, &imp->mappos, &dist); if (!room_is_invalid(room)) { if (create_task_move_creature_to_subtile(comp, imp, room->central_stl_x, room->central_stl_y, CrSt_CreatureSacrifice)) return CTaskRet_Unk4; } } } } //regular old imp check after this point long controlled_diggers; TbBool digging_gems; long limit; digging_gems = is_digging_any_gems(dungeon); controlled_diggers = dungeon->num_active_diggers - count_player_diggers_not_counting_to_total(dungeon->owner); //SYNCLOG("controlled diggers of %d = %d, params = %d %d", (int)dungeon->owner, controlled_diggers, check->param1, check->param2); limit = check->param1; if (digging_gems) { if (diggers_are_cheap) limit = max(limit, 50); else limit = max(limit, 20); } if (controlled_diggers >= limit) { return CTaskRet_Unk4; } long able; if ((controlled_diggers == 0 || (controlled_diggers < 3 && (digging_gems || diggers_are_cheap))) && is_power_available(dungeon->owner, PwrK_MKDIGGER)) { //ignore payday and everything else, we need at least 3 imp to play the game able = dungeon->total_money_owned >= compute_power_price(dungeon->owner, PwrK_MKDIGGER, 0); //TODO: recovery could be improved further by looking at length to payday and time it takes to get more money to increase lower bound } else if (controlled_diggers >= check->param2 && !digging_gems) { // We have less than preferred amount, but higher than minimal; allow building if we've got spare money able = computer_able_to_use_magic(comp, PwrK_MKDIGGER, 0, 3 + (controlled_diggers - check->param2)/4); } else { able = computer_able_to_use_magic(comp, PwrK_MKDIGGER, 0, 1); } if (able == CTaskRet_Unk1) { struct Thing *heartng; MapSubtlCoord stl_x, stl_y; heartng = get_player_soul_container(dungeon->owner); stl_x = heartng->mappos.x.stl.num; stl_y = heartng->mappos.y.stl.num; if (xy_walkable(stl_x, stl_y, dungeon->owner)) { if (try_game_action(comp, dungeon->owner, GA_UseMkDigger, 0, stl_x, stl_y, 1, 1) > Lb_OK) { return CTaskRet_Unk1; } } return CTaskRet_Unk1; } return CTaskRet_Unk0; }
TbBool process_scavenge_creature_from_level(struct Thing *scavtng, struct Thing *calltng, long work_value) { struct Dungeon *calldngn; long num_prayers; calldngn = get_dungeon(calltng->owner); if (dungeon_invalid(calldngn)) { ERRORLOG("The %s owner %d can't do scavenging - has no dungeon",thing_model_name(calltng),(int)calltng->owner); return false; } // Compute amount of creatures praying against the scavenge if (!is_neutral_thing(scavtng)) { struct Dungeon *scavdngn; scavdngn = get_dungeon(scavtng->owner); num_prayers = scavdngn->creatures_praying[scavtng->model]; } else { num_prayers = 0; } // Increase scavenging counter, used to break the prayers counter calldngn->creatures_scavenging[scavtng->model]++; // If scavenge is blocked by prayers, return if (calldngn->creatures_scavenging[calltng->model] < 2 * num_prayers) { SYNCDBG(8, "Player %d prayers (%d) are blocking player %d scavenging (%d) of %s", (int)scavtng->owner, (int)num_prayers, (int)calltng->owner, (int)calldngn->creatures_scavenging[calltng->model], thing_model_name(calltng)); return false; } SYNCDBG(18,"The %s index %d scavenges %s index %d",thing_model_name(calltng),(int)calltng->index,thing_model_name(scavtng),(int)scavtng->index); // If we're starting to scavenge a new creature, do the switch if (calldngn->scavenge_targets[calltng->model] != scavtng->index) { calldngn->scavenge_turn_points[calltng->model] = work_value; if (calldngn->scavenge_targets[calltng->model] > 0) { // Stop scavenging old creature struct Thing *thing; thing = thing_get(calldngn->scavenge_targets[calltng->model]); if (thing_is_creature(thing) && (thing->model == calltng->model)) { if (creature_is_being_scavenged(thing)) { set_start_state(thing); } } } // Start the new scavenging calldngn->scavenge_targets[calltng->model] = scavtng->index; if (is_my_player_number(scavtng->owner)) { output_message(SMsg_CreatureScanvenged, 500, 1); } event_create_event(scavtng->mappos.x.val, scavtng->mappos.y.val, EvKind_CreatrScavenged, scavtng->owner, scavtng->index); } else { calldngn->scavenge_turn_points[calltng->model] += work_value; } // Make sure the scavenged creature is in correct state if (!creature_is_being_scavenged(scavtng)) { if (!is_neutral_thing(scavtng)) { external_set_thing_state(scavtng, CrSt_CreatureBeingScavenged); } } long scavpts; scavpts = calculate_correct_creature_scavenge_required(scavtng, calltng->owner); if ((scavpts << 8) < calldngn->scavenge_turn_points[calltng->model]) { SYNCDBG(8,"The %s index %d owner %d accumulated enough points to turn to scavenger",thing_model_name(scavtng),(int)scavtng->index,(int)scavtng->owner); turn_creature_to_scavenger(scavtng, calltng); calldngn->scavenge_turn_points[calltng->model] -= (scavpts << 8); return true; } return false; }
/** * Updates gameplay score for a dungeon belonging to given player. * @return */ TbBool update_dungeon_scores_for_player(struct PlayerInfo *player) { struct Dungeon *dungeon; int i,k; dungeon = get_players_dungeon(player); unsigned long manage_efficiency,max_manage_efficiency; if (dungeon_invalid(dungeon)) { return false; } manage_efficiency = 0; max_manage_efficiency = 0; { manage_efficiency += 40 * compute_dungeon_rooms_attraction_score(dungeon->room_slabs_count[RoK_ENTRANCE], dungeon->field_949, dungeon->field_1485); max_manage_efficiency += 40 * compute_dungeon_rooms_attraction_score(LONG_MAX, LONG_MAX, LONG_MAX); } { manage_efficiency += 40 * compute_dungeon_creature_tactics_score(dungeon->battles_won, dungeon->battles_lost, dungeon->creatures_scavenge_gain, dungeon->creatures_scavenge_lost); max_manage_efficiency += 40 * compute_dungeon_creature_tactics_score(LONG_MAX, LONG_MAX, LONG_MAX, LONG_MAX); } { // Compute amount of different types of rooms built unsigned long room_types; room_types = 0; for (i=0; i < ROOM_TYPES_COUNT; i++) { if (dungeon->room_slabs_count[i] > 0) room_types++; } manage_efficiency += 40 * compute_dungeon_rooms_variety_score(room_types, dungeon->total_area); max_manage_efficiency += 40 * compute_dungeon_rooms_variety_score(ROOM_TYPES_COUNT, LONG_MAX); } { manage_efficiency += compute_dungeon_train_research_manufctr_wealth_score(dungeon->total_experience_creatures_gained, dungeon->total_research_points, dungeon->field_1181, dungeon->total_money_owned); max_manage_efficiency += compute_dungeon_train_research_manufctr_wealth_score(LONG_MAX, LONG_MAX, LONG_MAX, LONG_MAX); } unsigned long creatures_efficiency, creatures_mood; unsigned long max_creatures_efficiency, max_creatures_mood; { creatures_efficiency = compute_dungeon_creature_amount_score(dungeon->num_active_creatrs); max_creatures_efficiency = compute_dungeon_creature_amount_score(LONG_MAX); creatures_mood = compute_dungeon_creature_mood_score(dungeon->num_active_creatrs,dungeon->creatures_annoyed); max_creatures_mood = compute_dungeon_creature_mood_score(LONG_MAX,LONG_MAX); } { // Compute total score for this turn i = manage_efficiency + creatures_efficiency; k = max_manage_efficiency + max_creatures_efficiency; dungeon->field_AE9[1] = 1000 * i / k; } { // Compute managing efficiency score i = manage_efficiency - creatures_efficiency; k = max_manage_efficiency - max_creatures_efficiency; if (i < 0) i = 0; long raw_score; raw_score = 1000 * i / k; // Angry creatures may degrade the score by up to 50% raw_score = raw_score / 2 + raw_score * (max_creatures_mood - creatures_mood) / (2*max_creatures_mood); dungeon->field_AE9[0] = raw_score; } { unsigned long gameplay_score; gameplay_score = dungeon->field_AE9[1]; if (gameplay_score <= 1) { WARNLOG("Total score for turn is too low!"); gameplay_score = 1; } dungeon->field_AE9[1] = gameplay_score; } { unsigned long gameplay_score; gameplay_score = dungeon->field_AE9[0]; if (gameplay_score <= 1) { WARNLOG("Managing score for turn is too low!"); gameplay_score = 1; } dungeon->field_AE9[0] = gameplay_score; } { // Check to update max score unsigned long gameplay_score; gameplay_score = dungeon->field_AE9[1]; if (dungeon->max_gameplay_score < gameplay_score) dungeon->max_gameplay_score = gameplay_score; } return true; }