Files
thecrimesynticate/app/Models/Character.php
T

473 lines
11 KiB
PHP
Raw Normal View History

2026-06-27 14:38:18 +03:00
<?php
namespace App\Models;
use App\Enums\CharacterStatus;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property int $id
* @property int $user_id
* @property string $name
* @property string $gender
* @property int $level
* @property int $experience
* @property int $money
* @property int $bank
* @property int $energy
* @property int $max_energy
* @property int $nerve
* @property int $max_nerve
* @property \Illuminate\Support\Carbon|null $nerve_regen_at
2026-06-27 14:38:18 +03:00
* @property int $health
* @property int $max_health
* @property int $strength
* @property int $defense
* @property int $speed
* @property int $dexterity
* @property int $location_id
* @property int|null $faction_id
* @property \Illuminate\Support\Carbon|null $in_hospital_until
* @property \Illuminate\Support\Carbon|null $in_jail_until
* @property \Illuminate\Support\Carbon $last_action_at
* @property CharacterStatus $status
* @property \Illuminate\Support\Carbon $created_at
* @property \Illuminate\Support\Carbon $updated_at
*/
class Character extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'name',
'gender',
'level',
'experience',
'money',
'bank',
'energy',
'max_energy',
'nerve',
'max_nerve',
'nerve_regen_at',
'health',
'max_health',
2026-06-27 14:38:18 +03:00
'strength',
'defense',
'speed',
'dexterity',
'location_id',
'faction_id',
'in_hospital_until',
'in_jail_until',
'last_action_at',
'status',
];
protected $casts = [
'in_hospital_until' => 'datetime',
'in_jail_until' => 'datetime',
'last_action_at' => 'datetime',
'nerve_regen_at' => 'datetime',
2026-06-27 14:38:18 +03:00
'status' => CharacterStatus::class,
];
/**
* Get the user that owns the character.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the location where the character is.
*/
public function location(): BelongsTo
{
return $this->belongsTo(Location::class);
}
/**
* Get the faction the character belongs to.
* Phase 2: Faction System
*/
// public function faction(): BelongsTo
// {
// return $this->belongsTo(Faction::class)->withDefault();
// }
/**
* Get the inventory items for the character.
*/
public function inventory(): HasMany
{
return $this->hasMany(Inventory::class);
}
/**
* Get the crime attempts for the character.
*/
public function crimeAttempts(): HasMany
{
return $this->hasMany(CrimeAttempt::class);
}
/**
* Get the activity logs for the character.
*/
public function activityLogs(): HasMany
{
return $this->hasMany(ActivityLog::class);
}
/**
* Check if character can perform actions
*/
public function canAct(): bool
{
return $this->status === CharacterStatus::ACTIVE && $this->health > 0;
}
/**
* Check if character is in hospital
*/
public function isInHospital(): bool
{
return $this->status === CharacterStatus::IN_HOSPITAL
|| ($this->in_hospital_until && $this->in_hospital_until->isFuture());
}
/**
* Check if character is in jail
*/
public function isInJail(): bool
{
return $this->status === CharacterStatus::IN_JAIL
|| ($this->in_jail_until && $this->in_jail_until->isFuture());
}
/**
* Check if character is alive
*/
public function isAlive(): bool
{
return $this->health > 0;
}
/**
* Get energy percentage
*/
public function getEnergyPercentageAttribute(): float
{
if ($this->max_energy <= 0) {
return 0;
}
return min(100, ($this->energy / $this->max_energy) * 100);
}
/**
* Get health percentage
*/
public function getHealthPercentageAttribute(): float
{
if ($this->max_health <= 0) {
return 0;
}
return min(100, ($this->health / $this->max_health) * 100);
}
/**
* Get total attack power
*/
public function getAttackPowerAttribute(): int
{
$base = $this->strength * config('game.skills.strength.attack_bonus', 0.5);
$weapon = $this->inventory()->where('equipped', true)->whereHas('item', function($q) {
$q->where('type', 'weapon');
})->first();
$weaponBonus = $weapon ? $weapon->item->attack_bonus : 0;
return (int) ($base + $weaponBonus + config('game.combat.base_damage', 5));
}
/**
* Get total defense
*/
public function getDefenseAttribute(): int
{
2026-06-28 03:19:32 +03:00
$base = $this->attributes['defense'] ?? 0;
2026-06-27 14:38:18 +03:00
$armor = $this->inventory()->where('equipped', true)->whereHas('item', function($q) {
$q->where('type', 'armor');
})->first();
$armorBonus = $armor ? $armor->item->defense_bonus : 0;
return $base + $armorBonus;
}
/**
* Get experience needed for next level
*/
public function getExperienceForNextLevelAttribute(): int
{
$base = config('game.leveling.exp_per_level', 1000);
$multiplier = config('game.leveling.exp_multiplier', 1.20);
if (config('game.leveling.exp_curve') === 'exponential') {
return (int) ($base * pow($multiplier, $this->level - 1));
}
return $base;
}
/**
* Check if character has enough energy for an action
*/
public function hasEnergy(int $amount): bool
{
return $this->energy >= $amount;
}
/**
* Consume energy
*/
public function consumeEnergy(int $amount): bool
{
if (!$this->hasEnergy($amount)) {
return false;
}
$this->energy -= $amount;
$this->save();
return true;
}
/**
* Add energy (up to max)
*/
public function addEnergy(int $amount): void
{
$this->energy = min($this->max_energy, $this->energy + $amount);
$this->save();
}
/**
* Check if character has enough nerve for an action
*/
public function hasNerve(int $amount): bool
{
return $this->nerve >= $amount;
}
/**
* Consume nerve
*/
public function consumeNerve(int $amount): bool
{
if (!$this->hasNerve($amount)) {
return false;
}
$this->nerve -= $amount;
$this->save();
return true;
}
/**
* Add nerve (up to max)
*/
public function addNerve(int $amount): void
{
$this->nerve = min($this->max_nerve, $this->nerve + $amount);
$this->save();
}
/**
* Get nerve percentage
*/
public function getNervePercentageAttribute(): float
{
if ($this->max_nerve <= 0) {
return 0;
}
return min(100, ($this->nerve / $this->max_nerve) * 100);
}
2026-06-27 14:38:18 +03:00
/**
* Set energy to max
*/
public function restoreEnergy(): void
{
$this->energy = $this->max_energy;
$this->save();
}
/**
* Take damage
*/
public function takeDamage(int $amount): int
{
$defenseReduction = $this->defense * config('game.combat.defense_reduction', 0.5);
$actualDamage = max(1, $amount - $defenseReduction);
$this->health -= $actualDamage;
$this->save();
if ($this->health <= 0) {
$this->health = 0;
$this->status = CharacterStatus::DEAD;
$this->save();
}
return $actualDamage;
}
/**
* Heal health
*/
public function heal(int $amount): void
{
$this->health = min($this->max_health, $this->health + $amount);
if ($this->status === CharacterStatus::DEAD && $this->health > 0) {
$this->status = CharacterStatus::ACTIVE;
}
$this->save();
}
/**
* Add experience
*/
public function addExperience(int $amount): void
{
$this->experience += $amount;
while ($this->experience >= $this->experience_for_next_level && $this->level < config('game.leveling.max_level', 100)) {
$this->levelUp();
}
$this->save();
}
/**
* Level up the character
*/
public function levelUp(): void
{
$this->level++;
$this->experience -= $this->experience_for_next_level;
$this->max_health += 5;
$this->max_energy += 5;
$this->max_nerve += 2;
2026-06-27 14:38:18 +03:00
$this->health = $this->max_health;
$this->energy = $this->max_energy;
$this->money += 1000;
$this->save();
}
/**
* Add money
*/
public function addMoney(int $amount): void
{
$this->money += $amount;
$this->save();
}
/**
* Remove money
*/
public function removeMoney(int $amount): bool
{
if ($this->money < $amount) {
return false;
}
$this->money -= $amount;
$this->save();
return true;
}
/**
* Check if character has enough money
*/
public function hasMoney(int $amount): bool
{
return $this->money >= $amount;
}
/**
* Deposit money to bank
*/
public function depositToBank(int $amount): bool
{
if (!$this->hasMoney($amount)) {
return false;
}
$maxBank = config('game.economy.max_bank', 10000000);
if ($this->bank + $amount > $maxBank) {
return false;
}
$this->money -= $amount;
$this->bank += $amount;
$this->save();
return true;
}
/**
* Withdraw money from bank
*/
public function withdrawFromBank(int $amount): bool
{
if ($this->bank < $amount) {
return false;
}
$this->bank -= $amount;
$this->money += $amount;
$this->save();
return true;
}
/**
* Apply daily bank interest
*/
public function applyBankInterest(): void
{
$interestRate = config('game.economy.bank_interest', 0.05);
$interest = (int) ($this->bank * $interestRate);
$maxBank = config('game.economy.max_bank', 10000000);
if ($this->bank + $interest > $maxBank) {
$interest = $maxBank - $this->bank;
}
$this->bank += $interest;
$this->save();
}
/**
* Get the character's full name with level
*/
public function getFullNameAttribute(): string
{
return "{$this->name} (Lv. {$this->level})";
}
}