id = $id; $this->name = $name; $this->armType = $armType; $this->attack = $attack; $this->defence = $defence; $this->speed = $speed; $this->avoid = $avoid; $this->magicCoef = $magicCoef; $this->cost = $cost; $this->rice = $rice; $this->reqConstraints = []; foreach($reqConstraints as $constraint){ $className = Util::getClassNameFromObj($constraint); $this->reqConstraints[$className] = $constraint; } $this->attackCoef = $attackCoef; $this->defenceCoef = $defenceCoef; $this->initSkillTrigger = $initSkillTrigger; $this->phaseSkillTrigger = $phaseSkillTrigger; $this->iActionList = []; foreach($iActionList ?? [] as $rawAction){ $action = buildActionCrewTypeClass($rawAction); if(!$action){ continue; } $this->iActionList[] = $action; } } public function getInfo(): string { return join("\n
", $this->info); } public function getShortName(): string { return StringUtil::subStringForWidth($this->name, 0, 4); } public function riceWithTech(int $tech, int $crew = 100): float { return $this->rice * getTechCost($tech) * $crew / 100; } public function costWithTech(int $tech, int $crew = 100): float { return $this->cost * getTechCost($tech) * $crew / 100; } public function getAttackCoef(GameUnitDetail $opposeCrewType): float { $opposeCrewTypeID = $opposeCrewType->id; if (key_exists($opposeCrewTypeID, $this->attackCoef)) { return $this->attackCoef[$opposeCrewTypeID]; } $opposeArmType = $opposeCrewType->armType; return $this->attackCoef[$opposeArmType] ?? 1; } public function getDefenceCoef(GameUnitDetail $opposeCrewType): float { $opposeCrewTypeID = $opposeCrewType->id; if (key_exists($opposeCrewTypeID, $this->defenceCoef)) { return $this->defenceCoef[$opposeCrewTypeID]; } $opposeArmType = $opposeCrewType->armType; return $this->defenceCoef[$opposeArmType] ?? 1; } public function getComputedAttack(General $general, int $tech) { if ($this->armType == GameUnitConst::T_WIZARD) { $ratio = $general->getIntel(true, true, true) * 2 - 40; } else if ($this->armType == GameUnitConst::T_SIEGE) { $ratio = $general->getLeadership(true, true, true) * 2 - 40; } else if ($this->armType == GameUnitConst::T_MISC) { $ratio = $general->getIntel(true, true, true) + $general->getLeadership(true, true, true) + $general->getStrength(true, true, true); $ratio = $ratio * 2 / 3 - 40; } else { $ratio = $general->getStrength(true, true, true) * 2 - 40; } if ($ratio < 10) { $ratio = 10; } if ($ratio > 100) { $ratio = 50 + $ratio / 2; } $att = $this->attack + getTechAbil($tech); return $att * $ratio / 100; } public function getComputedDefence(General $general, int $tech) { $def = $this->defence + getTechAbil($tech); $crew = ($general->getVar('crew') / (7000 / 30)) + 70; return $def * $crew / 100; } public function getCriticalRatio(General $general) { if ($this->armType == GameUnitConst::T_CASTLE) { //성벽은 필살을 사용하지 않는다. return 0; } // 무장 무력 : 65 5%, 70 10%, 75 15%, 80 20% // 지장 지력 : 65 5%, 70 8%, 75 10%, 80 13% //충차장 통솔: 65 5%, 70 8%, 75 10%, 80 13% if ($this->armType == GameUnitConst::T_WIZARD) { $mainstat = $general->getIntel(false, true, true, false); $coef = 0.4; } else if ($this->armType == GameUnitConst::T_SIEGE) { $mainstat = $general->getLeadership(false, true, true, false); $coef = 0.4; } else if ($this->armType == GameUnitConst::T_MISC) { $mainstat = $general->getIntel(false, true, true, false) + $general->getLeadership(false, true, true, false) + $general->getStrength(false, true, true, false); $mainstat /= 3; $coef = 0.4; } else { $mainstat = $general->getStrength(false, true, true, false); $coef = 0.5; } $ratio = Util::valueFit($mainstat - 65, 0); $ratio *= $coef; return min(50, $ratio) / 100; } public function pickScore($tech) { $defaultWar = GameConst::$armperphase + $this->attack + $this->defence + getTechAbil($tech) * 2; $defaultWar *= 1 + $this->speed / 2; $defaultWar /= Util::valueFit(1 - $this->avoid / 100, 0.1); $defaultWar *= 1 + $this->magicCoef / 2; return $defaultWar; } public function isValid(General $general, $ownCities, $ownRegions, $relativeYear, $tech, $nationAux = []) { //음수 없음 $relativeYear = max(0, $relativeYear); foreach($this->reqConstraints as $constraint){ if(!$constraint->test($general, $ownCities, $ownRegions, $relativeYear, $tech, $nationAux)){ return false; } } return true; } //iAction public function getBattleInitSkillTriggerList(WarUnit $unit): ?WarUnitTriggerCaller { if (!$this->initSkillTrigger) { return null; } $triggerList = []; foreach ($this->initSkillTrigger as $triggerArgs) { if (is_string($triggerArgs)) { $typeName = $triggerArgs; $triggerList[] = buildWarUnitTriggerClass($typeName, $unit); } else { $typeName = $triggerArgs[0]; //WarUnit 다음 인자는 $raiseType이며, 0이어야할 것이다 $triggerArgs[0] = 0; $triggerList[] = buildWarUnitTriggerClass($typeName, $unit, $triggerArgs); } } return new WarUnitTriggerCaller(...$triggerList); } public function getBattlePhaseSkillTriggerList(WarUnit $unit): ?WarUnitTriggerCaller { if (!$this->phaseSkillTrigger) { return null; } $triggerList = []; foreach ($this->phaseSkillTrigger as $triggerArgs) { if (is_string($triggerArgs)) { $typeName = $triggerArgs; $triggerList[] = buildWarUnitTriggerClass($typeName, $unit); } else { $typeName = $triggerArgs[0]; //WarUnit 다음 인자는 $raiseType이며, 0이어야할 것이다 $triggerArgs[0] = 0; $triggerList[] = buildWarUnitTriggerClass($typeName, $unit, $triggerArgs); } } return new WarUnitTriggerCaller(...$triggerList); } public function onCalcDomestic(string $turnType, string $varType, float $value, $aux = null): float { if (!$this->iActionList) { return $value; } foreach ($this->iActionList as $iAction) { $value = $iAction->onCalcDomestic($turnType, $varType, $value, $aux); } return $value; } public function onCalcStat(General $general, string $statName, $value, $aux = null) { if (!$this->iActionList) { return $value; } foreach ($this->iActionList as $iAction) { $value = $iAction->onCalcStat($general, $statName, $value, $aux); } return $value; } public function onCalcOpposeStat(General $general, string $statName, $value, $aux = null) { if (!$this->iActionList) { return $value; } foreach ($this->iActionList as $iAction) { $value = $iAction->onCalcOpposeStat($general, $statName, $value, $aux); } return $value; } public function onCalcStrategic(string $turnType, string $varType, $value) { if (!$this->iActionList) { return $value; } foreach ($this->iActionList as $iAction) { $value = $iAction->onCalcStrategic($turnType, $varType, $value); } return $value; } public function onCalcNationalIncome(string $type, $amount) { if (!$this->iActionList) { return $amount; } foreach ($this->iActionList as $iAction) { $amount = $iAction->onCalcNationalIncome($type, $amount); } return $amount; } public function getWarPowerMultiplier(WarUnit $unit): array { if (!$this->iActionList) { return [1, 1]; } $attack = 1; $defence = 1; foreach ($this->iActionList as $iAction) { $attack *= $iAction->getWarPowerMultiplier($unit)[0]; $defence *= $iAction->getWarPowerMultiplier($unit)[1]; } return [$attack, $defence]; } public function onArbitraryAction(General $general, RandUtil $rng, string $actionType, ?string $phase = null, ?array $aux = null): null|array { if (!$this->iActionList) { return $aux; } foreach ($this->iActionList as $iAction) { $aux = $iAction->onArbitraryAction($general, $rng, $actionType, $phase, $aux); } return $aux; } }