Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions app/Http/Controllers/TechtreeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,60 @@ public function ajax(Request $request, PlayerService $player): View
'astrophysics_table' => $this->getAstrophysicsTable($object, $player),
]);
} elseif ($tab === 3) {
$planet = $player->planets->current();

$defenseAll = ObjectService::getDefenseObjects();
$missiles = array_values(array_filter($defenseAll, fn ($d) => str_ends_with($d->machine_name, '_missile')));
$defenseOnly = array_values(array_filter($defenseAll, fn ($d) => !str_ends_with($d->machine_name, '_missile')));

$categories = [
'building' => [
'label_key' => 't_ingame.techtree.technology_category_construction',
'objects' => [...ObjectService::getBuildingObjects(), ...ObjectService::getStationObjects()],
],
'research' => [
'label_key' => 't_ingame.techtree.technology_category_research',
'objects' => ObjectService::getResearchObjects(),
],
'ship' => [
'label_key' => 't_ingame.techtree.technology_category_ships',
'objects' => ObjectService::getShipObjects(),
],
'defense' => [
'label_key' => 't_ingame.techtree.technology_category_defense',
'objects' => $defenseOnly,
],
'missile' => [
'label_key' => 't_ingame.techtree.technology_category_rockets',
'objects' => $missiles,
],
];

// Pre-compute direct requirements (with current level) for every object that has requirements.
$requirements_by_object = [];
foreach ($categories as $category) {
foreach ($category['objects'] as $cat_object) {
if (empty($cat_object->requirements)) {
continue;
}
$reqs = [];
foreach ($cat_object->requirements as $requirement) {
$required_object = ObjectService::getObjectByMachineName($requirement->object_machine_name);
if ($required_object->type === GameObjectType::Research) {
$current_level = $player->getResearchLevel($required_object->machine_name);
} else {
$current_level = $planet->getObjectLevel($required_object->machine_name);
}
$reqs[] = new TechtreeRequirement(1, 0, null, $required_object, $requirement->level, $current_level);
}
$requirements_by_object[$cat_object->id] = $reqs;
}
}

return view('ingame.techtree.technology')->with([
'object' => $object,
'categories' => $categories,
'requirements_by_object' => $requirements_by_object,
]);
} elseif ($tab === 4) {
return view('ingame.techtree.applications')->with([
Expand Down
7 changes: 7 additions & 0 deletions resources/lang/en/t_ingame.php
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,13 @@
'is_requirement_for' => 'is a requirement for',
'level' => 'Level',

// Technology tab categories
'technology_category_construction' => 'Construction',
'technology_category_research' => 'Research',
'technology_category_ships' => 'Ships',
'technology_category_defense' => 'Defense',
'technology_category_rockets' => 'Rockets',

// Shared table columns
'col_level' => 'Level',
'col_difference' => 'Difference',
Expand Down
7 changes: 7 additions & 0 deletions resources/lang/it/t_ingame.php
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,13 @@
'is_requirement_for' => 'è un requisito per',
'level' => 'Livello',

// Categorie scheda Tecnologia
'technology_category_construction' => 'Costruzioni',
'technology_category_research' => 'Ricerca',
'technology_category_ships' => 'Navi',
'technology_category_defense' => 'Difese',
'technology_category_rockets' => 'Missili',

// Colonne tabella condivise
'col_level' => 'Livello',
'col_difference' => 'Differenza',
Expand Down
7 changes: 7 additions & 0 deletions resources/lang/nl/t_ingame.php
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,13 @@
'is_requirement_for' => 'is een vereiste voor',
'level' => 'Niveau',

// Technologie-tab categorieën
'technology_category_construction' => 'Constructie',
'technology_category_research' => 'Onderzoek',
'technology_category_ships' => 'Schepen',
'technology_category_defense' => 'Verdediging',
'technology_category_rockets' => 'Raketten',

// Gedeelde tabelkolommen
'col_level' => 'Niveau',
'col_difference' => 'Verschil',
Expand Down
6 changes: 6 additions & 0 deletions resources/lang/zh-TW/t_ingame.php
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,12 @@
'is_requirement_for' => '是...的需求',
'level' => '等級',

'technology_category_construction' => '建築',
'technology_category_research' => '研究',
'technology_category_ships' => '艦船',
'technology_category_defense' => '防禦',
'technology_category_rockets' => '火箭',

'col_level' => '等級',
'col_difference' => '差異',
'col_diff_per_level' => '差異/等級',
Expand Down
62 changes: 53 additions & 9 deletions resources/views/ingame/techtree/technology.blade.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,61 @@
@php
use OGame\GameObjects\Models\Abstracts\GameObject;
use OGame\GameObjects\Models\Techtree\TechtreeRequirement;
/** @var GameObject $object */
/** @var array<string, array{label_key: string, objects: array<GameObject>}> $categories */
/** @var array<int, array<TechtreeRequirement>> $requirements_by_object */
@endphp

<div id="technologytree" data-title="{{ __('t_ingame.techtree.page_title') }} - {{ $object->title }}">
@include('ingame.techtree.partials.nav', ['currentAction' => 'technologies', 'objectId' => $object->id])

<div class="content technology">
<p class="hint">
{{ __('t_ingame.techtree.no_requirements') }}
</p>
<div class="content technologies">
@foreach ($categories as $categoryKey => $category)
@if (empty($category['objects']))
@continue
@endif
<h1 data-category="{{ $categoryKey }}">{{ __($category['label_key']) }}</h1>
<ul>
@foreach ($category['objects'] as $categoryObject)
@php($reqs = $requirements_by_object[$categoryObject->id] ?? [])
<li class="{{ $categoryObject->class_name }}">
<a class="technology sprite_before sprite_tiny {{ $categoryObject->class_name }} overlay"
href="{{ route('techtree.ajax', ['tab' => 2, 'object_id' => $categoryObject->id]) }}"
data-overlay-same="true">
{{ $categoryObject->title }}
</a>
@if (!empty($reqs))
<a class="prerequisites overlay"
href="{{ route('techtree.ajax', ['tab' => 1, 'object_id' => $categoryObject->id]) }}"
data-overlay-same="true">
<ul>
@foreach ($reqs as $requirement)
<li class="{{ $requirement->levelCurrent >= $requirement->levelRequired ? 'fulfilled' : 'unfulfilled' }}">
{{ $requirement->gameObject->title }}
({{ __('t_ingame.techtree.level') }}
@if ($requirement->levelCurrent >= $requirement->levelRequired)
{{ $requirement->levelRequired }}
@else
{{ $requirement->levelCurrent }}/{{ $requirement->levelRequired }}
@endif
)
</li>
@endforeach
</ul>
</a>
@endif
</li>
@endforeach
</ul>
@endforeach
</div>
</div>

<script type="text/javascript">
$(
function(){
initOverlayName();
}
);
$(function(){
initOverlayName();
$('#technologytree .content.technologies > h1').off('click.techtree').on('click.techtree', function(){
$(this).next('ul').slideToggle(150);
});
});
</script>
77 changes: 77 additions & 0 deletions tests/Feature/TechtreeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,83 @@ public function testTechtreeInfoPopups(): void
}
}

/**
* Verify that techtree technology popups for all objects return HTTP 200.
*/
public function testTechtreeTechnologyPopupsHttp200(): void
{
foreach (ObjectService::getObjects() as $object) {
$response = $this->get('ajax/techtree?tab=3&object_id=' . $object->id);

try {
$response->assertStatus(200);
} catch (\PHPUnit\Framework\AssertionFailedError $e) {
$this->fail('AJAX techtree technology page for "' . $object->title . '" does not return HTTP 200.');
}
}
}

/**
* Verify that the technology tab shows the global category list with prerequisites status.
*/
public function testTechtreeTechnologyTabGlobalList(): void
{
$object = ObjectService::getObjectByMachineName('metal_mine');

$response = $this->get('ajax/techtree?tab=3&object_id=' . $object->id);
$response->assertStatus(200);

// Category headings
$response->assertSee('data-category="building"', false);
$response->assertSee('data-category="research"', false);
$response->assertSee('data-category="ship"', false);
$response->assertSee('data-category="defense"', false);
$response->assertSee('data-category="missile"', false);
$response->assertSee(__('t_ingame.techtree.technology_category_construction'));
$response->assertSee(__('t_ingame.techtree.technology_category_research'));
$response->assertSee(__('t_ingame.techtree.technology_category_ships'));
$response->assertSee(__('t_ingame.techtree.technology_category_defense'));
$response->assertSee(__('t_ingame.techtree.technology_category_rockets'));

// Sample objects from each category
$response->assertSee('class="technology sprite_before sprite_tiny metalMine overlay"', false);
$response->assertSee('class="technology sprite_before sprite_tiny energyTechnology overlay"', false);
$response->assertSee('class="technology sprite_before sprite_tiny fighterLight overlay"', false);
$response->assertSee('class="technology sprite_before sprite_tiny rocketLauncher overlay"', false);
$response->assertSee('class="technology sprite_before sprite_tiny missileInterceptor overlay"', false);

// Fusion plant prerequisites should be unfulfilled for a fresh account.
$fusionPlant = ObjectService::getObjectByMachineName('fusion_plant');
$response->assertSee('class="technology sprite_before sprite_tiny fusionPlant overlay"', false);
$response->assertSee('class="prerequisites overlay"', false);
$content = $response->getContent();
if ($content === false) {
$this->fail('AJAX techtree technology page returned no content.');
}
$this->assertMatchesRegularExpression(
'/<li class="fusionPlant">.*?class="unfulfilled"/s',
$content,
'Fusion plant prerequisites should be unfulfilled for a fresh account.'
);

// Meet fusion plant requirements and assert those prerequisites become fulfilled.
$this->planetSetObjectLevel('deuterium_synthesizer', 5);
$this->playerSetResearchLevel('energy_technology', 3);

$response = $this->get('ajax/techtree?tab=3&object_id=' . $object->id);
$response->assertStatus(200);
$content = $response->getContent();
if ($content === false) {
$this->fail('AJAX techtree technology page returned no content.');
}

$this->assertMatchesRegularExpression(
'/<li class="fusionPlant">.*?<li class="fulfilled">.*?<\/li>.*?<li class="fulfilled">/s',
$content,
'Fusion plant prerequisites should both be marked fulfilled after meeting requirements.'
);
}

/**
* Verify that techtree applications popups for all objects return HTTP 200.
*/
Expand Down
Loading