DisasterRemovalLogic.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. namespace App\Module\Farm\Logics;
  3. use App\Module\Farm\Enums\DISASTER_TYPE;
  4. use App\Module\Farm\Models\FarmCrop;
  5. use App\Module\Farm\Models\FarmLand;
  6. use App\Module\Farm\Enums\LAND_STATUS;
  7. use App\Module\Farm\Events\DisasterClearedEvent;
  8. use App\Module\GameItems\Services\ItemService;
  9. use Illuminate\Support\Facades\Log;
  10. use UCore\Db\Helper;
  11. use UCore\Exception\LogicException;
  12. /**
  13. * 灾害去除逻辑类
  14. *
  15. * 处理各种类型的灾害去除操作,包括概率计算、状态验证和物品消耗
  16. */
  17. class DisasterRemovalLogic
  18. {
  19. /**
  20. * 灾害类型与物品属性的映射关系
  21. */
  22. private const DISASTER_ITEM_ATTRIBUTES = [
  23. DISASTER_TYPE::DROUGHT->value => 'fram_drought_rate', // 干旱 -> 浇水概率
  24. DISASTER_TYPE::PEST->value => 'fram_pesticide_rate', // 虫害 -> 除虫概率
  25. DISASTER_TYPE::WEED->value => 'fram_weedicide_rate', // 杂草 -> 除草概率
  26. ];
  27. /**
  28. * 灾害类型与操作名称的映射关系
  29. */
  30. private const DISASTER_ACTION_NAMES = [
  31. DISASTER_TYPE::DROUGHT->value => '浇水',
  32. DISASTER_TYPE::PEST->value => '除虫',
  33. DISASTER_TYPE::WEED->value => '除草',
  34. ];
  35. /**
  36. * 尝试去除指定类型的灾害
  37. *
  38. * @param int $userId 用户ID
  39. * @param int $landId 土地ID
  40. * @param int $itemId 物品ID
  41. * @param int $disasterType 灾害类型
  42. * @param string $sourceType 消耗来源类型
  43. * @return array 操作结果
  44. * @throws LogicException
  45. */
  46. public function removeDisaster(int $userId, int $landId, int $itemId, int $disasterType, string $sourceType): array
  47. {
  48. // 检查事务状态
  49. Helper::check_tr();
  50. // 验证灾害类型
  51. if (!isset(self::DISASTER_ITEM_ATTRIBUTES[$disasterType])) {
  52. throw new LogicException("不支持的灾害类型: {$disasterType}");
  53. }
  54. // 验证土地
  55. $land = $this->validateLand($userId, $landId);
  56. // 验证物品
  57. $this->validateItem($userId, $itemId, $disasterType);
  58. // 获取物品成功率
  59. $successRate = $this->getItemSuccessRate($itemId, $disasterType);
  60. // 进行概率判断
  61. if (!$this->rollSuccess($successRate)) {
  62. // 失败时仍然消耗物品
  63. $this->consumeItem($userId, $itemId, $landId, $sourceType);
  64. $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
  65. throw new LogicException("{$actionName}失败,请再次尝试");
  66. }
  67. // 执行灾害清理
  68. $result = $this->clearDisasterFromCrop($userId, $landId, $disasterType);
  69. if (!$result) {
  70. throw new LogicException("灾害清理失败,请检查土地状态或作物生长阶段");
  71. }
  72. // 消耗物品
  73. $this->consumeItem($userId, $itemId, $landId, $sourceType);
  74. $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
  75. Log::info("用户{$actionName}成功", [
  76. 'user_id' => $userId,
  77. 'land_id' => $landId,
  78. 'item_id' => $itemId,
  79. 'disaster_type' => $disasterType,
  80. 'success_rate' => $successRate
  81. ]);
  82. return [
  83. 'success' => true,
  84. 'message' => "{$actionName}成功",
  85. 'disaster_type' => $disasterType,
  86. 'success_rate' => $successRate
  87. ];
  88. }
  89. /**
  90. * 验证土地是否存在且属于用户
  91. *
  92. * @param int $userId 用户ID
  93. * @param int $landId 土地ID
  94. * @return FarmLand
  95. * @throws LogicException
  96. */
  97. private function validateLand(int $userId, int $landId): FarmLand
  98. {
  99. $land = FarmLand::where('id', $landId)
  100. ->where('user_id', $userId)
  101. ->first();
  102. if (!$land) {
  103. throw new LogicException("土地不存在或不属于当前用户");
  104. }
  105. return $land;
  106. }
  107. /**
  108. * 验证用户是否拥有指定物品且物品具有对应的灾害去除属性
  109. *
  110. * @param int $userId 用户ID
  111. * @param int $itemId 物品ID
  112. * @param int $disasterType 灾害类型
  113. * @throws LogicException
  114. */
  115. private function validateItem(int $userId, int $itemId, int $disasterType): void
  116. {
  117. // 验证用户是否拥有该物品
  118. $hasItem = ItemService::getUserItems($userId, ['item_id' => $itemId]);
  119. if ($hasItem->isEmpty()) {
  120. $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
  121. throw new LogicException("您没有该{$actionName}物品");
  122. }
  123. // 验证物品是否具有对应的灾害去除属性
  124. $attributeName = self::DISASTER_ITEM_ATTRIBUTES[$disasterType];
  125. $rate = ItemService::getItemNumericAttribute($itemId, $attributeName);
  126. if ($rate <= 0) {
  127. $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
  128. throw new LogicException("不是{$actionName}物品");
  129. }
  130. }
  131. /**
  132. * 获取物品的成功率
  133. *
  134. * @param int $itemId 物品ID
  135. * @param int $disasterType 灾害类型
  136. * @return int 成功率(百分比)
  137. */
  138. private function getItemSuccessRate(int $itemId, int $disasterType): int
  139. {
  140. $attributeName = self::DISASTER_ITEM_ATTRIBUTES[$disasterType];
  141. return ItemService::getItemNumericAttribute($itemId, $attributeName, 0);
  142. }
  143. /**
  144. * 进行概率判断
  145. *
  146. * @param int $successRate 成功率(百分比,100=100%)
  147. * @return bool 是否成功
  148. */
  149. private function rollSuccess(int $successRate): bool
  150. {
  151. if ($successRate <= 0) {
  152. return false;
  153. }
  154. if ($successRate >= 100) {
  155. return true;
  156. }
  157. $randomNumber = mt_rand(1, 100);
  158. return $randomNumber <= $successRate;
  159. }
  160. /**
  161. * 从作物中清理指定类型的灾害
  162. *
  163. * @param int $userId 用户ID
  164. * @param int $landId 土地ID
  165. * @param int $disasterType 灾害类型
  166. * @return bool 是否成功
  167. */
  168. private function clearDisasterFromCrop(int $userId, int $landId, int $disasterType): bool
  169. {
  170. try {
  171. $cropLogic = new CropLogic();
  172. return $cropLogic->clearDisaster($userId, $landId, $disasterType);
  173. } catch (\Exception $e) {
  174. Log::error('清理灾害失败', [
  175. 'user_id' => $userId,
  176. 'land_id' => $landId,
  177. 'disaster_type' => $disasterType,
  178. 'error' => $e->getMessage(),
  179. 'trace' => $e->getTraceAsString()
  180. ]);
  181. return false;
  182. }
  183. }
  184. /**
  185. * 消耗物品
  186. *
  187. * @param int $userId 用户ID
  188. * @param int $itemId 物品ID
  189. * @param int $landId 土地ID
  190. * @param string $sourceType 消耗来源类型
  191. * @throws LogicException
  192. */
  193. private function consumeItem(int $userId, int $itemId, int $landId, string $sourceType): void
  194. {
  195. ItemService::consumeItem($userId, $itemId, null, 1, [
  196. 'source_type' => $sourceType,
  197. 'source_id' => $landId,
  198. 'details' => ['land_id' => $landId]
  199. ]);
  200. }
  201. }