|
|
@@ -0,0 +1,231 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace App\Module\Farm\Logics;
|
|
|
+
|
|
|
+use App\Module\Farm\Enums\DISASTER_TYPE;
|
|
|
+use App\Module\Farm\Models\FarmCrop;
|
|
|
+use App\Module\Farm\Models\FarmLand;
|
|
|
+use App\Module\Farm\Enums\LAND_STATUS;
|
|
|
+use App\Module\Farm\Events\DisasterClearedEvent;
|
|
|
+use App\Module\GameItems\Services\ItemService;
|
|
|
+use Illuminate\Support\Facades\Log;
|
|
|
+use UCore\Db\Helper;
|
|
|
+use UCore\Exception\LogicException;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 灾害去除逻辑类
|
|
|
+ *
|
|
|
+ * 处理各种类型的灾害去除操作,包括概率计算、状态验证和物品消耗
|
|
|
+ */
|
|
|
+class DisasterRemovalLogic
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 灾害类型与物品属性的映射关系
|
|
|
+ */
|
|
|
+ private const DISASTER_ITEM_ATTRIBUTES = [
|
|
|
+ DISASTER_TYPE::DROUGHT->value => 'fram_drought_rate', // 干旱 -> 浇水概率
|
|
|
+ DISASTER_TYPE::PEST->value => 'fram_pesticide_rate', // 虫害 -> 除虫概率
|
|
|
+ DISASTER_TYPE::WEED->value => 'fram_weedicide_rate', // 杂草 -> 除草概率
|
|
|
+ ];
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 灾害类型与操作名称的映射关系
|
|
|
+ */
|
|
|
+ private const DISASTER_ACTION_NAMES = [
|
|
|
+ DISASTER_TYPE::DROUGHT->value => '浇水',
|
|
|
+ DISASTER_TYPE::PEST->value => '除虫',
|
|
|
+ DISASTER_TYPE::WEED->value => '除草',
|
|
|
+ ];
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 尝试去除指定类型的灾害
|
|
|
+ *
|
|
|
+ * @param int $userId 用户ID
|
|
|
+ * @param int $landId 土地ID
|
|
|
+ * @param int $itemId 物品ID
|
|
|
+ * @param int $disasterType 灾害类型
|
|
|
+ * @param string $sourceType 消耗来源类型
|
|
|
+ * @return array 操作结果
|
|
|
+ * @throws LogicException
|
|
|
+ */
|
|
|
+ public function removeDisaster(int $userId, int $landId, int $itemId, int $disasterType, string $sourceType): array
|
|
|
+ {
|
|
|
+ // 检查事务状态
|
|
|
+ Helper::check_tr();
|
|
|
+
|
|
|
+ // 验证灾害类型
|
|
|
+ if (!isset(self::DISASTER_ITEM_ATTRIBUTES[$disasterType])) {
|
|
|
+ throw new LogicException("不支持的灾害类型: {$disasterType}");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证土地
|
|
|
+ $land = $this->validateLand($userId, $landId);
|
|
|
+
|
|
|
+ // 验证物品
|
|
|
+ $this->validateItem($userId, $itemId, $disasterType);
|
|
|
+
|
|
|
+ // 获取物品成功率
|
|
|
+ $successRate = $this->getItemSuccessRate($itemId, $disasterType);
|
|
|
+
|
|
|
+ // 进行概率判断
|
|
|
+ if (!$this->rollSuccess($successRate)) {
|
|
|
+ // 失败时仍然消耗物品
|
|
|
+ $this->consumeItem($userId, $itemId, $landId, $sourceType);
|
|
|
+
|
|
|
+ $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
|
|
|
+ throw new LogicException("{$actionName}失败,请再次尝试");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 执行灾害清理
|
|
|
+ $result = $this->clearDisasterFromCrop($userId, $landId, $disasterType);
|
|
|
+
|
|
|
+ if (!$result) {
|
|
|
+ throw new LogicException("灾害清理失败,请检查土地状态或作物生长阶段");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 消耗物品
|
|
|
+ $this->consumeItem($userId, $itemId, $landId, $sourceType);
|
|
|
+
|
|
|
+ $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
|
|
|
+
|
|
|
+ Log::info("用户{$actionName}成功", [
|
|
|
+ 'user_id' => $userId,
|
|
|
+ 'land_id' => $landId,
|
|
|
+ 'item_id' => $itemId,
|
|
|
+ 'disaster_type' => $disasterType,
|
|
|
+ 'success_rate' => $successRate
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success' => true,
|
|
|
+ 'message' => "{$actionName}成功",
|
|
|
+ 'disaster_type' => $disasterType,
|
|
|
+ 'success_rate' => $successRate
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证土地是否存在且属于用户
|
|
|
+ *
|
|
|
+ * @param int $userId 用户ID
|
|
|
+ * @param int $landId 土地ID
|
|
|
+ * @return FarmLand
|
|
|
+ * @throws LogicException
|
|
|
+ */
|
|
|
+ private function validateLand(int $userId, int $landId): FarmLand
|
|
|
+ {
|
|
|
+ $land = FarmLand::where('id', $landId)
|
|
|
+ ->where('user_id', $userId)
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if (!$land) {
|
|
|
+ throw new LogicException("土地不存在或不属于当前用户");
|
|
|
+ }
|
|
|
+
|
|
|
+ return $land;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证用户是否拥有指定物品且物品具有对应的灾害去除属性
|
|
|
+ *
|
|
|
+ * @param int $userId 用户ID
|
|
|
+ * @param int $itemId 物品ID
|
|
|
+ * @param int $disasterType 灾害类型
|
|
|
+ * @throws LogicException
|
|
|
+ */
|
|
|
+ private function validateItem(int $userId, int $itemId, int $disasterType): void
|
|
|
+ {
|
|
|
+ // 验证用户是否拥有该物品
|
|
|
+ $hasItem = ItemService::getUserItems($userId, ['item_id' => $itemId]);
|
|
|
+ if ($hasItem->isEmpty()) {
|
|
|
+ $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
|
|
|
+ throw new LogicException("您没有该{$actionName}物品");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证物品是否具有对应的灾害去除属性
|
|
|
+ $attributeName = self::DISASTER_ITEM_ATTRIBUTES[$disasterType];
|
|
|
+ $rate = ItemService::getItemNumericAttribute($itemId, $attributeName);
|
|
|
+
|
|
|
+ if ($rate <= 0) {
|
|
|
+ $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
|
|
|
+ throw new LogicException("不是{$actionName}物品");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取物品的成功率
|
|
|
+ *
|
|
|
+ * @param int $itemId 物品ID
|
|
|
+ * @param int $disasterType 灾害类型
|
|
|
+ * @return int 成功率(百分比)
|
|
|
+ */
|
|
|
+ private function getItemSuccessRate(int $itemId, int $disasterType): int
|
|
|
+ {
|
|
|
+ $attributeName = self::DISASTER_ITEM_ATTRIBUTES[$disasterType];
|
|
|
+ return ItemService::getItemNumericAttribute($itemId, $attributeName, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 进行概率判断
|
|
|
+ *
|
|
|
+ * @param int $successRate 成功率(百分比,100=100%)
|
|
|
+ * @return bool 是否成功
|
|
|
+ */
|
|
|
+ private function rollSuccess(int $successRate): bool
|
|
|
+ {
|
|
|
+ if ($successRate <= 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($successRate >= 100) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ $randomNumber = mt_rand(1, 100);
|
|
|
+ return $randomNumber <= $successRate;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从作物中清理指定类型的灾害
|
|
|
+ *
|
|
|
+ * @param int $userId 用户ID
|
|
|
+ * @param int $landId 土地ID
|
|
|
+ * @param int $disasterType 灾害类型
|
|
|
+ * @return bool 是否成功
|
|
|
+ */
|
|
|
+ private function clearDisasterFromCrop(int $userId, int $landId, int $disasterType): bool
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ $cropLogic = new CropLogic();
|
|
|
+ return $cropLogic->clearDisaster($userId, $landId, $disasterType);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('清理灾害失败', [
|
|
|
+ 'user_id' => $userId,
|
|
|
+ 'land_id' => $landId,
|
|
|
+ 'disaster_type' => $disasterType,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'trace' => $e->getTraceAsString()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 消耗物品
|
|
|
+ *
|
|
|
+ * @param int $userId 用户ID
|
|
|
+ * @param int $itemId 物品ID
|
|
|
+ * @param int $landId 土地ID
|
|
|
+ * @param string $sourceType 消耗来源类型
|
|
|
+ * @throws LogicException
|
|
|
+ */
|
|
|
+ private function consumeItem(int $userId, int $itemId, int $landId, string $sourceType): void
|
|
|
+ {
|
|
|
+ ItemService::consumeItem($userId, $itemId, null, 1, [
|
|
|
+ 'source_type' => $sourceType,
|
|
|
+ 'source_id' => $landId,
|
|
|
+ 'details' => ['land_id' => $landId]
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+}
|