fix: stabilize S100 cooldowns and generated NPC growth

This commit is contained in:
2026-07-31 01:11:47 +00:00
parent 191abf83c0
commit 162f198f08
7 changed files with 203 additions and 16 deletions
+18 -8
View File
@@ -39,6 +39,10 @@ class DieOnPrestart extends \sammo\BaseAPI
$gameStor->cacheValues(['turnterm', 'opentime', 'turntime', 'year', 'month']);
$general = $db->queryFirstRow('SELECT no,name,nation,owner_name,npc FROM general WHERE owner=%i AND npc = 0', $userID);
if (!$general) {
return '장수가 없습니다';
}
$lastRefresh = $db->queryFirstField(
'SELECT %b FROM general_access_log WHERE %b = %i',
GeneralAccessLogColumn::lastRefresh->value,
@@ -46,8 +50,9 @@ class DieOnPrestart extends \sammo\BaseAPI
$general['no']
);
if (!$general) {
return '장수가 없습니다';
$generalObj = General::createObjFromDB($general['no']);
if ($generalObj instanceof DummyGeneral) {
trigger_error("올바르지 않은 삭제 프로세스 $userID", E_USER_WARNING);
}
increaseRefresh("장수 삭제", 1);
@@ -61,18 +66,23 @@ class DieOnPrestart extends \sammo\BaseAPI
return '이미 국가에 소속되어있습니다.';
}
$targetTime = $generalObj->getAuxVar('prestart_delete_after');
if (!is_string($targetTime) || $targetTime === '') {
$targetTime = addTurn(
$lastRefresh ?: TimeUtil::now(),
$gameStor->turnterm,
GameConst::$minTurnDieOnPrestart
);
$generalObj->setAuxVar('prestart_delete_after', $targetTime);
$generalObj->applyDB($db);
}
//서버 가오픈시 할 수 있는 행동
$targetTime = addTurn($lastRefresh, $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
if ($targetTime > TimeUtil::now()) {
$targetTimeShort = substr($targetTime, 0, 19);
return "아직 삭제할 수 없습니다. {$targetTimeShort} 부터 가능합니다.";
}
$generalObj = General::createObjFromDB($general['no']);
if ($generalObj instanceof DummyGeneral) {
trigger_error("올바르지 않은 삭제 프로세스 $userID", E_USER_WARNING);
}
$generalName = $generalObj->getName();
$josaYi = JosaUtil::pick($generalName, '이');
$generalObj->kill($db, true, "<Y>{$generalName}</>{$josaYi} 홀연히 모습을 <R>감추었습니다</>");
+7
View File
@@ -435,6 +435,13 @@ class Join extends \sammo\BaseAPI
'specage2' => $specage2,
'special2' => $special2,
'penalty' => Json::encode($penalty),
'aux' => Json::encode([
'prestart_delete_after' => addTurn(
$now,
$admin['turnterm'],
GameConst::$minTurnDieOnPrestart
),
]),
]);
$generalID = $db->insertId();
$db->insert('general_access_log', [
@@ -451,6 +451,7 @@ final class CentennialAllStarGrowthService
if (!in_array($general->getNPCType(), [3, 4], true)) {
return null;
}
self::initializeGeneratedNPC($general, $targetInfo);
$result = self::applyTarget(
$general,
$targetInfo,
@@ -462,6 +463,36 @@ final class CentennialAllStarGrowthService
return $result;
}
/**
* Discards the builder's generic random stat/dex values before applying
* the selected all-star target. A newly generated NPC has no organic
* growth yet, so those temporary values must not mask the creation-date
* event baseline.
*/
public static function initializeGeneratedNPC(
General $general,
array $targetInfo
): void {
foreach (self::STAT_KEYS as $key) {
$target = min(
GameConst::$maxLevel,
max(0, (int) ($targetInfo[$key] ?? 0))
);
$general->updateVar(
$key,
CentennialAllStarGrowth::statFloor(
$target,
GameConst::$defaultStatMin,
0
)
);
}
foreach (self::DEX_KEYS as $key) {
$general->updateVar($key, 0);
}
$general->setAuxVar(self::AUX_KEY, self::initialAux($targetInfo));
}
/**
* Moves the event-backed part of a dex conversion with the converted
* value and consumes any guaranteed floor crossed by the source value.