'datetime', 'in_jail_until' => 'datetime', 'last_action_at' => 'datetime', '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 attacks made by this character. */ public function attacks(): HasMany { return $this->hasMany(Attack::class, 'attacker_id'); } /** * Get the attacks received by this character. */ public function attacksReceived(): HasMany { return $this->hasMany(Attack::class, 'defender_id'); } /** * 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 { $base = $this->attributes['defense'] ?? 0; $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); } /** * 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; $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})"; } }