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
+20 -6
View File
@@ -17,8 +17,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
*/
#[Fillable([
'user_id', 'city_id', 'name', 'skin', 'hair', 'shirt',
'pos_x', 'pos_y', 'pos_z', 'money', 'energy', 'hunger', 'thirst',
'state', 'job_id', 'house_id', 'education', 'is_online', 'last_tick_at',
'pos_x', 'pos_y', 'pos_z', 'money', 'energy', 'hunger', 'thirst', 'health',
'state', 'job_id', 'house_id', 'education', 'exercise_count', 'is_online', 'last_tick_at',
'hospitalized_until',
])]
class Character extends Model
@@ -34,6 +34,13 @@ class Character extends Model
public const STATE_STUDYING = 'studying';
/**
* Character is exercising on public plaza gym equipment.
*
* @var string
*/
public const STATE_EXERCISING = 'exercising';
/**
* Character admitted to the hospital after a traffic accident.
*
@@ -42,11 +49,14 @@ class Character extends Model
public const STATE_HOSPITAL = 'hospital';
/**
* Hospital stay length in seconds (two game days of 240s each).
* Hospital stay length in seconds (one game hour).
*
* The day/night cycle is 240 real seconds per 24 game hours, so one
* game hour equals 10 real seconds.
*
* @var int
*/
public const HOSPITAL_STAY_SECONDS = 480;
public const HOSPITAL_STAY_SECONDS = 10;
/**
* Default hospital bed coordinates used when no hospital building exists.
@@ -153,8 +163,10 @@ class Character extends Model
'energy' => 100,
'hunger' => 100,
'thirst' => 100,
'health' => 100,
'state' => self::STATE_AWAKE,
'education' => 0,
'exercise_count' => 0,
'is_online' => false,
]);
@@ -189,7 +201,9 @@ class Character extends Model
'energy' => 'integer',
'hunger' => 'integer',
'thirst' => 'integer',
'health' => 'integer',
'education' => 'integer',
'exercise_count' => 'integer',
'is_online' => 'boolean',
'last_tick_at' => 'datetime',
'hospitalized_until' => 'datetime',
@@ -207,7 +221,7 @@ class Character extends Model
}
/**
* Admit the character to the hospital for two game days after an accident.
* Admit the character to the hospital for one game hour after an accident.
*
* Teleports them to the city hospital bed and returns the bed position.
*
@@ -236,7 +250,7 @@ class Character extends Model
}
/**
* Release the character from the hospital when the stay has elapsed.
* Release the character from the hospital when the one-hour stay has elapsed.
*/
public function releaseIfHospitalStayOver(): bool
{