feat(city): add plaza exercise system with health tracking

- Adds CityPlazas support class for deterministic public plaza generation with outdoor gym equipment
- Implements exercise and stop-exercise actions with proximity validation to equipment
- Introduces health (0-100) and exercise_count attributes to Character model
- Reduces hospital stay duration from two game days to one game hour
- Adds 3D gym equipment rendering (bench, bars, bike, treadmill) in city viewer
- Includes exercise state machine handling in world ticker with energy drain
- Adds comprehensive PlazaExerciseTest and updates HospitalAdmissionTest
- Provides localized UI strings for health HUD and exercise prompts
This commit is contained in:
2026-10-17 22:10:50 -03:00
parent 79ce2a1825
commit 090b530481
18 changed files with 848 additions and 21 deletions
+6 -6
View File
@@ -11,7 +11,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
/**
* Traffic accident → hospital admission for two game days.
* Traffic accident → hospital admission for one game hour.
*/
class HospitalAdmissionTest extends TestCase
{
@@ -34,9 +34,9 @@ class HospitalAdmissionTest extends TestCase
}
/**
* A vehicle collision admits the character for two game days at the hospital.
* A vehicle collision admits the character for one game hour at the hospital.
*/
public function test_accident_admits_character_for_two_game_days(): void
public function test_accident_admits_character_for_one_game_hour(): void
{
$response = $this->postJson('/city/actions/accident');
$response->assertOk()
@@ -51,7 +51,7 @@ class HospitalAdmissionTest extends TestCase
$this->character->hospitalized_until->getTimestamp(),
5,
);
$this->assertSame(Character::HOSPITAL_STAY_SECONDS, 480, 'Two game days = 2 × 240s');
$this->assertSame(Character::HOSPITAL_STAY_SECONDS, 10, 'One game hour = 240s / 24');
$hospital = Building::where('type', Building::TYPE_HOSPITAL)->firstOrFail();
$this->assertSame((float) $hospital->pos_x, (float) $this->character->pos_x);
@@ -88,9 +88,9 @@ class HospitalAdmissionTest extends TestCase
}
/**
* After the two-day stay the ticker releases the character.
* After the one-hour stay the ticker releases the character.
*/
public function test_ticker_releases_after_two_game_days(): void
public function test_ticker_releases_after_one_game_hour(): void
{
$this->character->admitToHospital();
// Move the stay into the past to simulate elapsed time.