<?php
declare(strict_types=1);
namespace App\EventSubscriber\Game;
use App\Entity\BattleResult;
use App\Entity\Location\CapturableLocationInterface;
use App\Entity\Location\ConvoyInterceptionPoint;
use App\Entity\Location\Town;
use App\Entity\Mail;
use App\Entity\Relation;
use App\Event\BattleEvent;
use App\Event\ConvoyArrivedEvent;
use App\Model\DiscordTriggerService;
use App\Model\Game\GameUserService;
use App\Model\GameService;
use App\Model\UserService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class AttackSubscriber implements EventSubscriberInterface
{
public const CONVOY = 'game.convoy';
public const ATTACK = 'game.attack';
/**
* @var GameUserService
*/
private $userService;
/**
* @var DiscordTriggerService
*/
private $triggerService;
/**
* @var GameService
*/
private $gameService;
public function __construct(GameUserService $userService, DiscordTriggerService $triggerService, GameService $gameService)
{
$this->userService = $userService;
$this->triggerService = $triggerService;
$this->gameService = $gameService;
}
public function convoyArrival(ConvoyArrivedEvent $event)
{
$this->gameService->setArea($event->getArea());
$convoy = $event->getConvoy();
$owner = $convoy->getOwner();
$target = $convoy->getTargetName();
if (!$convoy->isAutoResolved()) {
if ($target == $owner->getName()) {
$this->gameService->eventService->addTownEvent($owner, "An attack convoy has arrived home.");
} else {
$this->gameService->eventService->addTownEvent($owner, "An attack convoy heading for $target has arrived.");
if ($owner instanceof Town) {
$this->userService->setAreaContext($this->gameService->area());
$targetUser = $this->userService->getUserFromUsername($owner->loginname);
$discordUser = $this->userService->getUserDiscord($targetUser->getId());
if ($discordUser && $discordUser->isVerified() && $discordUser->getSettings() != null && $discordUser->getSettings()->attack_convoy) {
$this->triggerService->addTrigger($this->gameService->area(), DiscordTriggerService::TRIGGER_USER_DM, $targetUser->getId(), "An attack convoy heading for **$target** has arrived.");
}
}
}
}
}
public function generateReports(BattleEvent $event)
{
$this->gameService->setArea($event->getArea());
$convoy = $event->getConvoy();
$battleResult = $event->getBattleResult();
// Generate report for attacker
if ($convoy->getOwner()->isPlayer()) {
$battleResult->setViewSide('attacker');
$reportId = $this->gameService->mailService->saveBattleReport($convoy->getOwner(), $battleResult, $convoy->isAutoResolved() ? Mail::STATUS_NEW : Mail::STATUS_READ);
$battleResult->setOwnerReportId($reportId);
}
// Generate report for target owner
if ($convoy->getTarget()->getOwner()->isPlayer()) {
$battleResult->setViewSide('defender');
/** @var Town $targetOwner */
$targetOwner = $convoy->getTarget()->getOwner();
$reportId = $this->gameService->mailService->saveBattleReport($targetOwner, $battleResult, Mail::STATUS_NEW);
$battleResult->setTargetReportId($reportId);
}
}
public function townEvents(BattleEvent $event)
{
$this->gameService->setArea($event->getArea());
$convoy = $event->getConvoy();
$battleResult = $event->getBattleResult();
// Town event for attacked when convoy is autoresolved
if ($battleResult->getOwnerReportId()) {
$link = $this->gameService->urlGenerator->generate('game_mail_reports_read', ['reportId' => $battleResult->getOwnerReportId()]);
if ($convoy->isAutoResolved()) {
$this->gameService->eventService->addTownEvent($convoy->getOwner(), "An attack convoy arrived at {$convoy->getTarget()->getName()} and attacked instantly. Your convoy " . ($battleResult->isVictorious() ? "was victorious" : "was pushed back") . ". Read the <a href='{$link}'>battle report</a>.");
}
}
// Town event when attacking town or owned acre
if ($battleResult->getTargetReportId() && $convoy->getTarget()->getOwner()->isPlayer()) {
/** @var Town $targetOwner */
$targetOwner = $convoy->getTarget()->getOwner();
$link = $this->gameService->urlGenerator->generate('game_mail_reports_read', ['reportId' => $battleResult->getTargetReportId()]);
if ($convoy->getTarget() instanceof CapturableLocationInterface) {
if ($battleResult->isVictorious()) {
$this->gameService->eventService->addTownEvent($targetOwner, "{$convoy->getTarget()->getName()} got captured by the town of {$convoy->getOwner()->getNameWithTag()}. Read the <a href='{$link}'>battle report</a>.");
} else {
$this->gameService->eventService->addTownEvent($targetOwner, "We managed to defend {$convoy->getTarget()->getName()} against an army from {$convoy->getOwner()->getNameWithTag()}. Read the <a href='{$link}'>battle report</a>.");
}
} elseif ($convoy->getTarget() instanceof ConvoyInterceptionPoint) {
if ($battleResult->isVictorious()) {
$this->gameService->eventService->addTownEvent($targetOwner, "Our convoy got overrun by forces from the town of {$convoy->getOwner()->getNameWithTag()}. Read the <a href='{$link}'>battle report</a>.");
} else {
$this->gameService->eventService->addTownEvent($targetOwner, "We managed to defend our convoy against an attack from {$convoy->getOwner()->getNameWithTag()}. Read the <a href='{$link}'>battle report</a>.");
}
} else {
if ($battleResult->isVictorious()) {
$this->gameService->eventService->addTownEvent($targetOwner, "Our town got overrun by forces from the town of {$convoy->getOwner()->getNameWithTag()}. Read the <a href='{$link}'>battle report</a>.");
} else {
$this->gameService->eventService->addTownEvent($targetOwner, "We managed to defend our town against an attack from {$convoy->getOwner()->getNameWithTag()}. Read the <a href='{$link}'>battle report</a>.");
}
}
}
}
public function discordNotify(BattleEvent $event)
{
$this->gameService->setArea($event->getArea());
// Discord notification
$convoy = $event->getConvoy();
$target = $convoy->getTarget();
if ($target->getOwner()->isPlayer()) {
/** @var Town $town */
$town = $target->getOwner();
$this->userService->setAreaContext($this->gameService->area());
$user = $this->userService->getUserFromUsername($town->loginname);
if ($user) {
$discordUser = $this->userService->getUserDiscord($user->getId());
if ($discordUser && $discordUser->isVerified() && $discordUser->getSettings() != null && $discordUser->getSettings()->attack) {
if ($target instanceof CapturableLocationInterface) {
$this->triggerService->addTrigger($event->getArea(), DiscordTriggerService::TRIGGER_USER_DM, $user->getId(), "{$target->getName()} has been attacked by {$convoy->getOwner()->getNameWithTag()}. The attacker was " . ($event->getBattleResult()->isVictorious() ? "victorious" : "defeated"));
} else if ($target instanceof ConvoyInterceptionPoint) {
$this->triggerService->addTrigger($event->getArea(), DiscordTriggerService::TRIGGER_USER_DM, $user->getId(), "Your convoy has been attacked by {$convoy->getOwner()->getNameWithTag()}." . ($event->getBattleResult()->getResult() == BattleResult::RESULT_VICTORY_DECISIVE ? " Your convoy was devastated and the remaining troops have turned around." : ""));
} else {
$this->triggerService->addTrigger($event->getArea(), DiscordTriggerService::TRIGGER_USER_DM, $user->getId(), "Your town has been attacked by {$convoy->getOwner()->getNameWithTag()}. The attacker was " . ($event->getBattleResult()->isVictorious() ? "victorious" : "defeated"));
}
}
}
}
}
public function relations(BattleEvent $event)
{
$this->gameService->setArea($event->getArea());
// Auto war declaration
$convoy = $event->getConvoy();
$target = $convoy->getTarget()->getOwner();
$attacker = $convoy->getOwner();
if ($attacker instanceof Town && $target instanceof Town) {
$target = $this->gameService->townService->getTownById($target->getId());
if (!$target->isAtWarWith($attacker)) {
$this->gameService->eventService->addTownEvent($attacker, "The town of {$target->getNameWithTag()} has declared war on us because of our recent aggression!");
$this->gameService->relationService->createRelation($target, $attacker, Relation::WAR);
$this->userService->setAreaContext($this->gameService->area());
$targetUser = $this->userService->getUserFromUsername($target->loginname);
$discordUser = $this->userService->getUserDiscord($targetUser->getId());
if ($discordUser && $discordUser->isVerified() && $discordUser->getSettings() != null && $discordUser->getSettings()->war_declaration) {
$this->triggerService->addTrigger($this->gameService->area(), DiscordTriggerService::TRIGGER_USER_DM, $targetUser->getId(), "You have declared war on {$attacker->getNameWithTag()}.");
}
}
}
}
/**
* {@inheritDoc}
* @codeCoverageIgnore
*/
public static function getSubscribedEvents(): array
{
return [
self::CONVOY => [
['convoyArrival', 0],
],
self::ATTACK => [
['generateReports', 50],
['townEvents', 0],
['discordNotify', 0],
['relations', 0],
]
];
}
}