Files
core/hwe/func_converter.php
T
Hide_D 477b77b59f feat: StaticEventHandler 처리기 추가
- 커맨드 종료 시점에 호출
  - pre, post 각각이 필요한지는 논의 필요
  - 일단 용도에 따라 pre, post 둘중에 하나만 처리
- eventType으로는 full qualified class name 사용
  - 꼭 그럴필요는 없지만, 커맨드에 한해서는 이렇게
2024-09-18 14:54:11 +00:00

908 lines
24 KiB
PHP

<?php
namespace sammo;
use sammo\Command\BaseCommand;
/**
* Value Converter
*
* Side effect 없이 값의 변환만을 수행하는 함수들의 모음.
* (단, autoload, 정적 변수 초기화는 허용)
*/
function getCharacterList(bool $onlyAvailable=true){
$infoText = [];
if(!$onlyAvailable){
$class = buildPersonalityClass(GameConst::$neutralPersonality);
$infoText[GameConst::$neutralPersonality] = [$class->getName(), $class->getInfo()];
}
foreach(GameConst::$availablePersonality as $personalityID){
$class = buildPersonalityClass($personalityID);
$infoText[$personalityID] = [$class->getName(), $class->getInfo()];
}
if(!$onlyAvailable){
foreach(GameConst::$optionalPersonality as $personalityID){
$class = buildPersonalityClass($personalityID);
$infoText[$personalityID] = [$class->getName(), $class->getInfo()];
}
}
return $infoText;
}
function isOfficerSet(int $officerSet, int $reqOfficerLevel):bool{
return ($officerSet & (1 << $reqOfficerLevel)) !== 0;
}
function doOfficerSet(int $officerSet, int $reqOfficerLevel):int{
return ($officerSet | (1 << $reqOfficerLevel));
}
function getNationChiefLevel(int $level) {
return [
7=>5,
6=>5,
5=>7,
4=>7,
3=>9,
2=>9,
1=>11,
0=>11,
][$level];
}
function getNationLevel(int $level) {
return [
7=>'황제',
6=>'왕',
5=>'공',
4=>'주목',
3=>'주자사',
2=>'군벌',
1=>'호족',
0=>'방랑군',
][$level];
}
function convertTournamentType(string $type){
return[
'전력전'=>0,
'통솔전'=>1,
'일기토'=>2,
'설전'=>3,
][$type]??-1;
}
function getGenChar(?string $type) {
if($type === null){
return '-';
}
return buildPersonalityClass($type)->getName();
}
function getGeneralSpecialDomesticName(?string $type):string{
if($type === null){
return '-';
}
return buildGeneralSpecialDomesticClass($type)->getName();
}
function getGeneralSpecialWarName(?string $type):string{
if($type === null){
return '-';
}
return buildGeneralSpecialWarClass($type)->getName();
}
function getSpecialTextList():array{
static $list = null;
if($list !== null){
return $list;
}
$list = ['None' => ['-', null]];
foreach(GameConst::$availableSpecialDomestic as $specialKey){
$specialClass = buildGeneralSpecialDomesticClass($specialKey);
$list[$specialKey] = [$specialClass->getName(), $specialClass->getInfo()];
}
foreach(GameConst::$availableSpecialWar as $specialKey){
$specialClass = buildGeneralSpecialWarClass($specialKey);
$list[$specialKey] = [$specialClass->getName(), $specialClass->getInfo()];
}
return $list;
}
function getSpecialInfo(?string $type):?string{
if($type === null){
return null;
}
$infoText = getSpecialTextList();
return $infoText[$type][1]??null;
}
function getNationType(?string $type) {
$nationClass = buildNationTypeClass($type);
$text = $nationClass->getName();
$text = join(' ', StringUtil::splitString($text));
return $text;
}
function getRefreshScoreText($score) {
if($score < 50) $scoreName = '안함';
elseif($score < 100) $scoreName = '무관심';
elseif($score < 200) $scoreName = '가끔';
elseif($score < 400) $scoreName = '보통';
elseif($score < 800) $scoreName = '자주';
elseif($score < 1600) $scoreName = '열심';
elseif($score < 3200) $scoreName = '중독';
elseif($score < 6400) $scoreName = '폐인';
elseif($score < 12800) $scoreName = '경고';
else $scoreName = '헐...';
return $scoreName;
}
function getNationType2(?string $type) {
$nationClass = getNationTypeClass($type);
[$pros, $cons] = [$nationClass::$pros, $nationClass::$cons];
return "<font color=cyan>{$pros}</font> <font color=magenta>{$cons}</font>";
}
function getNationTypeClass(?string $type){
if($type === null || $type === ''){
$type = GameConst::$neutralNationType;
}
static $basePath = __NAMESPACE__.'\\ActionNationType\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
$classPath = ($basePath.'che_'.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 올바른 국가 타입 클래스가 아님");
}
function buildNationTypeClass(?string $type):BaseNation{
static $cache = [];
if($type === null){
$type = 'None';
}
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getNationTypeClass($type);
$obj = new $class();
$cache[$type]= $obj;
return $obj;
}
function getPersonalityClass(?string $type){
if($type === null || $type === ''){
$type = GameConst::$neutralPersonality;
}
static $basePath = __NAMESPACE__.'\\ActionPersonality\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
$classPath = ($basePath.'che_'.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 올바른 성격 클래스가 아님");
}
function buildPersonalityClass(?string $type):iAction{
static $cache = [];
if($type === null){
$type = 'None';
}
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getPersonalityClass($type);
$obj = new $class();
$cache[$type]= $obj;
return $obj;
}
function getItemClass(?string $type){
if($type === null){
$type = 'None';
}
static $basePath = __NAMESPACE__.'\\ActionItem\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}는 올바른 아이템 클래스가 아님");
}
function buildItemClass(?string $type):BaseItem{
static $cache = [];
if($type === null){
$type = 'None';
}
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getItemClass($type);
$obj = new $class();
$cache[$type]= $obj;
return $obj;
}
function getScenarioEffectClass(?string $type){
if($type === null || $type === ''){
$type = 'None';
}
static $basePath = __NAMESPACE__.'\\ActionScenarioEffect\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
$classPath = ($basePath.'che_'.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 시나리오 효과 클래스가 아님");
}
function buildScenarioEffectClass(?string $type):iAction{
static $cache = [];
if($type === null){
$type = 'None';
}
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getScenarioEffectClass($type);
$obj = new $class();
$cache[$type]= $obj;
return $obj;
}
function getGeneralSpecialDomesticClass(?string $type){
if($type === null || $type === ''){
$type = GameConst::$defaultSpecialDomestic;
}
static $basePath = __NAMESPACE__.'\\ActionSpecialDomestic\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
$classPath = ($basePath.'che_'.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 올바른 내정 특기가 아님");
}
function buildGeneralSpecialDomesticClass(?string $type):BaseSpecial{
static $cache = [];
if($type === null){
$type = 'None';
}
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getGeneralSpecialDomesticClass($type);
$obj = new $class();
$cache[$type]= $obj;
return $obj;
}
function getGeneralSpecialWarClass(?string $type){
if($type === null || $type === ''){
$type = GameConst::$defaultSpecialWar;
}
static $basePath = __NAMESPACE__.'\\ActionSpecialWar\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
$classPath = ($basePath.'che_'.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 올바른 전투 특기가 아님");
}
function buildGeneralSpecialWarClass(?string $type):BaseSpecial{
static $cache = [];
if($type === null){
$type = 'None';
}
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getGeneralSpecialWarClass($type);
$obj = new $class();
$cache[$type]= $obj;
return $obj;
}
function getActionCrewTypeClass(?string $type){
if($type === null || $type === ''){
$type = 'None';
}
static $basePath = __NAMESPACE__.'\\ActionCrewType\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
$classPath = ($basePath.'che_'.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 올바른 병종 효과가 아님");
}
function buildActionCrewTypeClass(?string $type):iAction{
static $cache = [];
if($type === null){
$type = 'None';
}
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getActionCrewTypeClass($type);
$obj = new $class();
$cache[$type]= $obj;
return $obj;
}
function getGeneralCommandClass(?string $type){
if($type === null || $type === ''){
$type = '휴식';
}
static $basePath = __NAMESPACE__.'\\Command\\General\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 올바른 장수 커맨드가 아님");
}
function buildGeneralCommandClass(?string $type, General $generalObj, array $env, $arg = null):Command\GeneralCommand{
$class = getGeneralCommandClass($type);
return new $class($generalObj, $env, $arg);
}
function getNationCommandClass(?string $type){
if($type === null || $type === ''){
$type = '휴식';
}
static $basePath = __NAMESPACE__.'\\Command\\Nation\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 올바른 국가 커맨드가 아님");
}
function buildNationCommandClass(?string $type, General $generalObj, array $env, LastTurn $lastTurn, $arg = null):Command\NationCommand{
$class = getNationCommandClass($type);
return new $class($generalObj, $env, $lastTurn, $arg);
}
function getWarUnitTriggerClass(string $type){
static $basePath = __NAMESPACE__.'\\WarUnitTrigger\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 WarUnitTrigger가 아님");
}
function buildWarUnitTriggerClass(?string $type, WarUnit $unit, ?array $args = null):BaseWarUnitTrigger{
$classPath = getWarUnitTriggerClass($type);
if(!$args){
return new $classPath($unit);
}
$class = new \ReflectionClass($classPath);
return $class->newInstanceArgs(array_merge([$unit], $args));
}
function getStaticEventClass(string $type){
static $basePath = __NAMESPACE__.'\\StaticEvent\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 StaticEvent가 아님");
}
function buildStaticEventClass(?string $type):BaseStaticEvent{
static $cache = [];
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getStaticEventClass($type);
$obj = new $class();
$cache[$type] = $obj;
return $obj;
}
function getGeneralPoolClass(string $type){
static $basePath = __NAMESPACE__.'\\GeneralPool\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 GeneralPool이 아님");
}
/**
* @param \MeekroDB $db
* @param int $owner
* @param int $pickCnt
* @param null|string $prefix
* @return AbsGeneralPool[]
*/
function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array{
/** @var AbsGeneralPool */
$class = getGeneralPoolClass(GameConst::$targetGeneralPool);
return $class::pickGeneralFromPool($db, $rng, $owner, $pickCnt, $prefix);
}
function countPureGeneralFromRawList(?array $rawGeneralList=null):int{
if(!$rawGeneralList){
return 0;
}
$result = 0;
foreach($rawGeneralList as $rawGeneral){
if(!$rawGeneral['npc'] === 5){
continue;
}
$result+=1;
}
return $result;
}
function getOfficerLevelText($officerLevel, $nlevel=8) {
if($officerLevel >= 0 && $officerLevel <= 4) { $nlevel = 0; }
$code = $nlevel * 100 + $officerLevel;
return [
812 => '군주',
811 => '참모',
810 => '제1장군',
809 => '제1모사',
808 => '제2장군',
807 => '제2모사',
806 => '제3장군',
805 => '제3모사',
712 => '황제', 612 => '왕',
711 => '승상', 611 => '광록훈',
710 => '표기장군', 610 => '좌장군',
709 => '사공', 609 => '상서령',
708 => '거기장군', 608 => '우장군',
707 => '태위', 607 => '중서령',
706 => '위장군', 606 => '전장군',
705 => '사도', 605 => '비서령',
512 => '공', 412 => '주목',
511 => '광록대부', 411 => '태사령',
510 => '안국장군', 410 => '아문장군',
509 => '집금오', 409 => '낭중',
508 => '파로장군', 408 => '호군',
507 => '소부', 407 => '종사중랑',
312 => '주자사', 212 => '군벌',
311 => '주부', 211 => '참모',
310 => '편장군', 210 => '비장군',
309 => '간의대부', 209 => '부참모',
112 => '영주', 12 => '두목',
111 => '참모', 11 => '부두목',
4 => '태수',
3 => '군사',
2 => '종사',
1 => '일반',
0 => '재야',
][$code]??'-';
}
function getCall($leadership, $strength, $intel) {
if($leadership < 40){
if($strength + $intel < 40){
return '아둔';
}
if($intel >= GameConst::$chiefStatMin && $strength < $intel * 0.8){
return '학자';
}
if($strength >= GameConst::$chiefStatMin && $intel < $strength * 0.8){
return '장사';
}
return '명사';
}
$maxStat = max($leadership, $strength, $intel);
$sum2Stat = min($leadership+$strength, $strength+$intel, $intel+$leadership);
if($maxStat >= GameConst::$chiefStatMin + GameConst::$statGradeLevel && $sum2Stat >= $maxStat * 1.7){
return '만능';
}
if($strength >= GameConst::$chiefStatMin - GameConst::$statGradeLevel && $intel < $strength * 0.8){
return '용장';
}
if($intel >= GameConst::$chiefStatMin - GameConst::$statGradeLevel && $strength < $intel * 0.8){
return '명장';
}
if($leadership >= GameConst::$chiefStatMin - GameConst::$statGradeLevel && $strength + $intel < $leadership){
return '차장';
}
return '평범';
}
function getDed($dedication) {
return getDedLevelText(getDedLevel($dedication));
}
function getDedLevelText(int $dedLevel):string{
if($dedLevel === 0){
return '무품관';
}
//{$maxDedLevel}품관 ~ 1품관
$dedInvLevel = GameConst::$maxDedLevel - $dedLevel + 1;
return "{$dedInvLevel}품관";
}
function getHonor($experience) {
if($experience < 640 ) $honor = '전무';
elseif($experience < 2560) $honor = '무명';
elseif($experience < 5760) $honor = '신동';
elseif($experience < 10240) $honor = '약간';
elseif($experience < 16000) $honor = '평범';
elseif($experience < 23040) $honor = '지역적';
elseif($experience < 31360) $honor = '전국적';
elseif($experience < 40960) $honor = '세계적';
elseif($experience < 45000) $honor = '유명';
elseif($experience < 51840) $honor = '명사';
elseif($experience < 55000) $honor = '호걸';
elseif($experience < 64000) $honor = '효웅';
elseif($experience < 77440) $honor = '영웅';
else $honor = '구세주';
return $honor;
}
function getExpLevel($experience) {
if($experience < 1000) {
$level = intdiv($experience, 100);
} else {
$level = Util::toInt(sqrt($experience/10));
}
$level = Util::clamp($level, 0, GameConst::$maxLevel);
return $level;
}
function getDedLevel($dedication) {
$level = Util::valueFit(
ceil(sqrt($dedication) / 10),
0,
GameConst::$maxDedLevel
);
return $level;
}
function expStatus($exp) {
return $exp / GameConst::$upgradeLimit * 100;
}
function getLevelPer($exp, $level) {
if($exp < 100) { $per = $exp; }
elseif($exp < 1000) { $per = $exp - ($level)*100; }
else { $per = ($exp - 10*$level*$level) / (2*$level+1) * 10; }
return $per;
}
function getBill(int $dedication) : int{
return getBillByLevel(getDedLevel($dedication));
}
function getBillByLevel(int $dedLevel) : int{
return ($dedLevel * 200 + 400);
}
function getCost(int $armtype) : int {
return GameUnitConst::byID($armtype)->cost;
}
function getTechLevel($tech):int{
return Util::valueFit(
floor($tech / 1000),
0,
GameConst::$maxTechLevel
);
}
function TechLimit($startYear, $year, $tech) : bool {
$relYear = $year - $startYear;
$relMaxTech = Util::valueFit(
floor($relYear / 5) + 1,
1,
GameConst::$maxTechLevel
);
$techLevel = getTechLevel($tech);
return $techLevel >= $relMaxTech;
}
function getTechAbil($tech) : int{
return getTechLevel($tech) * 25;
}
function getTechCost($tech) : float{
return 1 + getTechLevel($tech) * 0.15;
}
function getTechCall($tech) : string {
$techLevel = getTechLevel($tech);
return "{$techLevel}등급";
}
function getDexLevelList(): array{
return [
[0, 'navy', 'F-'],
[350, 'navy', 'F'],
[1375, 'navy', 'F+'],
[3500, 'skyblue', 'E-'],
[7125, 'skyblue', 'E'],
[12650, 'skyblue', 'E+'],
[20475, 'seagreen', 'D-'],
[31000, 'seagreen', 'D'],
[44625, 'seagreen', 'D+'],
[61750, 'teal', 'C-'],
[82775, 'teal', 'C'],
[108100, 'teal', 'C+'],
[138125, 'limegreen', 'B-'],
[173250, 'limegreen', 'B'],
[213875, 'limegreen', 'B+'],
[260400, 'darkorange', 'A-'],
[313225, 'darkorange', 'A'],
[372750, 'darkorange', 'A+'],
[439375, 'tomato', 'S-'],
[513500, 'tomato', 'S'],
[595525, 'tomato', 'S+'],
[685850, 'darkviolet', 'Z-'],
[784875, 'darkviolet', 'Z'],
[893000, 'darkviolet', 'Z+'],
[1010625, 'gold', 'EX-'],
[1138150, 'gold', 'EX'],
[1275975, 'white', 'EX+'],
];
}
function getDexCall(int $dex) : string {
if($dex < 0){
throw new \InvalidArgumentException();
}
$color = null;
$name = null;
foreach(getDexLevelList() as $dexLevel => [$dexKey, $nextColor, $nextName]){
if($dex < $dexKey){
break;
}
$color = $nextColor;
$name = $nextName;
}
return "<font color='{$color}'>{$name}</font>";
}
function getDexLevel(int $dex) : int {
if($dex < 0){
return 0;
}
$retVal = 0;
foreach(getDexLevelList() as $dexLevel => [$dexKey, $nextColor, $nextName]){
if($dex < $dexKey){
break;
}
$retVal = $dexLevel;
}
return $retVal;
}
function getDexLog($dex1, $dex2) {
$ratio = (getDexLevel($dex1) - getDexLevel($dex2)) / 55 + 1;
return $ratio;
}
function getItemName(?string $item) : ?string {
if($item === null){
return '-';
}
$itemClass = buildItemClass($item);
return $itemClass->getName();
}
function isConsumable(?string $item) : bool{
if($item === null){
return false;
}
$itemClass = buildItemClass($item);
return $itemClass->isConsumable();
}
function getNPCColor(int $npc): ?string{
if ($npc == 1) {
return 'skyblue';
}
if ($npc == 4){
return 'deepskyblue';
}
if ($npc == 5){
return 'darkcyan';
}
if ($npc == 6){
return 'mediumaquamarine';
}
if ($npc > 1) {
return 'cyan';
}
return null;
}
function formatName(string $name, int $npc): string
{
$color = getNPCColor($npc);
if($color === null){
return $name;
}
return "<span style='color:{$color}'>$name</span>";
}
function ConvertLog(?string $str, $type=1) : string {
if(!$str){
return '';
}
//TODO: 이 함수는 없애야 한다. CSS로 대신하자
if($type > 0) {
$str = str_replace("<1>", "<font size=1>", $str);
$str = str_replace("<Y1>", "<font size=1 color=yellow>", $str);
$str = str_replace("<R>", "<font color=red>", $str);
$str = str_replace("<B>", "<font color=blue>", $str);
$str = str_replace("<G>", "<font color=green>", $str);
$str = str_replace("<M>", "<font color=magenta>", $str);
$str = str_replace("<C>", "<font color=cyan>", $str);
$str = str_replace("<L>", "<font color=limegreen>", $str);
$str = str_replace("<S>", "<font color=skyblue>", $str);
//$str = str_replace("<O>", "<font color=orange>", $str);
//$str = str_replace("<D>", "<font color=darkorange>", $str);
$str = str_replace("<O>", "<font color=orangered>", $str);
$str = str_replace("<D>", "<font color=orangered>", $str);
$str = str_replace("<Y>", "<font color=yellow>", $str);
$str = str_replace("<W>", "<font color=white>", $str);
$str = str_replace("</>", "</font>", $str);
} else {
$str = str_replace("<1>", "", $str);
$str = str_replace("<Y1>", "", $str);
$str = str_replace("<R>", "", $str);
$str = str_replace("<B>", "", $str);
$str = str_replace("<G>", "", $str);
$str = str_replace("<M>", "", $str);
$str = str_replace("<C>", "", $str);
$str = str_replace("<L>", "", $str);
$str = str_replace("<S>", "", $str);
$str = str_replace("<O>", "", $str);
$str = str_replace("<D>", "", $str);
$str = str_replace("<Y>", "", $str);
$str = str_replace("<W>", "", $str);
$str = str_replace("</>", "", $str);
}
return $str;
}
function newColor($color) : string {
switch($color) {
case "":
case "#330000":
case "#FF0000":
case "#800000":
case "#A0522D":
case "#FF6347":
case "#808000":
case "#008000":
case "#2E8B57":
case "#008080":
case "#6495ED":
case "#0000FF":
case "#000080":
case "#483D8B":
case "#7B68EE":
case "#800080":
case "#A9A9A9":
case "#000000":
$color = "#FFFFFF"; break;
default:
$color = "#000000"; break;
}
return $color;
}
function backColor($color) : string {
return newColor($color);
}
function getDomesticExpLevelBonus(int $expLevel):float{
return 1 + $expLevel / 500;
}