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(); // 获取物品成功率 $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); // 记录灾害清除事件日志 $this->logDisasterRemovalEvent($userId, $landId, $itemId, $disasterType, $successRate, $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 $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] ]); } /** * 记录灾害清除事件日志 * * @param int $userId 用户ID * @param int $landId 土地ID * @param int $itemId 物品ID * @param int $disasterType 灾害类型 * @param float $successRate 成功率 * @param string $sourceType 消耗来源类型 * @return void */ private function logDisasterRemovalEvent(int $userId, int $landId, int $itemId, int $disasterType, float $successRate, string $sourceType): void { try { // 获取作物信息 $crop = \App\Module\Farm\Models\FarmCrop::where('land_id', $landId)->first(); if (!$crop) { Log::warning('记录灾害清除事件时未找到作物', [ 'user_id' => $userId, 'land_id' => $landId, 'disaster_type' => $disasterType ]); return; } // 根据灾害类型选择对应的日志方法 $eventData = [ 'growth_stage' => $crop->growth_stage, 'land_type' => $crop->land->land_type ?? 1, 'disaster_type' => $disasterType, 'item_id' => $itemId, 'success_rate' => $successRate, 'source_type' => $sourceType, 'cleared_at' => now()->format('Y-m-d H:i:s'), ]; switch ($disasterType) { case \App\Module\Farm\Enums\DISASTER_TYPE::PEST->value: \App\Module\Farm\Models\FarmCropLog::logPesticideUsed( $userId, $landId, $crop->id, $crop->seed_id, $eventData ); break; case \App\Module\Farm\Enums\DISASTER_TYPE::WEED->value: \App\Module\Farm\Models\FarmCropLog::logWeedicideUsed( $userId, $landId, $crop->id, $crop->seed_id, $eventData ); break; case \App\Module\Farm\Enums\DISASTER_TYPE::DROUGHT->value: \App\Module\Farm\Models\FarmCropLog::logWatering( $userId, $landId, $crop->id, $crop->seed_id, $eventData ); break; default: Log::warning('未知的灾害类型,无法记录日志', [ 'disaster_type' => $disasterType, 'user_id' => $userId, 'land_id' => $landId ]); } } catch (\Exception $e) { Log::error('记录灾害清除事件日志失败', [ 'user_id' => $userId, 'land_id' => $landId, 'disaster_type' => $disasterType, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); } } }