/** * Checks if given player is either friendly to origin player or defeated. * @param check_plyr_idx * @param origin_plyr_idx * @return */ TbBool player_is_friendly_or_defeated(PlayerNumber check_plyr_idx, PlayerNumber origin_plyr_idx) { struct PlayerInfo *player; struct PlayerInfo *win_player; // Handle neutral player at first, because we can't get PlayerInfo nor Dungeon for it if ((origin_plyr_idx == game.neutral_player_num) || (check_plyr_idx == game.neutral_player_num)) return true; player = get_player(check_plyr_idx); win_player = get_player(origin_plyr_idx); if (player_exists(player)) { if ( (!player_allied_with(win_player, check_plyr_idx)) || (!player_allied_with(player, origin_plyr_idx)) ) { if (player_has_heart(check_plyr_idx)) return false; } } return true; }
/** * 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; }
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; }
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; }