87 lines
2.8 KiB
PHP
87 lines
2.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace sammo;
|
|
|
|
final class NpcPossessionSelector
|
|
{
|
|
public static function buildSeed(string|int $hiddenSeed, int $owner, string|int $now): string
|
|
{
|
|
return Util::simpleSerialize($hiddenSeed, 'SelectNPCToken', $owner, $now);
|
|
}
|
|
|
|
/** @param array<string, mixed> $general */
|
|
public static function weight(array $general): float
|
|
{
|
|
return pow(
|
|
(int)$general['leadership'] + (int)$general['strength'] + (int)$general['intel'],
|
|
1.5,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param array<int|string, array<string, mixed>> $oldPick
|
|
* @param list<int> $keepIds
|
|
* @return array{picked: array<int|string, array<string, mixed>>, cancelled: bool}
|
|
*/
|
|
public static function applyKeep(array $oldPick, array $keepIds): array
|
|
{
|
|
$picked = [];
|
|
foreach ($keepIds as $keepId) {
|
|
if (array_key_exists($keepId, $oldPick) && (int)$oldPick[$keepId]['keepCnt'] > 0) {
|
|
$picked[$keepId] = $oldPick[$keepId];
|
|
$picked[$keepId]['keepCnt'] = (int)$picked[$keepId]['keepCnt'] - 1;
|
|
}
|
|
}
|
|
return [
|
|
'picked' => $picked,
|
|
'cancelled' => count($picked) === count($oldPick),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<int|string, array<string, mixed>> $candidates
|
|
* @param array<int|string, float> $weights
|
|
* @param iterable<string> $reservedPayloads
|
|
*/
|
|
public static function removeReserved(array &$candidates, array &$weights, iterable $reservedPayloads): void
|
|
{
|
|
foreach ($reservedPayloads as $reservedPayload) {
|
|
$reserved = Json::decode($reservedPayload);
|
|
foreach (array_keys($reserved) as $reservedNpc) {
|
|
if (array_key_exists($reservedNpc, $weights)) {
|
|
unset($candidates[$reservedNpc], $weights[$reservedNpc]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<int|string, array<string, mixed>> $candidates
|
|
* @param array<int|string, float> $weights
|
|
* @param array<int|string, array<string, mixed>> $picked
|
|
* @param null|callable(int|string): void $onDraw
|
|
* @return array<int|string, array<string, mixed>>
|
|
*/
|
|
public static function select(
|
|
array $candidates,
|
|
array $weights,
|
|
array $picked,
|
|
RandUtil $rng,
|
|
?callable $onDraw = null,
|
|
): array {
|
|
$pickLimit = min(count($candidates), 5);
|
|
while (count($picked) < $pickLimit) {
|
|
$generalId = $rng->choiceUsingWeight($weights);
|
|
if ($onDraw !== null) {
|
|
$onDraw($generalId);
|
|
}
|
|
if (!array_key_exists($generalId, $picked)) {
|
|
$picked[$generalId] = $candidates[$generalId];
|
|
}
|
|
}
|
|
return $picked;
|
|
}
|
|
}
|