Files
chatroom/app/Services/FishingService.php

123 lines
4.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 文件功能:钓鱼核心业务逻辑
*
* 提取自 FishingController供玩家请求和 AI 挂机脚本复用。
*
* @author ChatRoom Laravel
*
* @version 1.0.0
*/
namespace App\Services;
use App\Enums\CurrencySource;
use App\Events\MessageSent;
use App\Models\FishingEvent;
use App\Models\User;
class FishingService
{
public function __construct(
private readonly ChatStateService $chatState,
private readonly VipService $vipService,
private readonly UserCurrencyService $currencyService,
private readonly ShopService $shopService,
) {}
/**
* 处理收竿逻辑:计算结果、发放积分并全服广播。
*
* @param User $user 收竿的用户实体
* @param int $roomId 所在房间 ID
* @param bool $isAi 是否为 AI 调用(用于影响文案或标签)
*/
public function processCatch(User $user, int $roomId, bool $isAi = false): array
{
// 1. 随机决定钓鱼结果
$result = $this->randomFishResult();
// 2. 更新经验和金币
$expMul = $this->vipService->getExpMultiplier($user);
$jjbMul = $this->vipService->getJjbMultiplier($user);
if ($result['exp'] !== 0) {
$finalExp = $result['exp'] > 0 ? (int) round($result['exp'] * $expMul) : $result['exp'];
$this->currencyService->change(
$user, 'exp', $finalExp, CurrencySource::FISHING_GAIN,
"钓鱼收竿:{$result['message']}", $roomId,
);
}
if ($result['jjb'] !== 0) {
$finalJjb = $result['jjb'] > 0 ? (int) round($result['jjb'] * $jjbMul) : $result['jjb'];
$this->currencyService->change(
$user, 'gold', $finalJjb, CurrencySource::FISHING_GAIN,
"钓鱼收竿:{$result['message']}", $roomId,
);
}
$user->refresh();
// 3. 广播钓鱼结果到聊天室
$promoTag = '';
if (! $isAi) {
$autoFishingMinutesLeft = $this->shopService->getActiveAutoFishingMinutesLeft($user);
$promoTag = $autoFishingMinutesLeft > 0
? ' <span onclick="window.openShopModal&&window.openShopModal()" '
.'style="display:inline-block;margin-left:6px;padding:1px 7px;background:#e9e4f5;'
.'color:#6d4fa8;border-radius:10px;font-size:10px;cursor:pointer;font-weight:bold;vertical-align:middle;'
.'border:1px solid #d0c4ec;" title="点击购买自动钓鱼卡">🎣 自动钓鱼卡</span>'
: '';
}
$sysMsg = [
'id' => $this->chatState->nextMessageId($roomId),
'room_id' => $roomId,
'from_user' => '钓鱼播报',
'to_user' => '大家',
'content' => "{$result['emoji']}{$user->username}{$result['message']}{$promoTag}",
'is_secret' => false,
'font_color' => $result['exp'] >= 0 ? '#16a34a' : '#dc2626',
'action' => '',
'sent_at' => now()->toDateTimeString(),
];
$this->chatState->pushMessage($roomId, $sysMsg);
broadcast(new MessageSent($roomId, $sysMsg));
// 发送完需持久化,不过 controller 里并未直接看到 SaveMessageJob, 但 AIheartbeat 里有。
// 这里就先维持原样,只 broadcast 和 pushMessage
return $result;
}
/**
* 随机钓鱼结果(从数据库 fishing_events 加权随机抽取)
*
* 若数据库中无激活事件,回退到兜底结果。
*
* @return array{emoji: string, message: string, exp: int, jjb: int}
*/
public function randomFishResult(): array
{
$event = FishingEvent::rollOne();
if (! $event) {
return [
'emoji' => '🐟',
'message' => '钓到一条小鱼获得金币10',
'exp' => 0,
'jjb' => 10,
];
}
return [
'emoji' => $event->emoji,
'message' => $event->message,
'exp' => $event->exp,
'jjb' => $event->jjb,
];
}
}