Skip to content

Commit

Permalink
Merge pull request #509 from yazilimmz/155-fleet-deuterium
Browse files Browse the repository at this point in the history
fixed #156 fixed #155 fixed #494
  • Loading branch information
lanedirt authored Dec 27, 2024
2 parents ec82b98 + 61922f9 commit f1576cf
Show file tree
Hide file tree
Showing 23 changed files with 4,574 additions and 4,317 deletions.
3 changes: 3 additions & 0 deletions app/Console/Commands/Tests/TestRaceConditionGameMission.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Validation\ValidationException;
use OGame\Models\FleetMission;
use OGame\Models\Resources;
use OGame\Services\ObjectService;

/**
Expand Down Expand Up @@ -105,6 +106,7 @@ private function dispatchFleetMissionTransport(): void
{
$missionTypeTransport = 3;
$secondPlanet = $this->playerService->planets->all()[1];
$this->playerService->planets->first()->addResources(new Resources(0, 0, 1000000, 0));
$secondPlanetCoordinates = $secondPlanet->getPlanetCoordinates();

$csrfToken = $this->getCsrfToken();
Expand All @@ -118,6 +120,7 @@ private function dispatchFleetMissionTransport(): void
'type' => 1,
'mission' => $missionTypeTransport,
'metal' => 0,
'speed' => 10,
'crystal' => 0,
'deuterium' => 0,
'am' . ObjectService::getUnitObjectByMachineName('small_cargo')->id => '10',
Expand Down
16 changes: 12 additions & 4 deletions app/GameMissions/Abstracts/GameMission.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,23 @@ public function deductMissionResources(PlanetService $planet, Resources $resourc
* @return FleetMission
* @throws Exception
*/
public function start(PlanetService $planet, Coordinate $targetCoordinate, PlanetType $targetType, UnitCollection $units, Resources $resources, int $parent_id = 0): FleetMission
public function start(PlanetService $planet, Coordinate $targetCoordinate, PlanetType $targetType, UnitCollection $units, Resources $resources, float $speed_percent, int $parent_id = 0): FleetMission
{
$this->startMissionSanityChecks($planet, $targetCoordinate, $targetType, $units, $resources);

$consumption = $this->fleetMissionService->calculateConsumption($planet, $units, $targetCoordinate, 0, $speed_percent);
$consumption_resources = new Resources(0, 0, $consumption, 0);

$total_deuterium = $resources->deuterium->get() + $consumption_resources->deuterium->get();
$deduct_resources = new Resources($resources->metal->get(), $resources->crystal->get(), $total_deuterium, 0);

$this->startMissionSanityChecks($planet, $targetCoordinate, $targetType, $units, $deduct_resources);

// Time this fleet mission will depart (now).
$time_start = (int)Carbon::now()->timestamp;

// Time fleet mission will arrive.
// TODO: refactor calculate to gamemission base class?
$time_end = $time_start + $this->fleetMissionService->calculateFleetMissionDuration($planet, $targetCoordinate, $units);
$time_end = $time_start + $this->fleetMissionService->calculateFleetMissionDuration($planet, $targetCoordinate, $units, $speed_percent);

$mission = new FleetMission();

Expand All @@ -199,6 +206,7 @@ public function start(PlanetService $planet, Coordinate $targetCoordinate, Plane
$mission->time_arrival = $time_end;

$mission->type_to = $targetType->value;
$mission->deuterium_consumption = $consumption_resources->deuterium->get();

// Only set the target planet ID if the target is a planet or moon.
if ($targetType === PlanetType::Planet) {
Expand Down Expand Up @@ -226,7 +234,7 @@ public function start(PlanetService $planet, Coordinate $targetCoordinate, Plane
$mission->deuterium = $resources->deuterium->getRounded();

// Deduct mission resources from the planet.
$this->deductMissionResources($planet, $resources, $units);
$this->deductMissionResources($planet, $deduct_resources, $units);

// Save the new fleet mission.
$mission->save();
Expand Down
1 change: 1 addition & 0 deletions app/GameMissions/AttackMission.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public function isMissionPossible(PlanetService $planet, Coordinate $targetCoord
*/
protected function processArrival(FleetMission $mission): void
{

$defenderPlanet = $this->planetServiceFactory->make($mission->planet_id_to, true);
$origin_planet = $this->planetServiceFactory->make($mission->planet_id_from, true);

Expand Down
5 changes: 3 additions & 2 deletions app/GameMissions/DeploymentMission.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ public function isMissionPossible(PlanetService $planet, Coordinate $targetCoord
*/
protected function processArrival(FleetMission $mission): void
{
$target_planet = $this->planetServiceFactory->make($mission->planet_id_to, true);

$target_planet = $this->planetServiceFactory->make($mission->planet_id_to, true);
// Add resources to the target planet
$resources = $this->fleetMissionService->getResources($mission);

$target_planet->addResources($resources);

// Add units to the target planet
Expand All @@ -65,7 +66,7 @@ protected function processArrival(FleetMission $mission): void
'to' => '[planet]' . $mission->planet_id_to . '[/planet]',
'metal' => (string)$mission->metal,
'crystal' => (string)$mission->crystal,
'deuterium' => (string)$mission->deuterium
'deuterium' => (string)($mission->deuterium + ($mission->deuterium_consumption / 2)), //if mission deployment: Add half of the consumed deuterium
]);
} else {
$this->messageService->sendSystemMessageToPlayer($target_planet->getPlayer(), FleetDeployment::class, [
Expand Down
9 changes: 7 additions & 2 deletions app/Http/Controllers/FleetController.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ public function dispatchSendFleet(PlayerService $player, FleetMissionService $fl
// Create the target coordinate
$target_coordinate = new Coordinate($galaxy, $system, $position);

// Extract speed and holding time from the request
$speed_percent = (float)request()->input('speed');
$holding_time = (int)request()->input('holdingtime');

// Extract units from the request and create a unit collection.
// Loop through all input fields and get all units prefixed with "am".
$units = $this->getUnitsFromRequest($planet);
Expand All @@ -264,7 +268,7 @@ public function dispatchSendFleet(PlayerService $player, FleetMissionService $fl

// Create a new fleet mission
$planetType = PlanetType::from($target_type);
$fleetMissionService->createNewFromPlanet($planet, $target_coordinate, $planetType, $mission_type, $units, $resources);
$fleetMissionService->createNewFromPlanet($planet, $target_coordinate, $planetType, $mission_type, $units, $resources, $speed_percent);

return response()->json([
'components' => [],
Expand Down Expand Up @@ -333,7 +337,8 @@ public function dispatchSendMiniFleet(PlayerService $player, FleetMissionService

// Create a new fleet mission
$planetType = PlanetType::from($targetType);
$fleetMission = $fleetMissionService->createNewFromPlanet($planet, $targetCoordinate, $planetType, $mission_type, $units, $resources);

$fleetMission = $fleetMissionService->createNewFromPlanet($planet, $targetCoordinate, $planetType, $mission_type, $units, $resources, 10);

// Calculate the actual amount of units sent.
$fleetUnitCount = $fleetMissionService->getFleetUnitCount($fleetMission);
Expand Down
1 change: 0 additions & 1 deletion app/Http/Controllers/TechtreeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,6 @@ public function getPropertiesTable(GameObject $object, PlayerService $player): V

// Load object again to get the UnitObject
$object = ObjectService::getUnitObjectByMachineName($object->machine_name);

// Get UnitObject properties...
$properties = $object->properties;

Expand Down
1 change: 1 addition & 0 deletions app/Models/FleetMission.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* @property int $metal
* @property int $crystal
* @property int $deuterium
* @property float $deuterium_consumption
* @property int $light_fighter
* @property int $heavy_fighter
* @property int $cruiser
Expand Down
162 changes: 133 additions & 29 deletions app/Services/FleetMissionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,42 +68,146 @@ public function __construct(PlayerService $player, MessageService $messageServic
* @param UnitCollection $units
* @return int
*/
public function calculateFleetMissionDuration(PlanetService $fromPlanet, Coordinate $to, UnitCollection $units): int
public function calculateFleetMissionDuration(PlanetService $fromPlanet, Coordinate $to, UnitCollection $units, float $speed_percent = 10): int
{
// Get slowest unit speed.
$slowest_speed = $units->getSlowestUnitSpeed($fromPlanet->getPlayer());
$distance = $this->calculateFleetMissionDistance($fromPlanet, $to);
return (int) max(
round(
(35000 / $speed_percent * sqrt($distance * 10 / $slowest_speed) + 10) / $this->settingsService->fleetSpeed()
),
1
);

}

/**
* Calculates the fleet mission distance between two coordinates in a galaxy map.
*
* The method determines the distance based on the differences in galaxy, system,
* and planet positions, while accounting for features like donut-shaped galaxy
* and system mechanics, empty systems, and inactive systems.
*
* Distance Calculation Rules:
* 1. If the galaxies differ:
* Distance = 20,000 * |galaxy1 - galaxy2|
* If "donut galaxy" is enabled, the shortest path between galaxies is used.
*
* 2. If the systems differ (within the same galaxy):
* Distance = 2,700 + (19 * 5 * max(|system1 - system2| - emptySystems - inactiveSystems, 1))
* If "donut system" is enabled, the shortest path between systems is used.
*
* 3. If only the planets differ (within the same system):
* Distance = 1,000 + (5 * |planet1 - planet2|)
*
* 4. If the coordinates are identical (same galaxy, system, and planet):
* Distance = 5 (minimum distance for same location).
*
* Parameters:
* - $fromPlanet: The starting planet's coordinates (PlanetService object).
* - $to: The target coordinates (Coordinate object).
* - $maxGalaxy: Maximum number of galaxies in the map.
* - $maxSystem: Maximum number of systems in each galaxy.
* - $emptySystems: Number of empty systems between start and target.
* - $inactiveSystems: Number of inactive systems between start and target.
*
* Returns:
* - int: The calculated fleet mission distance.
*/
public function calculateFleetMissionDistance(PlanetService $fromPlanet, Coordinate $to): int
{

// Calculate distance between current planet and target planet.
// ----------------------------------------
// Between galaxies:
// 20.000 x (galaxy2 - galaxy1)
// Between systems:
// 2.700 + (95 x (system2 - system1))
// Between planets:
// 1.000 + (5 x (position2 - position1))
// Between moon or debris field and planet:
// 5
// ----------------------------------------
$fromCoordinate = $fromPlanet->getPlanetCoordinates();
$distance = 0;
if ($fromCoordinate->galaxy !== $to->galaxy) {
$distance = 20000 * abs($to->galaxy - $fromCoordinate->galaxy);

$diffGalaxy = abs($fromCoordinate->galaxy - $to->galaxy);
$diffSystem = abs($fromCoordinate->system - $to->system);
$diffPlanet = abs($fromCoordinate->position - $to->position);

// If the galaxies are different
if ($diffGalaxy != 0) {
$diff2 = abs($diffGalaxy - $this->settingsService->numberOfGalaxies());

if ($diff2 < $diffGalaxy) {
return $diff2 * 20000;
} else {
return $diffGalaxy * 20000;
}
}

// If the system are different
if ($diffSystem != 0) {
$diff2 = abs($diffSystem - 499);
$deltaSystem = 0;

if ($diff2 < $diffSystem) {
$deltaSystem = $diff2;
} else {
$deltaSystem = $diffSystem;
}

//deltaSystem = Math.max(deltaSystem - emptySystems - inactiveSystems, 1);
$deltaSystem = max($deltaSystem, 1);
return $deltaSystem * 5 * 19 + 2700;
}
if ($fromCoordinate->system !== $to->system) {
$distance = 2700 + (95 * abs($to->system - $fromCoordinate->system));

// If the planet are different
if ($diffPlanet != 0) {
return $diffPlanet * 5 + 1000;
}
if ($fromCoordinate->position !== $to->position) {
$distance = 1000 + (5 * abs($to->position - $fromCoordinate->position));

// If the coordinates are the same
return 5;
}

/**
* Calculate the consumption of a fleet mission based on the current planet, target coordinates and fleet.
* @param PlanetService $fromPlanet
* @param UnitCollection $ships
* @param Coordinate $target_coordinate
* @param int $holdingTime
* @param float $speed_percent
* @param $mission
* @return float|mixed
*/
public function calculateConsumption(PlanetService $fromPlanet, UnitCollection $ships, Coordinate $target_coordinate, int $holdingTime, float $speed_percent)
{
$consumption = 0;
$holdingCosts = 0;

$distance = $this->calculateFleetMissionDistance($fromPlanet, $target_coordinate);
$duration = $this->calculateFleetMissionDuration($fromPlanet, $target_coordinate, $ships, $speed_percent);

$speedValue = max(0.5, $duration * $this->settingsService->fleetSpeed() - 10);
foreach ($ships->units as $shipEntry) {
// Get the ship object and amount
$ship = $shipEntry->unitObject; // Ship object
$shipAmount = $shipEntry->amount; // Amount of ships

// Calculate the speed of the ship
$ship_speed = $ship->properties->speed->calculate($fromPlanet->getPlayer())->totalValue;

if (!empty($shipAmount)) {
$shipSpeedValue = 35000 / $speedValue * sqrt($distance * 10 / $ship_speed);
$holdingCosts += $ship->properties->fuel->rawValue * $shipAmount * $holdingTime;

$consumption += max(
$ship->properties->fuel->rawValue * $shipAmount * $distance / 35000 *
(pow(($shipSpeedValue / 10 + 1), 2)),
1
);
}
}

// If the target is a moon or debris field on the same coordinate, the distance is always 5.
if ($distance === 0) {
$distance = 5;
// Calculate the consumption based on the speed percent
$consumption = round($consumption);

// Holding costs
if ($holdingTime > 0) {
$consumption += max(floor($holdingCosts / 10), 1);
}

// The duration is calculated as follows:
// duration = (10 + (3500 / speed modifier as decimal) * ((distance * 10) / lowest fleet speed) ^ 0.5) / universe fleet speed
return (int)((10 + (3500 / 1) * (($distance * 10) / $slowest_speed) ** 0.5) / $this->settingsService->fleetSpeed());
return $consumption;
}

/**
Expand Down Expand Up @@ -150,7 +254,7 @@ public function getActiveFleetMissionsForCurrentPlayer(): Collection
$query->where('user_id', $this->player->getId())
->orWhereIn('planet_id_to', $planetIds);
})
->where('processed', 0);
->where('processed', 0);

return $query->orderBy('time_arrival')->get();
}
Expand Down Expand Up @@ -228,7 +332,7 @@ public function getResources(FleetMission $mission): Resources
return new Resources(
$mission->metal,
$mission->crystal,
$mission->deuterium,
$mission->deuterium + ($mission->deuterium_consumption / 2), //if mission deployment: Add half of the consumed deuterium
0
);
}
Expand Down Expand Up @@ -286,13 +390,13 @@ public function getFleetMissionById(int $id, bool $only_active = true): FleetMis
* @return FleetMission
* @throws Exception
*/
public function createNewFromPlanet(PlanetService $planet, Coordinate $targetCoordinate, PlanetType $targetType, int $missionType, UnitCollection $units, Resources $resources, int $parent_id = 0): FleetMission
public function createNewFromPlanet(PlanetService $planet, Coordinate $targetCoordinate, PlanetType $targetType, int $missionType, UnitCollection $units, Resources $resources, float $speed_percent, int $parent_id = 0): FleetMission
{
$missionObject = $this->gameMissionFactory->getMissionById($missionType, [
'fleetMissionService' => $this,
'messageService' => $this->messageService,
]);
return $missionObject->start($planet, $targetCoordinate, $targetType, $units, $resources, $parent_id);
return $missionObject->start($planet, $targetCoordinate, $targetType, $units, $resources, $speed_percent, $parent_id);
}

/**
Expand Down
9 changes: 5 additions & 4 deletions app/Services/PlanetService.php
Original file line number Diff line number Diff line change
Expand Up @@ -531,16 +531,17 @@ public function deductResources(Resources $resources, bool $save_planet = true):
*/
public function hasResources(Resources $resources): bool
{
if (!empty($resources->metal->get()) && $this->metal()->get() < $resources->metal->get()) {

if (!empty($resources->metal->get()) && ceil($this->metal()->get()) < $resources->metal->get()) {
return false;
}
if (!empty($resources->crystal->get()) && $this->crystal()->get() < $resources->crystal->get()) {
if (!empty($resources->crystal->get()) && ceil($this->crystal()->get()) < $resources->crystal->get()) {
return false;
}
if (!empty($resources->deuterium->get()) && $this->deuterium()->get() < $resources->deuterium->get()) {
if (!empty($resources->deuterium->get()) && ceil($this->deuterium()->get()) < $resources->deuterium->get()) {
return false;
}
if (!empty($resources->energy->get()) && $this->energyProduction()->get() < $resources->energy->get()) {
if (!empty($resources->energy->get()) && ceil($this->energyProduction()->get()) < $resources->energy->get()) {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion app/Services/PlayerService.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ public function getEmail(): string
public function getResearchLevel(string $machine_name): int
{
$research = ObjectService::getResearchObjectByMachineName($machine_name);
$research_level = $this->user_tech->{$research->machine_name};

$research_level = $this->user_tech->{$research->machine_name} ?? 0;
if ($research_level) {
return $research_level;
} else {
Expand Down
Loading

0 comments on commit f1576cf

Please sign in to comment.