"Заточка" предметов

Старая версия на php5.4 переделанная на php7+. Работает со всеми проклинаемой текстовой строкой параметров предмета data add_s1=4|add_s3=6|add_m1=20|add_m3=25|hpAll=500|итд. Увеличивает каждый существующий на предмете стат на +1, параметр на +3, здоровье\мана на +30. Чем толще заточка тем больше шансов, что следующая провалится.

STAT_NAMES, MF_NAMES, PARAM_NAMES — в идеале вытягивать из базы или из существующего кода. Но помнить, что всё что тут указано будет увеличиваться.

<?php
declare(strict_types=1);

class Sharpen
{
    private int $sharp_chance;
    private array $itemDataArray;
    private bool $status;
    private string $item_data_default;

    /** === Настройки скрипта. */

    /** Базовая стоимость заточки */
    public const SHARP_PRICE = 50;
    /** На сколько повышаем мф. */
    public const SHARP_MF_BONUS = 5;
    /** На сколько повышаем статы. */
    public const SHARP_STAT_BONUS = 1;
    /** На сколько повышаем хиты и ману. */
    public const SHARP_PARAM_BONUS = 30;

    /** Статы */
    private const STAT_NAMES = [
        's1' => 'Сила',
        's2' => 'Ловкость',
        's3' => 'Интуиция',
        's4' => 'Выносливость',
        's5' => 'Интеллект',
        's6' => 'Мудрость',
        's7' => 'Духовность',
        's8' => 'Воля',
        's9' => 'Свобода духа',
        's10' => 'Божественность',
        's11' => 'Энергия',
    ];

    /** Модификаторы */
    private const MF_NAMES = [
        'm1' => 'Мф. критического удара (%)',
        'm2' => 'Мф. против критического удара (%)',
        'm3' => 'Мф. мощности крит. удара (%)',
        'm4' => 'Мф. увертывания (%)',
        'm5' => 'Мф. против увертывания (%)',
        'm6' => 'Мф. контрудара (%)',
        'm7' => 'Мф. парирования (%)',
        'm8' => 'Мф. блока щитом (%)',
        'm9' => 'Мф. удара сквозь броню (%)',
        'm14' => 'Мф. абс. критического удара (%)',
        'm15' => 'Мф. абс. увертывания (%)',
        'm16' => 'Мф. абс. парирования (%)',
        'm17' => 'Мф. абс. контрудара (%)',
        'm18' => 'Мф. абс. блока щитом (%)',
        'm19' => 'Мф. абс. магический промах (%)',
        'm20' => 'Мф. удача (%)',
    ];

    /** Параметры */
    private const PARAM_NAMES = [
        'hpAll' => 'Уровень жизни (HP)',
        'mpAll' => 'Уровень маны',
        'enAll' => 'Уровень энергии',
    ];

    /** === Конец настроек. */

    public function __construct(string $item_data, string $item_data_default)
    {
        $this->item_data_default = $item_data_default;
        $this->itemDataArray = $this->strToArr($item_data);

        if (!isset($this->itemDataArray['sharp_level'])) {
            $this->itemDataArray['sharp_level'] = 0;
        }

        $this->sharp_chance = $this->successRateCheck();
    }

    /**
     * Запуск заточки и возврат результата
     */
    public function process(): array
    {
        $this->sharp();

        return [
            'new_item_data' => $this->arrToStr($this->itemDataArray),
            'operation_cost' => self::SHARP_PRICE * $this->itemDataArray['sharp_level'],
            'status' => $this->status,
        ];
    }

    private function successRateCheck(): int
    {
        return $this->itemDataArray['sharp_level'] < 10
            ? 100 - $this->itemDataArray['sharp_level'] * 5
            : 5;
    }

    private function sharp(): void
    {
        if (mt_rand(0, 100) > $this->sharp_chance) {
            $this->resetItem();
            $this->status = false;
        } else {
            $this->updateItem();
            $this->status = true;
        }
    }

    private function updateItem(): void
    {
        $statsArray = $this->arrMaker(self::STAT_NAMES, self::SHARP_STAT_BONUS);
        $paramArray = $this->arrMaker(self::PARAM_NAMES, self::SHARP_PARAM_BONUS, false);
        $mfArray = $this->arrMaker(self::MF_NAMES, self::SHARP_MF_BONUS);

        $finArray = array_merge($statsArray, $paramArray, $mfArray);
        $finArray = array_intersect_key($finArray, $this->itemDataArray);

        foreach ($finArray as $key => $value) {
            $this->itemDataArray[$key] = ($this->itemDataArray[$key] ?? 0) + $value;
        }

        $this->itemDataArray['sharp_level']++;
    }

    private function resetItem(): void
    {
        $this->itemDataArray = $this->strToArr($this->item_data_default);
        $this->itemDataArray['sharp_level'] = 0;
    }

    private function strToArr(string $string): array
    {
        $arr = [];
        foreach (explode('|', $string) as $pair) {
            [$k, $v] = array_pad(explode('=', $pair, 2), 2, null);
            $arr[$k] = $v === null || $v === '' ? null : $v;
        }
        return $arr;
    }

    private function arrToStr(array $array): string
    {
        return implode('|', array_map(static fn($k, $v) => "$k=$v", array_keys($array), $array));
    }

    private function arrMaker(array $array, int $values = 0, bool $withPrefix = true): array
    {
        // К некоторым значениям префикс 'add_' не добавляется!
        $keys = $withPrefix
            ? array_map(static fn($key) => 'add_' . $key, array_keys($array))
            : array_keys($array);

        return array_fill_keys($keys, $values);
    }
}

Проверяем:

$itemData = 'add_s1=4|add_s3=6|add_m1=20|add_m3=25|hpAll=500';
$baseData = 'add_s1=4|add_s3=6|add_m1=20|add_m3=25|hpAll=500';
$cost = 0; $fails = 0; $sharp_level = 0; $uses = 50; $sharp_level_max = 0;


for ($i = 0; $i < $uses; $i++) {
    $s = new Sharpen($itemData, $baseData);
    $use = $s->process();
    $itemData = $use['new_item_data'];
    $cost += $use['operation_cost'];
    $sharp_level++;
    if (!$use['status']) {
        $fails++;
        $sharp_level = 0;
    }
    if ($sharp_level > $sharp_level_max) {
        $sharp_level_max = $sharp_level;
    }
    //var_dump($use); - раскомментируй, если хочешь увидеть пошагово.
    echo "<p>";
}

echo "Попыток: $i<br>
Уровень заточки: $sharp_level, доходило до $sharp_level_max<br> 
Сломаных заточек: $fails<br> 
Потраченных денег: $cost<br><br>
Было: $baseData<br>Стало: $itemData";

// Попыток: 50
// Уровень заточки: 4, доходило до 7
// Сломаных заточек: 9
// Потраченных денег: 5800
// 
// Было: add_s1=4|add_s3=6|add_m1=20|add_m3=25|hpAll=500
// Стало: add_s1=8|add_s3=10|add_m1=40|add_m3=45|hpAll=620|sharp_level=4

Так это получается не заточка, а просто улучшение предмета, так как увеличивается не конкретный урон от заточки, а все параметры которые там прописаны.
Подобная логика была уже в виде “подгонки” брони, которая просто добавляла немного хп

Тут нужно брать min/max урон и повышать на 1ед вплоть до х10, но с той логикой шанса которую ты описал.

Тогда вписывается в логику применимую к оружию

Ну для этого параметры и подтягиваются извне. Что не надо повышать —— удалил.