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] ]); } }