Skip to content

Commit

Permalink
#2504 Added support for Mark of the Wild, Skyfury Totem, etc. for Sim…
Browse files Browse the repository at this point in the history
…ulationCraft options.
  • Loading branch information
Wotuu committed Nov 12, 2024
1 parent 36a9325 commit 3f1b2d6
Show file tree
Hide file tree
Showing 16 changed files with 389 additions and 156 deletions.
2 changes: 2 additions & 0 deletions app/Http/Controllers/Ajax/AjaxDungeonRouteController.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Random\RandomException;
use Teapot\StatusCode\Http;
use Throwable;

Expand Down Expand Up @@ -762,6 +763,7 @@ public function mdtExport(Request $request,

/**
* @throws AuthorizationException
* @throws RandomException
*/
public function simulate(AjaxDungeonRouteSimulateFormRequest $request, RaidEventsServiceInterface $raidEventsService, DungeonRoute $dungeonRoute): array
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Http\Requests\DungeonRoute;

use App\Models\SimulationCraft\SimulationCraftRaidBuffs;
use App\Models\SimulationCraft\SimulationCraftRaidEventsOptions;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
Expand Down Expand Up @@ -31,12 +32,10 @@ public function rules(): array
SimulationCraftRaidEventsOptions::ALL_AFFIXES
)],
'thundering_clear_seconds' => 'required|int|max:15',
'bloodlust' => 'required|in:0,1',
'arcane_intellect' => 'required|in:0,1',
'power_word_fortitude' => 'required|in:0,1',
'battle_shout' => 'required|in:0,1',
'mystic_touch' => 'required|in:0,1',
'chaos_brand' => 'required|in:0,1',
'raid_buffs_mask' => sprintf(
'required|int|max:%d',
pow(2, collect(SimulationCraftRaidBuffs::cases())->count() - 1)
),
'hp_percent' => 'required|int',
'ranged_pull_compensation_yards' => 'required|int',
'use_mounts' => 'in:0,1',
Expand Down
4 changes: 3 additions & 1 deletion app/Logic/SimulationCraft/RaidEventPull.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Models\Enemy;
use App\Models\KillZone\KillZone;
use App\Models\MountableArea;
use App\Models\SimulationCraft\SimulationCraftRaidBuffs;
use App\Models\SimulationCraft\SimulationCraftRaidEventsOptions;
use App\Service\Coordinates\CoordinatesServiceInterface;
use Illuminate\Support\Collection;
Expand All @@ -33,7 +34,8 @@ public function __construct(private readonly CoordinatesServiceInterface $coordi
public function calculateRaidEventPullEnemies(KillZone $killZone, LatLng $previousKillLocation): RaidEventPullInterface
{
// If bloodlust is enabled, and if this pull has bloodlust active on it..
$this->bloodLust = $this->options->bloodlust && in_array($killZone->id, explode(',', $this->options->simulate_bloodlust_per_pull));
$this->bloodLust = $this->options->hasRaidBuff(SimulationCraftRaidBuffs::Bloodlust) &&
in_array($killZone->id, explode(',', $this->options->simulate_bloodlust_per_pull));

$this->pullIndex = $killZone->index;
$this->raidEventPullEnemies = collect();
Expand Down
21 changes: 15 additions & 6 deletions app/Logic/SimulationCraft/RaidEventsCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Logic\SimulationCraft;

use App\Models\KillZone\KillZone;
use App\Models\SimulationCraft\SimulationCraftRaidBuffs;
use App\Models\SimulationCraft\SimulationCraftRaidEventsOptions;
use App\Service\Coordinates\CoordinatesServiceInterface;
use Illuminate\Support\Collection;
Expand Down Expand Up @@ -57,9 +58,13 @@ public function toString(): string
override.bloodlust=%d
override.arcane_intellect=%d
override.power_word_fortitude=%d
override.mark_of_the_wild=%d
override.battle_shout=%d
override.mystic_touch=%d
override.chaos_brand=%d
override.skyfury=%d
override.hunters_mark=%d
override.power_infusion=%d
override.bleeding=0
single_actor_batch=1
max_time=%s
Expand All @@ -68,12 +73,16 @@ public function toString(): string
%s
keystone_level=%d
raid_events=/invulnerable,cooldown=5160,duration=5160,retarget=1
', $this->options->bloodlust,
$this->options->arcane_intellect,
$this->options->power_word_fortitude,
$this->options->battle_shout,
$this->options->mystic_touch,
$this->options->chaos_brand,
', $this->options->hasRaidBuff(SimulationCraftRaidBuffs::Bloodlust) ? 1 : 0,
$this->options->hasRaidBuff(SimulationCraftRaidBuffs::ArcaneIntellect) ? 1 : 0,
$this->options->hasRaidBuff(SimulationCraftRaidBuffs::PowerWordFortitude) ? 1 : 0,
$this->options->hasRaidBuff(SimulationCraftRaidBuffs::MarkOfTheWild) ? 1 : 0,
$this->options->hasRaidBuff(SimulationCraftRaidBuffs::BattleShout) ? 1 : 0,
$this->options->hasRaidBuff(SimulationCraftRaidBuffs::MysticTouch) ? 1 : 0,
$this->options->hasRaidBuff(SimulationCraftRaidBuffs::ChaosBrand) ? 1 : 0,
$this->options->hasRaidBuff(SimulationCraftRaidBuffs::Skyfury) ? 1 : 0,
$this->options->hasRaidBuff(SimulationCraftRaidBuffs::HuntersMark) ? 1 : 0,
$this->options->hasRaidBuff(SimulationCraftRaidBuffs::PowerInfusion) ? 1 : 0,
$this->options->dungeonroute->mappingVersion->timer_max_seconds,
$this->options->dungeonroute->title,
$this->options->shrouded_bounty_type === SimulationCraftRaidEventsOptions::SHROUDED_BOUNTY_TYPE_NONE ?
Expand Down
18 changes: 18 additions & 0 deletions app/Models/SimulationCraft/SimulationCraftRaidBuffs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace App\Models\SimulationCraft;

enum SimulationCraftRaidBuffs: int
{
case Bloodlust = 1;
case ArcaneIntellect = 2;
case PowerWordFortitude = 4;
case MarkOfTheWild = 8;
case BattleShout = 16;
case MysticTouch = 32;
case ChaosBrand = 64;
case Skyfury = 128;
case HuntersMark = 256;
case PowerInfusion = 512;
case Bleeding = 1024;
}
48 changes: 35 additions & 13 deletions app/Models/SimulationCraft/SimulationCraftRaidEventsOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
use App\Models\Affix;
use App\Models\DungeonRoute\DungeonRoute;
use App\Models\Patreon\PatreonBenefit;
use App\Models\Traits\BitMasks;
use App\Models\Traits\GeneratesPublicKey;
use App\Models\User;
use Auth;
use Eloquent;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Random\RandomException;

/**
* @property int $id
Expand All @@ -22,12 +24,7 @@
* @property string $shrouded_bounty_type
* @property string $affix Comma separated list of affixes
* @property int|null $thundering_clear_seconds
* @property bool $bloodlust Override to say yes/no to Bloodlust/Heroism being available.
* @property bool $arcane_intellect
* @property bool $power_word_fortitude
* @property bool $battle_shout
* @property bool $mystic_touch
* @property bool $chaos_brand
* @property int $raid_buffs_mask
* @property float $hp_percent
* @property float $ranged_pull_compensation_yards Premium: the amount of yards that are 'free' between pulls because you
* don't have to always walk from center of previous pull to center of next pull. This reduces the delay between pulls making the sims more accurate
Expand All @@ -43,7 +40,7 @@
*/
class SimulationCraftRaidEventsOptions extends Model
{
use GeneratesPublicKey;
use GeneratesPublicKey, BitMasks;

public $timestamps = true;

Expand All @@ -55,12 +52,7 @@ class SimulationCraftRaidEventsOptions extends Model
'shrouded_bounty_type',
'affix',
'thundering_clear_seconds',
'bloodlust',
'arcane_intellect',
'power_word_fortitude',
'battle_shout',
'mystic_touch',
'chaos_brand',
'raid_buffs_mask',
'hp_percent',
'simulate_bloodlust_per_pull',
'ranged_pull_compensation_yards',
Expand All @@ -69,6 +61,18 @@ class SimulationCraftRaidEventsOptions extends Model

protected $with = ['dungeonroute'];

protected $casts = [
'id' => 'int',
'dungeon_route_id' => 'int',
'user_id' => 'int',
'key_level' => 'int',
'thundering_clear_seconds' => 'int',
'raid_buffs_mask' => 'int',
'hp_percent' => 'float',
'ranged_pull_compensation_yards' => 'int',
'use_mounts' => 'bool',
];

public const SHROUDED_BOUNTY_TYPE_NONE = 'none';
public const SHROUDED_BOUNTY_TYPE_CRIT = 'crit';
public const SHROUDED_BOUNTY_TYPE_HASTE = 'haste';
Expand Down Expand Up @@ -106,6 +110,21 @@ public function isThunderingAffixActive(): bool
return $this->thundering_clear_seconds !== null;
}

public function addRaidBuff(SimulationCraftRaidBuffs $raidBuff): void
{
$this->raid_buffs_mask = $this->bitMaskAdd($this->raid_buffs_mask, $raidBuff->value);
}

public function removeRaidBuff(SimulationCraftRaidBuffs $raidBuff): void
{
$this->raid_buffs_mask = $this->bitMaskRemove($this->raid_buffs_mask, $raidBuff->value);
}

public function hasRaidBuff(SimulationCraftRaidBuffs $raidBuff): bool
{
return $this->bitMaskHasValue($this->raid_buffs_mask, $raidBuff->value);
}

public function hasAffix(string $affix): bool
{
return in_array($affix, explode(',', $this->affix));
Expand All @@ -128,6 +147,9 @@ public function getAffixes(): array
return $affixes;
}

/**
* @throws RandomException
*/
public static function fromRequest(AjaxDungeonRouteSimulateFormRequest $request, DungeonRoute $dungeonRoute): SimulationCraftRaidEventsOptions
{
$hasAdvancedSimulation = Auth::check() && Auth::user()->hasPatreonBenefit(PatreonBenefit::ADVANCED_SIMULATION);
Expand Down
36 changes: 36 additions & 0 deletions app/Models/Traits/BitMasks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace App\Models\Traits;

trait BitMasks
{
/**
* @param int $value
* @param int $flag
* @return int
*/
protected function bitMaskAdd(int $value, int $flag): int
{
return $value | $flag;
}

/**
* @param int $value
* @param int $flag
* @return int
*/
protected function bitMaskRemove(int $value, int $flag): int
{
return $value & ~$flag;
}

/**
* @param int $value
* @param int $flag
* @return bool
*/
protected function bitMaskHasValue(int $value, int $flag): bool
{
return ($value & $flag) > 0;
}
}
10 changes: 9 additions & 1 deletion app/Providers/KeystoneGuruServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use App\Models\Patreon\PatreonBenefit;
use App\Models\Release;
use App\Models\Season;
use App\Models\SimulationCraft\SimulationCraftRaidBuffs;
use App\Models\SimulationCraft\SimulationCraftRaidEventsOptions;
use App\Models\User;
use App\Models\UserReport;
Expand Down Expand Up @@ -119,6 +120,7 @@
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use Jenssegers\Agent\Agent;
use Str;

class KeystoneGuruServiceProvider extends ServiceProvider
{
Expand Down Expand Up @@ -519,14 +521,20 @@ static function (View $view) use ($globalViewVariables) {
}
$affixes = [];
foreach (SimulationCraftRaidEventsOptions::ALL_AFFIXES as $affix) {
$affixes[$affix] = __(sprintf('view_common.modal.simulate.affixes_map.%s', $affix));
$affixes[$affix] = __(sprintf('view_common.modal.simulateoptions.default.affixes_map.%s', $affix));
}
/** @var Season $currentSeason */
$currentSeason = $regionViewVariables['currentSeason'];
$currentAffixGroup = $currentSeason->getCurrentAffixGroup();
$view->with('shroudedBountyTypes', $shroudedBountyTypes);
$view->with('affixes', $affixes);
$view->with('isShrouded', $currentAffixGroup?->hasAffix(Affix::AFFIX_SHROUDED) ?? false);
$view->with('raidBuffsOptions', collect(SimulationCraftRaidBuffs::cases())->mapWithKeys(static function (SimulationCraftRaidBuffs $raidBuff) {
return [
$raidBuff->value =>
__(sprintf('view_common.modal.simulateoptions.default.raid_buffs_map.%s', Str::lower(Str::snake($raidBuff->name))))
];
})->toArray());
});

// Thirdparty
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('simulation_craft_raid_events_options', function (Blueprint $table) {
$table->integer('raid_buffs_mask')->after('thundering_clear_seconds')->default(0);
$table->index('raid_buffs_mask');
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('simulation_craft_raid_events_options', function (Blueprint $table) {
$table->dropColumn('raid_buffs_mask');
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

use App\Models\SimulationCraft\SimulationCraftRaidBuffs;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
$replace = [
'bloodlust' => SimulationCraftRaidBuffs::Bloodlust,
'arcane_intellect' => SimulationCraftRaidBuffs::ArcaneIntellect,
'power_word_fortitude' => SimulationCraftRaidBuffs::PowerWordFortitude,
'battle_shout' => SimulationCraftRaidBuffs::BattleShout,
'mystic_touch' => SimulationCraftRaidBuffs::MysticTouch,
'chaos_brand' => SimulationCraftRaidBuffs::ChaosBrand,
];

foreach($replace as $from => $to) {
/** @noinspection SqlResolve */
DB::update(
sprintf(
'UPDATE `simulation_craft_raid_events_options` SET `raid_buffs_mask` = `raid_buffs_mask` | %d WHERE `%s` = 1',
$to,
$from
)
);
}
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('simulation_craft_raid_events_options', function (Blueprint $table) {
//
});
}
};
Loading

0 comments on commit 3f1b2d6

Please sign in to comment.