feat: 100기 NPC 동조와 후보 추첨 보완
This commit is contained in:
@@ -6,19 +6,19 @@ include "func.php";
|
|||||||
|
|
||||||
WebUtil::requireAJAX();
|
WebUtil::requireAJAX();
|
||||||
|
|
||||||
$pick = Util::getPost('pick');
|
$pick = Util::getPost('pick');
|
||||||
$leadership = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
|
$leadership = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
|
||||||
$isCentennialAllStar = CentennialAllStarGrowthService::isActive();
|
$isCentennialAllStar = CentennialAllStarGrowthService::isActive();
|
||||||
$strength = Util::getPost(
|
$strength = Util::getPost(
|
||||||
$isCentennialAllStar ? 'strength' : 'leadership',
|
$isCentennialAllStar ? 'strength' : 'leadership',
|
||||||
'int',
|
'int',
|
||||||
GameConst::$defaultStatMin
|
GameConst::$defaultStatMin
|
||||||
);
|
);
|
||||||
$intel = Util::getPost(
|
$intel = Util::getPost(
|
||||||
$isCentennialAllStar ? 'intel' : 'leadership',
|
$isCentennialAllStar ? 'intel' : 'leadership',
|
||||||
'int',
|
'int',
|
||||||
GameConst::$defaultStatMin
|
GameConst::$defaultStatMin
|
||||||
);
|
);
|
||||||
$personal = Util::getPost('personal', 'string', null);
|
$personal = Util::getPost('personal', 'string', null);
|
||||||
$use_own_picture = Util::getPost('use_own_picture', 'bool', false);
|
$use_own_picture = Util::getPost('use_own_picture', 'bool', false);
|
||||||
|
|
||||||
@@ -87,19 +87,19 @@ if ($gencount >= $maxgeneral) {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$poolClass = getGeneralPoolClass(GameConst::$targetGeneralPool);
|
$poolClass = getGeneralPoolClass(GameConst::$targetGeneralPool);
|
||||||
/** @var AbsGeneralPool */
|
/** @var AbsGeneralPool */
|
||||||
if ($isCentennialAllStar) {
|
if ($isCentennialAllStar) {
|
||||||
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
UniqueConst::$hiddenSeed,
|
UniqueConst::$hiddenSeed,
|
||||||
'selectPickedGeneral',
|
'selectPickedGeneral',
|
||||||
$userID,
|
$userID,
|
||||||
$pick
|
$pick
|
||||||
)));
|
)));
|
||||||
$pickedGeneral = new $poolClass($db, $rng, $selectInfo, $now);
|
$pickedGeneral = new $poolClass($db, $rng, $selectInfo, $now);
|
||||||
} else {
|
} else {
|
||||||
$pickedGeneral = new $poolClass($db, $selectInfo, $now);
|
$pickedGeneral = new $poolClass($db, $selectInfo, $now);
|
||||||
}
|
}
|
||||||
|
|
||||||
$builder = $pickedGeneral->getGeneralBuilder();
|
$builder = $pickedGeneral->getGeneralBuilder();
|
||||||
|
|
||||||
@@ -124,10 +124,10 @@ foreach(GameConst::$generalPoolAllowOption as $allowOption){
|
|||||||
if(!$personal || $personal == 'Random'){
|
if(!$personal || $personal == 'Random'){
|
||||||
$personal = Util::choiceRandom(GameConst::$availablePersonality);
|
$personal = Util::choiceRandom(GameConst::$availablePersonality);
|
||||||
}
|
}
|
||||||
$invalidPersonal = $isCentennialAllStar
|
$invalidPersonal = $isCentennialAllStar
|
||||||
? !in_array($personal, GameConst::$availablePersonality, true)
|
? !in_array($personal, GameConst::$availablePersonality, true)
|
||||||
: !array_search($personal, GameConst::$availablePersonality);
|
: !array_search($personal, GameConst::$availablePersonality);
|
||||||
if($invalidPersonal){
|
if($invalidPersonal){
|
||||||
Json::die([
|
Json::die([
|
||||||
'result'=>false,
|
'result'=>false,
|
||||||
'reason'=>'올바르지 않은 성격입니다.'
|
'reason'=>'올바르지 않은 성격입니다.'
|
||||||
@@ -145,6 +145,23 @@ $builder->setKillturn(5);
|
|||||||
$builder->setNPCType(0);
|
$builder->setNPCType(0);
|
||||||
$builder->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $env['turnterm']));
|
$builder->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $env['turnterm']));
|
||||||
$builder->fillRemainSpecAsZero($env);
|
$builder->fillRemainSpecAsZero($env);
|
||||||
|
if ($isCentennialAllStar) {
|
||||||
|
$candidateCities = $db->queryFirstColumn(
|
||||||
|
'SELECT city FROM city WHERE level >= 5 AND level <= 6 AND nation = 0'
|
||||||
|
);
|
||||||
|
if (!$candidateCities) {
|
||||||
|
$candidateCities = $db->queryFirstColumn(
|
||||||
|
'SELECT city FROM city WHERE level >= 5 AND level <= 6'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!$candidateCities) {
|
||||||
|
Json::die([
|
||||||
|
'result' => false,
|
||||||
|
'reason' => '장수를 생성할 소·중성이 없습니다.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$builder->setCityID($rng->choice($candidateCities));
|
||||||
|
}
|
||||||
$builder->build($env);
|
$builder->build($env);
|
||||||
$generalID = $builder->getGeneralID();
|
$generalID = $builder->getGeneralID();
|
||||||
if(!$generalID){
|
if(!$generalID){
|
||||||
@@ -189,4 +206,4 @@ $rootDB->insert('member_log', [
|
|||||||
Json::die([
|
Json::die([
|
||||||
'result'=>true,
|
'result'=>true,
|
||||||
'reason'=>'success'
|
'reason'=>'success'
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ use sammo\Util;
|
|||||||
|
|
||||||
abstract class AbsFromUserPool extends AbsGeneralPool{
|
abstract class AbsFromUserPool extends AbsGeneralPool{
|
||||||
|
|
||||||
|
protected static function getCandidateWeight(array $info, int $owner): int|float
|
||||||
|
{
|
||||||
|
return array_sum($info['dex'] ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
public function occupyGeneralName(): bool
|
public function occupyGeneralName(): bool
|
||||||
{
|
{
|
||||||
$generalID = $this->getGeneralBuilder()->getGeneralID();
|
$generalID = $this->getGeneralBuilder()->getGeneralID();
|
||||||
@@ -36,8 +41,7 @@ abstract class AbsFromUserPool extends AbsGeneralPool{
|
|||||||
$pool = [];
|
$pool = [];
|
||||||
foreach($db->query('SELECT id, unique_name, info FROM select_pool WHERE reserved_until IS NULL AND general_id IS NULL', $pickCnt) as $cand){
|
foreach($db->query('SELECT id, unique_name, info FROM select_pool WHERE reserved_until IS NULL AND general_id IS NULL', $pickCnt) as $cand){
|
||||||
$cand['info'] = Json::decode($cand['info']);
|
$cand['info'] = Json::decode($cand['info']);
|
||||||
$dexTotal = array_sum($cand['info']['dex']);
|
$pool[] = [$cand, static::getCandidateWeight($cand['info'], $owner)];
|
||||||
$pool[] = [$cand, $dexTotal];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count($pool) < $pickCnt){
|
if(count($pool) < $pickCnt){
|
||||||
@@ -69,4 +73,4 @@ abstract class AbsFromUserPool extends AbsGeneralPool{
|
|||||||
|
|
||||||
return array_values($result);
|
return array_values($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ final class CentennialAllStarGrowthService
|
|||||||
public const POOL_CLASS = 'SPoolUnderU100';
|
public const POOL_CLASS = 'SPoolUnderU100';
|
||||||
public const AUX_KEY = 'event100_allstar';
|
public const AUX_KEY = 'event100_allstar';
|
||||||
public const TRAIT_UNLOCK_PROGRESS = 0.4;
|
public const TRAIT_UNLOCK_PROGRESS = 0.4;
|
||||||
|
public const NPC_PROGRESS_MULTIPLIER = 0.9;
|
||||||
|
|
||||||
private const STAT_KEYS = ['leadership', 'strength', 'intel'];
|
private const STAT_KEYS = ['leadership', 'strength', 'intel'];
|
||||||
private const DEX_KEYS = ['dex1', 'dex2', 'dex3', 'dex4', 'dex5'];
|
private const DEX_KEYS = ['dex1', 'dex2', 'dex3', 'dex4', 'dex5'];
|
||||||
@@ -35,18 +36,47 @@ final class CentennialAllStarGrowthService
|
|||||||
$builder->setAuxVar(self::AUX_KEY, self::initialAux($targetInfo));
|
$builder->setAuxVar(self::AUX_KEY, self::initialAux($targetInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function calculateProgress(
|
||||||
|
int $startYear,
|
||||||
|
int $year,
|
||||||
|
int $month,
|
||||||
|
float $progressMultiplier = 1.0
|
||||||
|
): float {
|
||||||
|
if ($progressMultiplier < 0 || $progressMultiplier > 1) {
|
||||||
|
throw new \InvalidArgumentException('progress multiplier must be between 0 and 1');
|
||||||
|
}
|
||||||
|
return min(
|
||||||
|
1,
|
||||||
|
CentennialAllStarGrowth::progress($startYear, $year, $month)
|
||||||
|
* $progressMultiplier
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mutates the General object but leaves persistence to the caller.
|
* Mutates the General object but leaves persistence to the caller.
|
||||||
*
|
*
|
||||||
* @return array{progress:float,milestone:int,previousMilestone:int,targetChanged:bool,changed:bool}
|
* @return array{progress:float,milestone:int,previousMilestone:int,targetChanged:bool,changed:bool}
|
||||||
*/
|
*/
|
||||||
public static function applyTarget(General $general, array $targetInfo, array $env): array
|
public static function applyTarget(
|
||||||
|
General $general,
|
||||||
|
array $targetInfo,
|
||||||
|
array $env,
|
||||||
|
float $progressMultiplier = 1.0
|
||||||
|
): array
|
||||||
{
|
{
|
||||||
$startYear = (int) $env['startyear'];
|
$startYear = (int) $env['startyear'];
|
||||||
$year = (int) $env['year'];
|
$year = (int) $env['year'];
|
||||||
$month = (int) $env['month'];
|
$month = (int) $env['month'];
|
||||||
$progress = CentennialAllStarGrowth::progress($startYear, $year, $month);
|
$progress = self::calculateProgress(
|
||||||
$progressMonth = max(0, ($year - $startYear) * 12 + $month - 1);
|
$startYear,
|
||||||
|
$year,
|
||||||
|
$month,
|
||||||
|
$progressMultiplier
|
||||||
|
);
|
||||||
|
$progressMonth = (int) floor(
|
||||||
|
max(0, ($year - $startYear) * 12 + $month - 1)
|
||||||
|
* $progressMultiplier
|
||||||
|
);
|
||||||
$targetId = (string) ($targetInfo['uniqueName'] ?? '');
|
$targetId = (string) ($targetInfo['uniqueName'] ?? '');
|
||||||
|
|
||||||
$aux = $general->getAuxVar(self::AUX_KEY);
|
$aux = $general->getAuxVar(self::AUX_KEY);
|
||||||
@@ -159,6 +189,42 @@ final class CentennialAllStarGrowthService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function progressMultiplierFor(General $general): float
|
||||||
|
{
|
||||||
|
return self::progressMultiplierForNPCType($general->getNPCType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function progressMultiplierForNPCType(int $npcType): float
|
||||||
|
{
|
||||||
|
return in_array($npcType, [3, 4], true)
|
||||||
|
? self::NPC_PROGRESS_MULTIPLIER
|
||||||
|
: 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function applyCurrentTargetToBuiltNPC(
|
||||||
|
\MeekroDB $db,
|
||||||
|
GeneralBuilder $builder,
|
||||||
|
array $targetInfo,
|
||||||
|
array $env
|
||||||
|
): ?array {
|
||||||
|
if (!self::isActive()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$general = General::createObjFromDB($builder->getGeneralID());
|
||||||
|
if (!in_array($general->getNPCType(), [3, 4], true)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$result = self::applyTarget(
|
||||||
|
$general,
|
||||||
|
$targetInfo,
|
||||||
|
$env,
|
||||||
|
self::NPC_PROGRESS_MULTIPLIER
|
||||||
|
);
|
||||||
|
$general->applyDB($db);
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
public static function recordableValue(General $general, string $key): int
|
public static function recordableValue(General $general, string $key): int
|
||||||
{
|
{
|
||||||
$aux = $general->getAuxVar(self::AUX_KEY);
|
$aux = $general->getAuxVar(self::AUX_KEY);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use \sammo\Util;
|
|||||||
use \sammo\JosaUtil;
|
use \sammo\JosaUtil;
|
||||||
use \sammo\General;
|
use \sammo\General;
|
||||||
use \sammo\ActionLogger;
|
use \sammo\ActionLogger;
|
||||||
|
use \sammo\CentennialAllStarGrowthService;
|
||||||
use \sammo\GameConst;
|
use \sammo\GameConst;
|
||||||
use \sammo\LastTurn;
|
use \sammo\LastTurn;
|
||||||
use \sammo\GameUnitConst;
|
use \sammo\GameUnitConst;
|
||||||
@@ -190,6 +191,12 @@ class che_인재탐색 extends Command\GeneralCommand
|
|||||||
$newNPC->fillRemainSpecAsRandom($pickTypeList, $avgGen, $env);
|
$newNPC->fillRemainSpecAsRandom($pickTypeList, $avgGen, $env);
|
||||||
|
|
||||||
$newNPC->build($this->env);
|
$newNPC->build($this->env);
|
||||||
|
CentennialAllStarGrowthService::applyCurrentTargetToBuiltNPC(
|
||||||
|
$db,
|
||||||
|
$newNPC,
|
||||||
|
$pickedNPC->getInfo(),
|
||||||
|
$this->env
|
||||||
|
);
|
||||||
$pickedNPC->occupyGeneralName();
|
$pickedNPC->occupyGeneralName();
|
||||||
$npcName = $newNPC->getGeneralName();
|
$npcName = $newNPC->getGeneralName();
|
||||||
$josaRa = JosaUtil::pick($npcName, '라');
|
$josaRa = JosaUtil::pick($npcName, '라');
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use \sammo\Util;
|
|||||||
use \sammo\JosaUtil;
|
use \sammo\JosaUtil;
|
||||||
use \sammo\General;
|
use \sammo\General;
|
||||||
use \sammo\ActionLogger;
|
use \sammo\ActionLogger;
|
||||||
|
use \sammo\CentennialAllStarGrowthService;
|
||||||
use \sammo\GameConst;
|
use \sammo\GameConst;
|
||||||
use \sammo\LastTurn;
|
use \sammo\LastTurn;
|
||||||
use \sammo\GameUnitConst;
|
use \sammo\GameUnitConst;
|
||||||
@@ -160,6 +161,12 @@ class che_의병모집 extends Command\NationCommand
|
|||||||
$newNPC->fillRemainSpecAsRandom($pickTypeList, $avgGen, $env);
|
$newNPC->fillRemainSpecAsRandom($pickTypeList, $avgGen, $env);
|
||||||
|
|
||||||
$newNPC->build($this->env);
|
$newNPC->build($this->env);
|
||||||
|
CentennialAllStarGrowthService::applyCurrentTargetToBuiltNPC(
|
||||||
|
$db,
|
||||||
|
$newNPC,
|
||||||
|
$pickedNPC->getInfo(),
|
||||||
|
$this->env
|
||||||
|
);
|
||||||
$pickedNPC->occupyGeneralName();
|
$pickedNPC->occupyGeneralName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,12 @@ class AdvanceCentennialAllStar extends \sammo\Event\Action
|
|||||||
) as $row) {
|
) as $row) {
|
||||||
$general = General::createObjFromDB((int) $row['no']);
|
$general = General::createObjFromDB((int) $row['no']);
|
||||||
$targetInfo = Json::decode($row['info']);
|
$targetInfo = Json::decode($row['info']);
|
||||||
$result = CentennialAllStarGrowthService::applyTarget($general, $targetInfo, $env);
|
$result = CentennialAllStarGrowthService::applyTarget(
|
||||||
|
$general,
|
||||||
|
$targetInfo,
|
||||||
|
$env,
|
||||||
|
CentennialAllStarGrowthService::progressMultiplierFor($general)
|
||||||
|
);
|
||||||
|
|
||||||
if ($result['milestone'] > $result['previousMilestone']) {
|
if ($result['milestone'] > $result['previousMilestone']) {
|
||||||
$percent = $result['milestone'] * 20;
|
$percent = $result['milestone'] * 20;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace sammo\Event\Action;
|
|||||||
use \sammo\GameConst;
|
use \sammo\GameConst;
|
||||||
use \sammo\Util;
|
use \sammo\Util;
|
||||||
use \sammo\DB;
|
use \sammo\DB;
|
||||||
|
use sammo\CentennialAllStarGrowthService;
|
||||||
use sammo\LiteHashDRBG;
|
use sammo\LiteHashDRBG;
|
||||||
use sammo\RandUtil;
|
use sammo\RandUtil;
|
||||||
use sammo\UniqueConst;
|
use sammo\UniqueConst;
|
||||||
@@ -35,7 +36,8 @@ class CreateManyNPC extends \sammo\Event\Action
|
|||||||
)));
|
)));
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach (pickGeneralFromPool(DB::db(), $rng, 0, $cnt) as $pickedNPC) {
|
$db = DB::db();
|
||||||
|
foreach (pickGeneralFromPool($db, $rng, 0, $cnt) as $pickedNPC) {
|
||||||
$age = $rng->nextRangeInt(20, 25);
|
$age = $rng->nextRangeInt(20, 25);
|
||||||
$birthYear = $env['year'] - $age;
|
$birthYear = $env['year'] - $age;
|
||||||
$deathYear = $env['year'] + $rng->nextRangeInt(10, 50);
|
$deathYear = $env['year'] + $rng->nextRangeInt(10, 50);
|
||||||
@@ -50,6 +52,12 @@ class CreateManyNPC extends \sammo\Event\Action
|
|||||||
}
|
}
|
||||||
$newNPC->fillRemainSpecAsZero($env);
|
$newNPC->fillRemainSpecAsZero($env);
|
||||||
$newNPC->build($env);
|
$newNPC->build($env);
|
||||||
|
CentennialAllStarGrowthService::applyCurrentTargetToBuiltNPC(
|
||||||
|
$db,
|
||||||
|
$newNPC,
|
||||||
|
$pickedNPC->getInfo(),
|
||||||
|
$env
|
||||||
|
);
|
||||||
$pickedNPC->occupyGeneralName();
|
$pickedNPC->occupyGeneralName();
|
||||||
$result[] = [
|
$result[] = [
|
||||||
$newNPC->getGeneralName(), $newNPC->getGeneralID()
|
$newNPC->getGeneralName(), $newNPC->getGeneralID()
|
||||||
|
|||||||
+4682
-4682
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,11 @@ use sammo\RandUtil;
|
|||||||
|
|
||||||
class SPoolUnderU100 extends AbsFromUserPool
|
class SPoolUnderU100 extends AbsFromUserPool
|
||||||
{
|
{
|
||||||
|
private const MIN_DEX_WEIGHT = 100000;
|
||||||
|
private const STAT_BONUS_MIN_TOTAL = 160;
|
||||||
|
private const STAT_BONUS_MAX_TOTAL = 190;
|
||||||
|
private const STAT_BONUS_MAX_MULTIPLIER = 1.5;
|
||||||
|
|
||||||
public function __construct(\MeekroDB $db, RandUtil $rng, array $info, string $validUntil)
|
public function __construct(\MeekroDB $db, RandUtil $rng, array $info, string $validUntil)
|
||||||
{
|
{
|
||||||
$targetInfo = $info;
|
$targetInfo = $info;
|
||||||
@@ -36,6 +41,32 @@ class SPoolUnderU100 extends AbsFromUserPool
|
|||||||
return '100기 올스타 클래식';
|
return '100기 올스타 클래식';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function getCandidateWeight(array $info, int $owner): int|float
|
||||||
|
{
|
||||||
|
$dexWeight = max(
|
||||||
|
self::MIN_DEX_WEIGHT,
|
||||||
|
array_sum($info['dex'] ?? [])
|
||||||
|
);
|
||||||
|
if ($owner <= 0) {
|
||||||
|
return $dexWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
$statTotal = array_sum([
|
||||||
|
(int) ($info['leadership'] ?? 0),
|
||||||
|
(int) ($info['strength'] ?? 0),
|
||||||
|
(int) ($info['intel'] ?? 0),
|
||||||
|
]);
|
||||||
|
$normalizedStat = min(1, max(
|
||||||
|
0,
|
||||||
|
($statTotal - self::STAT_BONUS_MIN_TOTAL)
|
||||||
|
/ (self::STAT_BONUS_MAX_TOTAL - self::STAT_BONUS_MIN_TOTAL)
|
||||||
|
));
|
||||||
|
$statMultiplier = 1
|
||||||
|
+ (self::STAT_BONUS_MAX_MULTIPLIER - 1) * $normalizedStat;
|
||||||
|
|
||||||
|
return $dexWeight * $statMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
public static function initPool(\MeekroDB $db)
|
public static function initPool(\MeekroDB $db)
|
||||||
{
|
{
|
||||||
$jsonData = Json::decode(file_get_contents(__DIR__ . '/Pool/UnderS100.json'));
|
$jsonData = Json::decode(file_get_contents(__DIR__ . '/Pool/UnderS100.json'));
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ function decodeSourceRow(string $line, int $lineNo): array
|
|||||||
if ($sourceName === '') {
|
if ($sourceName === '') {
|
||||||
fail("line {$lineNo}: empty general name");
|
fail("line {$lineNo}: empty general name");
|
||||||
}
|
}
|
||||||
$generalName = sprintf('【%d기】%s', $phaseNo, $sourceName);
|
$generalName = sprintf('%d·%s', $phaseNo, $sourceName);
|
||||||
if (mb_strlen($generalName) > 32) {
|
if (mb_strlen($generalName) > 32) {
|
||||||
fail("line {$lineNo}: generated name exceeds 32 characters: {$generalName}");
|
fail("line {$lineNo}: generated name exceeds 32 characters: {$generalName}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,40 @@ final class CentennialAllStarGrowthTest extends TestCase
|
|||||||
self::assertSame(1.0, CentennialAllStarGrowth::progress(180, 210, 1));
|
self::assertSame(1.0, CentennialAllStarGrowth::progress(180, 210, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testMAndGGeneralsAdvanceAtNinetyPercentProgress(): void
|
||||||
|
{
|
||||||
|
self::assertSame(
|
||||||
|
CentennialAllStarGrowthService::NPC_PROGRESS_MULTIPLIER,
|
||||||
|
CentennialAllStarGrowthService::progressMultiplierForNPCType(3)
|
||||||
|
);
|
||||||
|
self::assertSame(
|
||||||
|
CentennialAllStarGrowthService::NPC_PROGRESS_MULTIPLIER,
|
||||||
|
CentennialAllStarGrowthService::progressMultiplierForNPCType(4)
|
||||||
|
);
|
||||||
|
self::assertSame(1.0, CentennialAllStarGrowthService::progressMultiplierForNPCType(2));
|
||||||
|
self::assertEqualsWithDelta(
|
||||||
|
0.36,
|
||||||
|
CentennialAllStarGrowthService::calculateProgress(180, 186, 1, 0.9),
|
||||||
|
0.000001
|
||||||
|
);
|
||||||
|
self::assertEqualsWithDelta(
|
||||||
|
0.9,
|
||||||
|
CentennialAllStarGrowthService::calculateProgress(180, 195, 1, 0.9),
|
||||||
|
0.000001
|
||||||
|
);
|
||||||
|
self::assertEqualsWithDelta(
|
||||||
|
0.9,
|
||||||
|
CentennialAllStarGrowthService::calculateProgress(180, 210, 1, 0.9),
|
||||||
|
0.000001
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProgressMultiplierMustStayWithinUnitInterval(): void
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
CentennialAllStarGrowthService::calculateProgress(180, 195, 1, 1.01);
|
||||||
|
}
|
||||||
|
|
||||||
public function testLowStatGrowsWhileHigherStatStays(): void
|
public function testLowStatGrowsWhileHigherStatStays(): void
|
||||||
{
|
{
|
||||||
$floor = CentennialAllStarGrowth::statFloor(90, 15, 0.6);
|
$floor = CentennialAllStarGrowth::statFloor(90, 15, 0.6);
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use sammo\GeneralPool\SPoolUnderU100;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../hwe/sammo/AbsGeneralPool.php';
|
||||||
|
require_once __DIR__ . '/../hwe/sammo/AbsFromUserPool.php';
|
||||||
|
require_once __DIR__ . '/../hwe/sammo/GeneralPool/SPoolUnderU100.php';
|
||||||
|
|
||||||
final class CentennialAllStarPoolTest extends TestCase
|
final class CentennialAllStarPoolTest extends TestCase
|
||||||
{
|
{
|
||||||
@@ -57,6 +62,13 @@ final class CentennialAllStarPoolTest extends TestCase
|
|||||||
$generalName = $row[$column['generalName']];
|
$generalName = $row[$column['generalName']];
|
||||||
self::assertArrayNotHasKey($generalName, $generalNames);
|
self::assertArrayNotHasKey($generalName, $generalNames);
|
||||||
$generalNames[$generalName] = true;
|
$generalNames[$generalName] = true;
|
||||||
|
self::assertMatchesRegularExpression('/^(\d{1,2})·.+$/u', $generalName);
|
||||||
|
self::assertSame(
|
||||||
|
1,
|
||||||
|
preg_match('/^(\d{1,2})·/u', $generalName, $nameMatch)
|
||||||
|
);
|
||||||
|
self::assertSame($phase, (int) $nameMatch[1]);
|
||||||
|
self::assertLessThanOrEqual(32, mb_strlen($generalName));
|
||||||
|
|
||||||
self::assertCount(5, $row[$column['dex']]);
|
self::assertCount(5, $row[$column['dex']]);
|
||||||
self::assertNotEmpty($row[$column['selectionReasons']]);
|
self::assertNotEmpty($row[$column['selectionReasons']]);
|
||||||
@@ -86,6 +98,29 @@ final class CentennialAllStarPoolTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCentennialSelectionWeightFavorsUserStatsAndKeepsZeroDexEligible(): void
|
||||||
|
{
|
||||||
|
$method = new ReflectionMethod(SPoolUnderU100::class, 'getCandidateWeight');
|
||||||
|
$method->setAccessible(true);
|
||||||
|
$low = [
|
||||||
|
'leadership' => 80,
|
||||||
|
'strength' => 70,
|
||||||
|
'intel' => 10,
|
||||||
|
'dex' => [0, 0, 0, 0, 0],
|
||||||
|
];
|
||||||
|
$high = [
|
||||||
|
'leadership' => 95,
|
||||||
|
'strength' => 85,
|
||||||
|
'intel' => 10,
|
||||||
|
'dex' => [0, 0, 0, 0, 0],
|
||||||
|
];
|
||||||
|
|
||||||
|
self::assertSame(100000, $method->invoke(null, $low, 0));
|
||||||
|
self::assertSame(100000.0, $method->invoke(null, $low, 1));
|
||||||
|
self::assertSame(150000.0, $method->invoke(null, $high, 1));
|
||||||
|
self::assertSame(100000, $method->invoke(null, $high, 0));
|
||||||
|
}
|
||||||
|
|
||||||
public function testEveryHistoricalEventSpecialHasAnImplementation(): void
|
public function testEveryHistoricalEventSpecialHasAnImplementation(): void
|
||||||
{
|
{
|
||||||
$pool = json_decode(
|
$pool = json_decode(
|
||||||
|
|||||||
Reference in New Issue
Block a user