|
|
@@ -3,7 +3,6 @@
|
|
|
namespace App\Module\Farm\Logics;
|
|
|
|
|
|
use App\Module\Farm\Dtos\DisasterInfoDto;
|
|
|
-use App\Module\Farm\Enums\BUFF_TYPE;
|
|
|
use App\Module\Farm\Enums\DISASTER_TYPE;
|
|
|
use App\Module\Farm\Enums\GROWTH_STAGE;
|
|
|
use App\Module\Farm\Enums\LAND_STATUS;
|
|
|
@@ -129,58 +128,18 @@ class DisasterLogic
|
|
|
->pluck('buff_type')
|
|
|
->toArray();
|
|
|
|
|
|
- // 灾害类型及其基础概率
|
|
|
- $disasterTypes =DisasterService::getAllDisasters();
|
|
|
-
|
|
|
- // 随机选择一种灾害类型
|
|
|
- $randomDisasterType = array_rand($disasterTypes);
|
|
|
- $baseProb = $disasterTypes[$randomDisasterType];
|
|
|
-
|
|
|
- // 计算最终概率,考虑种子抵抗、土地抵抗和神灵加持
|
|
|
- $seedResistance = $disasterResistance[$this->getDisasterKey($randomDisasterType)] ?? 0;
|
|
|
- $finalProb = $baseProb - $seedResistance - $landDisasterResistance;
|
|
|
-
|
|
|
- // 如果有对应的神灵加持,则不生成该类型的灾害
|
|
|
- $buffType = DISASTER_TYPE::getPreventBuffType($randomDisasterType);
|
|
|
- if ($buffType && in_array($buffType, $activeBuffs)) {
|
|
|
- $finalProb = 0;
|
|
|
- }
|
|
|
-
|
|
|
- // 确保概率在有效范围内
|
|
|
- $finalProb = max(0, min(1, $finalProb));
|
|
|
-
|
|
|
- // 随机决定是否生成灾害
|
|
|
- if (mt_rand(1, 100) <= $finalProb * 100) {
|
|
|
- // 生成灾害
|
|
|
- $disasterInfo = [
|
|
|
- 'type' => $randomDisasterType,
|
|
|
- 'generated_ts' => now()->toDateTimeString(),
|
|
|
- 'status' => 'active'
|
|
|
- ];
|
|
|
-
|
|
|
- // 更新作物灾害信息
|
|
|
- $disasters = $crop->disasters ?? [];
|
|
|
- $disasters[] = $disasterInfo;
|
|
|
- $crop->disasters = $disasters;
|
|
|
-
|
|
|
- // 更新土地状态为灾害
|
|
|
- $land->status = LAND_STATUS::DISASTER;
|
|
|
-
|
|
|
- // 保存更改
|
|
|
- $crop->save();
|
|
|
- $land->save();
|
|
|
-
|
|
|
- // 触发灾害生成事件
|
|
|
- event(new DisasterGeneratedEvent($userId, $crop, $randomDisasterType, $disasterInfo));
|
|
|
+ // 尝试生成灾害
|
|
|
+ $disasterInfo = $this->tryGenerateDisasterForCrop($crop, $disasterResistance, $landDisasterResistance, $activeBuffs);
|
|
|
|
|
|
+ if ($disasterInfo) {
|
|
|
Log::info('灾害生成成功', [
|
|
|
'user_id' => $userId,
|
|
|
'crop_id' => $crop->id,
|
|
|
'land_id' => $land->id,
|
|
|
- 'disaster_type' => $randomDisasterType
|
|
|
+ 'disaster_type' => $disasterInfo->type
|
|
|
]);
|
|
|
|
|
|
- return DisasterInfoDto::fromArray($disasterInfo);
|
|
|
+ return $disasterInfo;
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
@@ -196,19 +155,153 @@ class DisasterLogic
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取灾害类型对应的键名
|
|
|
+ * 尝试为作物生成灾害
|
|
|
*
|
|
|
+ * @param FarmCrop $crop
|
|
|
+ * @param array $disasterResistance
|
|
|
+ * @param float $landDisasterResistance
|
|
|
+ * @param array $activeBuffs
|
|
|
+ * @return DisasterInfoDto|null
|
|
|
+ */
|
|
|
+ private function tryGenerateDisasterForCrop(FarmCrop $crop, array $disasterResistance, float $landDisasterResistance, array $activeBuffs): ?DisasterInfoDto
|
|
|
+ {
|
|
|
+ // 灾害类型及其基础概率
|
|
|
+ $disasterTypes = DisasterService::getRate();
|
|
|
+
|
|
|
+ // 随机选择一种灾害类型
|
|
|
+ $randomDisasterType = array_rand($disasterTypes);
|
|
|
+ $baseProb = $disasterTypes[$randomDisasterType];
|
|
|
+
|
|
|
+ // 计算最终概率,考虑种子抵抗、土地抵抗和神灵加持
|
|
|
+ $seedResistance = $disasterResistance[DisasterService::getDisasterKey($randomDisasterType)] ?? 0;
|
|
|
+ $finalProb = $baseProb - $seedResistance - $landDisasterResistance;
|
|
|
+
|
|
|
+ // 如果有对应的神灵加持,则不生成该类型的灾害
|
|
|
+ $buffType = DISASTER_TYPE::getPreventBuffType($randomDisasterType);
|
|
|
+ if ($buffType && in_array($buffType, $activeBuffs)) {
|
|
|
+ $finalProb = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确保概率在有效范围内
|
|
|
+ $finalProb = max(0, min(1, $finalProb));
|
|
|
+
|
|
|
+ // 随机决定是否生成灾害
|
|
|
+ if (mt_rand(1, 100) <= $finalProb * 100) {
|
|
|
+ return $this->applyDisasterToCrop($crop, $randomDisasterType);
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将灾害应用到作物上
|
|
|
+ *
|
|
|
+ * @param FarmCrop $crop
|
|
|
* @param int $disasterType
|
|
|
- * @return string
|
|
|
+ * @return DisasterInfoDto
|
|
|
*/
|
|
|
- private function getDisasterKey(int $disasterType): string
|
|
|
+ private function applyDisasterToCrop(FarmCrop $crop, int $disasterType): DisasterInfoDto
|
|
|
{
|
|
|
- $keys = [
|
|
|
- DISASTER_TYPE::DROUGHT => 'drought',
|
|
|
- DISASTER_TYPE::PEST => 'pest',
|
|
|
- DISASTER_TYPE::WEED => 'weed',
|
|
|
+ // 生成灾害信息
|
|
|
+ $disasterInfo = [
|
|
|
+ 'type' => $disasterType,
|
|
|
+ 'generated_ts' => now()->toDateTimeString(),
|
|
|
+ 'status' => 'active'
|
|
|
];
|
|
|
|
|
|
- return $keys[$disasterType] ?? '';
|
|
|
+ // 更新作物灾害信息
|
|
|
+ $disasters = $crop->disasters ?? [];
|
|
|
+ $disasters[] = $disasterInfo;
|
|
|
+ $crop->disasters = $disasters;
|
|
|
+
|
|
|
+ // 更新土地状态为灾害
|
|
|
+ $land = $crop->land;
|
|
|
+ $land->status = LAND_STATUS::DISASTER;
|
|
|
+
|
|
|
+ // 保存更改
|
|
|
+ $crop->save();
|
|
|
+ $land->save();
|
|
|
+
|
|
|
+ // 触发灾害生成事件
|
|
|
+ event(new DisasterGeneratedEvent($crop->user_id, $crop, $disasterType, $disasterInfo));
|
|
|
+
|
|
|
+ return DisasterInfoDto::fromArray($disasterInfo);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量检查并生成灾害
|
|
|
+ *
|
|
|
+ * @param int|null $checkIntervalMinutes 检查间隔(分钟)
|
|
|
+ * @return array 生成结果统计
|
|
|
+ */
|
|
|
+ public function batchGenerateDisasters(?int $checkIntervalMinutes = null): array
|
|
|
+ {
|
|
|
+ if ($checkIntervalMinutes === null) {
|
|
|
+ $checkIntervalMinutes = DisasterService::getCheckInterval();
|
|
|
+ }
|
|
|
+
|
|
|
+ $checkTime = now()->subMinutes($checkIntervalMinutes);
|
|
|
+
|
|
|
+ // 获取需要检查灾害的作物:
|
|
|
+ // 1. 必须在发芽期或生长期
|
|
|
+ // 2. 当前阶段可以产生灾害 (can_disaster = 1)
|
|
|
+ // 3. 满足时间检查条件(首次检查或超过检查间隔)
|
|
|
+ $crops = FarmCrop::whereIn('growth_stage', [GROWTH_STAGE::SPROUT, GROWTH_STAGE::GROWTH])
|
|
|
+ ->where('can_disaster', true)
|
|
|
+ ->where(function ($query) use ($checkTime) {
|
|
|
+ $query->whereNull('last_disaster_check_time')
|
|
|
+ ->orWhere('last_disaster_check_time', '<', $checkTime);
|
|
|
+ })
|
|
|
+ ->with(['land.landType', 'seed', 'user.buffs' => function ($query) {
|
|
|
+ $query->where('expire_time', '>', now());
|
|
|
+ }])
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ $totalCount = $crops->count();
|
|
|
+ $generatedCount = 0;
|
|
|
+ $skippedCount = 0;
|
|
|
+
|
|
|
+ foreach ($crops as $crop) {
|
|
|
+ try {
|
|
|
+ // 更新检查时间
|
|
|
+ $crop->last_disaster_check_time = now();
|
|
|
+
|
|
|
+ // 跳过已经有灾害的土地
|
|
|
+ if ($crop->land->status === LAND_STATUS::DISASTER) {
|
|
|
+ $crop->save(); // 仍需更新检查时间
|
|
|
+ $skippedCount++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取相关数据
|
|
|
+ $disasterResistance = $crop->seed->disaster_resistance ?? [];
|
|
|
+ $landDisasterResistance = $crop->land->landType->disaster_resistance ?? 0;
|
|
|
+ $activeBuffs = $crop->user->buffs->pluck('buff_type')->toArray();
|
|
|
+
|
|
|
+ // 尝试生成灾害
|
|
|
+ $disasterInfo = $this->tryGenerateDisasterForCrop($crop, $disasterResistance, $landDisasterResistance, $activeBuffs);
|
|
|
+
|
|
|
+ if ($disasterInfo) {
|
|
|
+ // 生成灾害后,设置当前阶段不能再产生灾害
|
|
|
+ $crop->can_disaster = false;
|
|
|
+ $generatedCount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存更改
|
|
|
+ $crop->save();
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('批量生成灾害失败', [
|
|
|
+ 'crop_id' => $crop->id,
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'total' => $totalCount,
|
|
|
+ 'generated' => $generatedCount,
|
|
|
+ 'skipped' => $skippedCount
|
|
|
+ ];
|
|
|
}
|
|
|
}
|