152 lines
3.9 KiB
PHP
152 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Enums\CrimeDifficulty;
|
|
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 string $name
|
|
* @property string $slug
|
|
* @property string|null $description
|
|
* @property CrimeDifficulty $difficulty
|
|
* @property float $success_rate
|
|
* @property int $reward_min
|
|
* @property int $reward_max
|
|
* @property int $experience
|
|
* @property int $energy_cost
|
|
* @property int $nerve_cost
|
|
* @property int $cooldown
|
|
* @property int|null $requires_level
|
|
* @property int|null $location_id
|
|
* @property \Illuminate\Support\Carbon $created_at
|
|
* @property \Illuminate\Support\Carbon $updated_at
|
|
*/
|
|
class Crime extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'name',
|
|
'slug',
|
|
'description',
|
|
'difficulty',
|
|
'success_rate',
|
|
'reward_min',
|
|
'reward_max',
|
|
'experience',
|
|
'energy_cost',
|
|
'nerve_cost',
|
|
'cooldown',
|
|
'requires_level',
|
|
'location_id',
|
|
];
|
|
|
|
protected $casts = [
|
|
'difficulty' => CrimeDifficulty::class,
|
|
'success_rate' => 'float',
|
|
];
|
|
|
|
/**
|
|
* Get the location where this crime can be committed.
|
|
*/
|
|
public function location(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Location::class);
|
|
}
|
|
|
|
/**
|
|
* Get the crime attempts for this crime.
|
|
*/
|
|
public function attempts(): HasMany
|
|
{
|
|
return $this->hasMany(CrimeAttempt::class);
|
|
}
|
|
|
|
/**
|
|
* Check if a character can attempt this crime
|
|
*/
|
|
public function canBeAttemptedBy(Character $character): bool
|
|
{
|
|
// Check level requirement
|
|
if ($this->requires_level && $character->level < $this->requires_level) {
|
|
return false;
|
|
}
|
|
|
|
// Check energy
|
|
if ($character->energy < $this->energy_cost) {
|
|
return false;
|
|
}
|
|
|
|
// Check nerve
|
|
if ($character->nerve < $this->nerve_cost) {
|
|
return false;
|
|
}
|
|
|
|
// Check location (if crime is location-specific)
|
|
if ($this->location_id && $character->location_id !== $this->location_id) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Calculate the success rate for a specific character
|
|
*/
|
|
public function calculateSuccessRate(Character $character): float
|
|
{
|
|
$baseRate = $this->success_rate;
|
|
$difficultyModifier = $this->difficulty->successModifier();
|
|
$levelModifier = $character->level * 0.01; // +1% per level
|
|
|
|
$rate = $baseRate + $difficultyModifier + $levelModifier;
|
|
|
|
// Clamp between 10% and 95%
|
|
return max(0.10, min(0.95, $rate));
|
|
}
|
|
|
|
/**
|
|
* Calculate the reward for a successful crime
|
|
*/
|
|
public function calculateReward(Character $character): int
|
|
{
|
|
$baseReward = random_int($this->reward_min, $this->reward_max);
|
|
$difficultyMultiplier = $this->difficulty->rewardMultiplier();
|
|
$levelMultiplier = 1 + ($character->level * 0.01); // +1% per level
|
|
|
|
return (int) ($baseReward * $difficultyMultiplier * $levelMultiplier);
|
|
}
|
|
|
|
/**
|
|
* Calculate the experience reward
|
|
*/
|
|
public function calculateExperience(Character $character): int
|
|
{
|
|
$baseExp = $this->experience;
|
|
$levelMultiplier = 1 + ($character->level * 0.01);
|
|
|
|
return (int) ($baseExp * $levelMultiplier);
|
|
}
|
|
|
|
/**
|
|
* Get the display name for the difficulty
|
|
*/
|
|
public function getDifficultyLabelAttribute(): string
|
|
{
|
|
return $this->difficulty->label();
|
|
}
|
|
|
|
/**
|
|
* Get the color class for the difficulty badge
|
|
*/
|
|
public function getDifficultyColorAttribute(): string
|
|
{
|
|
return $this->difficulty->color();
|
|
}
|
|
}
|