$classObj){ $cache[$classObj->getName()] = $className; } static::$domesticInv = $cache; if(!key_exists($type, $cache)){ throw new \InvalidArgumentException('올바르지 않은 특기명:'.$type); } return $cache[$type]; } public static function getWarClassByName(?string $type):string{ if($type === null || $type === '' || $type == 'None'){ return GameConst::$defaultSpecialWar; } if(static::$warInv){ if(!key_exists($type, static::$warInv)){ throw new \InvalidArgumentException('올바르지 않은 특기명:'.$type); } return static::$warInv[$type]; } $cache = []; foreach(static::getSpecialWarList(false) as $className=>$classObj){ $cache[$classObj->getName()] = $className; } if(!key_exists($type, $cache)){ throw new \InvalidArgumentException('올바르지 않은 특기명:'.$type); } static::$warInv = $cache; return $cache[$type]; } private static function calcCondGeneric(array $general) : int { $myCond = 0; $leadership = $general['leadership']??50; $strength = $general['strength']??50; $intel = $general['intel']??50; if($leadership > GameConst::$chiefStatMin){ $myCond |= self::STAT_LEADERSHIP; } if($strength >= $intel * 0.95 && $strength > GameConst::$chiefStatMin){ $myCond |= self::STAT_STRENGTH; } if($intel >= $strength * 0.95 && $intel > GameConst::$chiefStatMin){ $myCond |= self::STAT_INTEL; } if($myCond !== 0){ if($leadership < GameConst::$chiefStatMin){ $myCond |= self::STAT_NOT_LEADERSHIP; } if($strength < GameConst::$chiefStatMin){ $myCond |= self::STAT_NOT_STRENGTH; } if($intel < GameConst::$chiefStatMin){ $myCond |= self::STAT_NOT_INTEL; } } if($myCond === 0){ if ($leadership * 0.9 > $strength && $leadership * 0.9 > $intel) { $myCond |= self::STAT_LEADERSHIP; } else if($strength >= $intel){ $myCond |= self::STAT_STRENGTH; } else { $myCond |= self::STAT_INTEL; } } return $myCond; } private static function calcCondDexterity(RandUtil $rng, array $general) : int { $dex = [ static::ARMY_FOOTMAN => $general['dex1']??0, static::ARMY_ARCHER => $general['dex2']??0, static::ARMY_CAVALRY => $general['dex3']??0, static::ARMY_WIZARD => $general['dex4']??0, static::ARMY_SIEGE => $general['dex5']??0, ]; $dexSum = array_sum($dex); $dexBase = Util::round(sqrt($dexSum) / 4); if($rng->nextBool(0.8)){ return 0; } if($rng->nextRangeInt(0, 99) < $dexBase){ return 0; } if(!$dexSum){ return $rng->choice($dex); } return $rng->choice(array_keys($dex, max($dex))); } /** @return BaseSpecial[] */ public static function getSpecialDomesticList(bool $onlyAvailable=true):array{ $result = []; if(!$onlyAvailable){ $specialObj = buildGeneralSpecialDomesticClass(GameConst::$defaultSpecialDomestic); $result[GameConst::$defaultSpecialDomestic] = $specialObj; } foreach(GameConst::$availableSpecialDomestic as $specialID){ $specialObj = buildGeneralSpecialDomesticClass($specialID); $result[$specialID] = $specialObj; } if(!$onlyAvailable){ foreach(GameConst::$optionalSpecialDomestic as $specialID){ $specialObj = buildGeneralSpecialDomesticClass($specialID); $result[$specialID] = $specialObj; } } return $result; } /** @return BaseSpecial[] */ public static function getSpecialWarList(bool $onlyAvailable=true):array{ $result = []; if(!$onlyAvailable){ $specialObj = buildGeneralSpecialWarClass(GameConst::$defaultSpecialWar); $result[GameConst::$defaultSpecialWar] = $specialObj; } foreach(GameConst::$availableSpecialWar as $specialID){ $specialObj = buildGeneralSpecialWarClass($specialID); $result[$specialID] = $specialObj; } if(!$onlyAvailable){ foreach(GameConst::$optionalSpecialWar as $specialID){ $specialObj = buildGeneralSpecialWarClass($specialID); $result[$specialID] = $specialObj; } } return $result; } public static function pickSpecialDomestic(RandUtil $rng, array $general, array $prevSpecials=[]) : string{ $pAbs = []; $pRel = []; $id = null; $myCond = static::calcCondGeneric($general); foreach(static::getSpecialDomesticList() as $specialID=>$specialObj){ $conds = $specialObj::$type; $name = $specialObj->getName(); $weightType = $specialObj::$selectWeightType; $weight = $specialObj::$selectWeight; $valid = false; foreach($conds as $cond){ if($cond === ($cond & $myCond)){ $valid = true; break; } } if(!$valid){ continue; } if(in_array($specialID, $prevSpecials)){ continue; } if($weightType === static::WEIGHT_PERCENT){ $pAbs[$specialID] = $weight; } else{ $pRel[$specialID] = $weight; } } if($pAbs){ if($pRel){ $pAbs[0] = max(0, 100 - array_sum($pAbs)); } $id = $rng->choiceUsingWeight($pAbs); if($id){ return $id; } } if($pRel){ $id = $rng->choiceUsingWeight($pRel); } if($id){ return $id; } if($prevSpecials){ return static::pickSpecialDomestic($rng, $general, []); } throw new MustNotBeReachedException("{$general['name']}, {$myCond}"); } public static function pickSpecialWar(RandUtil $rng, array $general, array $prevSpecials=[]) : string{ $reqDex = []; $pAbs = []; $pRel = []; $id = null; $myCond = static::calcCondGeneric($general); $myCond |= static::calcCondDexterity($rng, $general); $myCond |= static::REQ_DEXTERITY; foreach(static::getSpecialWarList() as $specialID=>$specialObj){ $conds = $specialObj::$type; $name = $specialObj->getName(); $weightType = $specialObj::$selectWeightType; $weight = $specialObj::$selectWeight; $valid = false; foreach($conds as $cond){ if($cond === ($cond & $myCond)){ $valid = true; break; } } if(!$valid){ continue; } if(in_array($specialID, $prevSpecials)){ continue; } if($cond & self::REQ_DEXTERITY){ $reqDex[$specialID] = $weight; } else if($weightType === static::WEIGHT_PERCENT){ $pAbs[$specialID] = $weight; } else{ $pRel[$specialID] = $weight; } } if($reqDex){ return $rng->choiceUsingWeight($reqDex); } if($pAbs){ if($pRel){ $pAbs[0] = max(0, 100 - array_sum($pAbs)); } $id = $rng->choiceUsingWeight($pAbs); if($id){ return $id; } } if($pRel){ $id = $rng->choiceUsingWeight($pRel); } if($id){ return $id; } if($prevSpecials){ return static::pickSpecialWar($rng, $general, []); } throw new MustNotBeReachedException(); } }