From fb8d3a038d6079ef0ca081b257d2f6a7c847bce2 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 18 Aug 2018 02:26:27 +0900 Subject: [PATCH] =?UTF-8?q?=EC=83=88=20=EC=A0=84=ED=88=AC=20=EC=97=94?= =?UTF-8?q?=EC=A7=84=20=EC=A4=91=EA=B0=84=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/process_war.ng.php | 152 +++++++++++++++++++++++++---------- hwe/sammo/WarUnit.php | 75 +++++++++++++++-- hwe/sammo/WarUnitCity.php | 82 ------------------- hwe/sammo/WarUnitGeneral.php | 152 ++++++++++++++++++++++++++++++++--- 4 files changed, 321 insertions(+), 140 deletions(-) diff --git a/hwe/process_war.ng.php b/hwe/process_war.ng.php index 9d1484ab..f6cb88bf 100644 --- a/hwe/process_war.ng.php +++ b/hwe/process_war.ng.php @@ -38,73 +38,132 @@ function processWar_NG( $logger->pushGeneralActionLog("{$city->name}{$josaRo} 진격합니다. <1>$date"); for($currPhase = 0; $currPhase <= $maxPhase; $currPhase+=1){ - if($defender !== null && $defender->getPhase() == 0){ + + if($defender === null){ + $defender = $city; + + if($rawDefenderNation['rice'] <= 0){ + $conquerCity = true; + break; + } + } + + if($defender->getPhase() == 0){ $defender->setPrePhase($currPhase); $attacker->addTrain(1); $defender->addTrain(1); - $josaWa = JosaUtil::pick($attacker->getCrewType()->name, '와'); - $josaYi = JosaUtil::pick($defender->getCrewType()->name, '이'); - $logger->pushGlobalActionLog("{$attacker->getName()}의 {$attacker->getCrewType()->name}{$josaWa} {$defender->getName()}의 {$defender->getCrewType()->name}{$josaYi} 대결합니다."); - $josaUl = JosaUtil::pick($defender->getCrewType()->name, '을'); - $josaRo = JosaUtil::pick($attacker->getCrewType()->name, '로'); - $attacker->getLogger()->pushGeneralActionLog("{$attacker->getCrewType()->name}{$josaRo} {$defender->name}의 {$defender->getCrewType()->name}{$josaUl} 공격합니다."); - $defender->getLogger()->pushGeneralActionLog("{$defender->getCrewType()->name}{$josaRo} {$attacker->name}의 {$attacker->getCrewType()->name}{$josaUl} 수비합니다."); + if($defender instanceof WarUnitGeneral){ + $josaWa = JosaUtil::pick($attacker->getCrewType()->name, '와'); + $josaYi = JosaUtil::pick($defender->getCrewType()->name, '이'); + $logger->pushGlobalActionLog("{$attacker->getName()}의 {$attacker->getCrewType()->name}{$josaWa} {$defender->getName()}의 {$defender->getCrewType()->name}{$josaYi} 대결합니다."); + $josaUl = JosaUtil::pick($defender->getCrewType()->name, '을'); + $josaRo = JosaUtil::pick($attacker->getCrewType()->name, '로'); + $attacker->getLogger()->pushGeneralActionLog("{$attacker->getCrewType()->name}{$josaRo} {$defender->name}의 {$defender->getCrewType()->name}{$josaUl} 공격합니다."); + $defender->getLogger()->pushGeneralActionLog("{$defender->getCrewType()->name}{$josaRo} {$attacker->name}의 {$attacker->getCrewType()->name}{$josaUl} 수비합니다."); + } + else{ + $josaYi = JosaUtil::pick($attacker->getName(), '이'); + $josaRo = JosaUtil::pick($attacker->getCrewType()->name, '로'); + $logger->pushGlobalActionLog("{$attacker->getName()}{$josaYi} {$attacker->getCrewType()->name}{$josaRo} 성벽을 공격합니다."); + $logger->pushGeneralActionLog("●{$generalCrewType->name}{$josaRo} 성벽을 공격합니다.", ActionLogger::PLAIN); + } $defender->useBattleInitItem(); $attacker->setOppose($defender); $defender->setOppose($attacker); - $attacker->useActiveItem(); - $defender->useActiveItem(); - //TODO: 수극 류 아이템 사용 - } - else if($defender === null && $rawDefenderNation['rice'] > 0){ - $defender = $city; - - $defender->setPrePhase($currPhase); + $attacker->checkBattleBeginSkill(); + $defender->checkBattleBeginSkill(); - $josaYi = JosaUtil::pick($attacker->getName(), '이'); - $josaRo = JosaUtil::pick($attacker->getCrewType()->name, '로'); - $logger->pushGlobalActionLog("{$attacker->getName()}{$josaYi} {$attacker->getCrewType()->name}{$josaRo} 성벽을 공격합니다."); - $logger->pushGeneralActionLog("●{$generalCrewType->name}{$josaRo} 성벽을 공격합니다.", ActionLogger::PLAIN); + $attacker->checkBattleBeginItem(); + $defender->checkBattleBeginItem(); - $defender->useBattleInitItem(); - - $attacker->setOppose($defender); - $defender->setOppose($attacker); - } - else if($defender === null){ - $defender = $city; - $conquerCity = true; - //TODO: 병량 패퇴를 여기에 넣어야 하는가? - break; + $attacker->applyBattleBeginSkillAndItem(); + $defender->applyBattleBeginSkillAndItem(); } $attacker->computeWarPower(); $defender->computeWarPower(); - - //TODO: 1합씩 공격(마법도 여기에서) + $attacker->checkActiveSkill(); + $defender->checkActiveSkill(); - //TODO: 쌀 소모 반영 + $attacker->checkActiveItem(); + $defender->checkActiveItem(); + + $attacker->applyActiveSkillAndItem(); + $defender->applyActiveSkillAndItem(); + + $killedDefender = $attacker->tryAttackInPhase(); + $killedAttacker = $defender->tryAttackInPhase(); + //NOTE: 쌀 소모는 tryAttackInPhase 내에서 반영 + + $attackerHP = $attacker->getHP(); + $defenderHP = $defender->getHP(); + + if($killedAttacker > $attackerHP || $killedDefender > $defenderHP){ + $killedAttackerRatio = $attackerHP / $killedAttacker; + $killedDefenderRatio = $defenderHP / $killedDefender; + + if($killedDefenderRatio < $killedAttackerRatio){ + //수비자가 더 병력 부족 + $killedAttacker *= $killedDefenderRatio; + $killedDefender = $defenderHP; + break; + } + else{ + //공격자가 더 병력 부족 + $killedDefender *= $killedAttackerRatio; + $killedAttacker = $attackerHP; + break; + } + } //TODO: 전투 로그 기록(여기서??) + $attacker->decreaseHP(ceil($killedAttacker)); + $defender->decreaseHP(ceil($killedDefender)); + $attacker->addPhase(); - if($defender->continueWar($noRice)){ - $defender->addPhase(); + $defender->addPhase(); + + //TODO: 기술로그 반영등은 이전 코드와 달리 동적으로 매 페이즈마다 추가 계산 + + if(!$attacker->continueWar($noRice)){ + //TODO: 퇴각해야함 + $attacker->addLose(); + $defender->addWin(); + + $attacker->tryWound(); + $defender->tryWound(); + + $josaYi = JosaUtil::pick($attacker->getCrewType()->name, '이'); + $logger->pushGlobalActionLog("{$attacker->getName()}의 {$attacker->getCrewType()->name}{$josaYi} 퇴각했습니다."); + $attacker->getLogger()->pushGeneralActionLog("퇴각했습니다.", ActionLogger::PLAIN); + $defender->getLogger()->pushGeneralActionLog("{$attacker->getName()}의 {$attacker->getCrewType()->name}{$josaYi} 퇴각했습니다.", ActionLogger::PLAIN); + + break; } - else{ + + if(!$defender->continueWar($noRice)){ + $attacker->addWin(); + $defender->addLose(); + + $attacker->tryWound(); + $defender->tryWound(); + if($defender === $city){ $conquerCity = true; break; } $josaYi = JosaUtil::pick($defender->getCrewType()->name, '이'); - $logger->pushGeneralActionLog("{$defender->getName()}의 {$defender->getCrewType()->name}{$josaYi} 퇴각했습니다."); + $logger->pushGlobalActionLog("{$defender->getName()}의 {$defender->getCrewType()->name}{$josaYi} 퇴각했습니다."); + $attacker->getLogger()->pushGeneralActionLog("{$defender->getName()}의 {$defender->getCrewType()->name}{$josaYi} 퇴각했습니다.", ActionLogger::PLAIN); + $defender->getLogger()->pushGeneralActionLog("퇴각했습니다.", ActionLogger::PLAIN); $defender = ($getNextDefender)($defender); if($defender === null){ @@ -112,22 +171,33 @@ function processWar_NG( } if(!($defender instanceof WarUnitGeneral)){ throw new \RuntimeException('다음 수비자를 받아오는데 실패'); - } - + } } + + } //TODO: 전투 종료 - if($conquerCity){ - //TODO: 도시 정복 처리 + if (!$conquerCity) { + } + + $conquerNation = false; + //TODO: 도시 정복 처리 + //TODO: 패퇴면 메시지 별도 + if($rawDefenderNation['rice'] <= 0){ } //TODO: 공격자 경험치? (여기서?) //TODO: DB 처리를 위한 반영 + + if(!$conquerNation){ + } + + //TODO:국가 정복 처리 } diff --git a/hwe/sammo/WarUnit.php b/hwe/sammo/WarUnit.php index ef9fb1ee..a5b3abb3 100644 --- a/hwe/sammo/WarUnit.php +++ b/hwe/sammo/WarUnit.php @@ -22,6 +22,7 @@ class WarUnit{ protected $oppose; protected $warPower; + protected $warPowerMultiply = 1.0; private function __construct(){ } @@ -46,7 +47,7 @@ class WarUnit{ return 'EMPTY'; } - function getCrewType():GameUnitConst{ + function getCrewType():GameUnitDetail{ return $this->crewType; } @@ -67,7 +68,7 @@ class WarUnit{ } function getMaxPhase():int{ - return 1; + return $this->getCrewType()->speed; } function setPrePhase(int $phase){ @@ -83,6 +84,22 @@ class WarUnit{ } + function getWarPower(){ + return $this->warPower * $this->warPowerMultiply; + } + + function getRawWarPower(){ + return $this->warPower; + } + + function getWarPowerMultiply(){ + return $this->warPowerMultiply; + } + + function setWarPowerMultiply($multiply = 1.0){ + $this->warPowerMultiply = $multiply; + } + function computeWarPower(){ $oppose = $this->oppose; @@ -90,6 +107,8 @@ class WarUnit{ $opDef = $oppose->getCrewType()->getComputedDefence($oppose->getRaw(), $oppose->getRawNation()['tech']); // 감소할 병사 수 $warPower = GameConst::$armperphase + $myAtt - $opDef; + $opposeWarPowerMultiply = 1.0; + if($warPower <= 0){ //FIXME: 0으로 잡을때 90~100이면, 1은 너무 억울하지 않나? $warPower = rand(90, 100); @@ -110,14 +129,14 @@ class WarUnit{ $genDexAtt = getGenDex($this->getRaw(), $this->getCrewType()->id); $oppDexDef = getGenDex($oppose->getRaw(), $this->getCrewType()->id); $warPower *= getDexLog($genDexAtt, $oppDexDef); + $warPower *= $this->getCrewType()->getAttackCoef($oppose->getCrewType()); - //FIXME : 이대로면 서로의 '공격력'만 반영됨 getDefenceCoef는 어따씀? + $opposeWarPowerMultiply *= $this->getCrewType()->getDefenceCoef($oppose->getCrewType()); - //TODO:관직 보정 (상속받은 쪽에서..?) - //TODO:레벨 보정 (상속받은 쪽에서..?) - //TODO:특기 보정 (상속받은 쪽에서..?) $this->warPower = $warPower; - return $warPower; + $this->oppose->setWarPowerMultiply($opposeWarPowerMultiply); + + return [$warPower, $opposeWarPowerMultiply]; } function addTrain(int $train){ @@ -138,6 +157,14 @@ class WarUnit{ return 100; } + function addWin(){ + //TODO: 1승 로그 추가 + } + + function addLose(){ + //TODO: 1패 로그 추가 + } + function getCharacter(){ //TODO: 나머지에 구현 return 0; @@ -147,14 +174,46 @@ class WarUnit{ return false; } - function useActiveItem():bool{ + function checkBattleBeginSkill():bool{ return false; } + function checkBattleBeginItem():bool{ + return false; + } + + function applyBattleBeginSkillAndItem(){ + return false; + } + + function checkActiveSkill():bool{ + return false; + } + + function checkActiveItem():bool{ + return false; + } + + function applyActiveSkillAndItem():bool{ + return false; + } + + function getHP():int{ + return 1; + } + function decreaseHP(int $damage):int{ return false; } + function tryAttackInPhase():int{ + return 0; + } + + function tryWound():bool{ + return false; + } + function continueWar(&$noRice):bool{ //전투가 가능하면 true $noRice = false; diff --git a/hwe/sammo/WarUnitCity.php b/hwe/sammo/WarUnitCity.php index 82809eca..50896c40 100644 --- a/hwe/sammo/WarUnitCity.php +++ b/hwe/sammo/WarUnitCity.php @@ -40,88 +40,6 @@ class WarUnitCity extends WarUnit{ return $this->raw['name']; } - function getCrewType():GameUnitConst{ - return $this->crewType; - } - - function getLogger():ActionLogger{ - return $this->logger; - } - - function getSpecialDomestic():int{ - return $this->raw['special']; - } - - function getSpecialWar():int{ - return $this->raw['special2']; - } - - function getItem():int{ - return $this->raw['item']; - } - - function getMaxPhase():int{ - $phase = $this->getCrewType()->speed; - if($this->getSpecialWar() == 60){ - $phase += 1; - } - return $phase; - } - - function useBattleInitItem():bool{ - $item = $this->getItem(); - - if($item == 0){ - return false; - } - - $itemActivated = false; - $itemConsumed = false; - $itemName = getItemName($item); - - if($item == 3){ - //탁주 사용 - $this->genAtmos += 3; - $itemActivated = true; - $itemConsumed = true; - } - else if($item >= 14 && $item <= 16){ - //의적주, 두강주, 보령압주 사용 - $this->genAtmos += 5; - $itemActivated = true; - } - else if($item >= 19 && $item <= 20){ - //춘화첩, 초선화 사용 - $this->genAtmos += 7; - $itemActivated = true; - } - else if($item == 4){ - //청주 사용 - $this->genTrain += 3; - $itemActivated = true; - $itemConsumed = true; - } - else if($item >= 12 && $item <= 13){ - //과실주, 이강주 사용 - $this->genTrain += 5; - $itemActivated = true; - } - else if($item >= 18 && $item <= 18){ - //철벽서, 단결도 사용 - $this->genTrain += 7; - $itemActivated = true; - } - - if($itemConsumed){ - $this->raw['item'] = 0; - $this->updatedVar['item'] = true; - $josaUl = JosaUtil::pick($itemName, '을'); - $this->getLogger()->generalActionLog("{$itemName}{$josaUl} 사용!"); - } - - return $itemActivated; - } - function continueWar(&$noRice):bool{ //전투가 가능하면 true $noRice = false; diff --git a/hwe/sammo/WarUnitGeneral.php b/hwe/sammo/WarUnitGeneral.php index 0d49fab4..934518aa 100644 --- a/hwe/sammo/WarUnitGeneral.php +++ b/hwe/sammo/WarUnitGeneral.php @@ -20,6 +20,8 @@ class WarUnitGeneral extends WarUnit{ protected $genAtmosBonus = 0; protected $genTrainBonus = 0; + protected $sniped = false; + function __construct($raw, $rawCity, $rawNation, $isAttacker, $year, $month){ setLeadershipBonus($raw, $rawNation['level']); @@ -60,14 +62,6 @@ class WarUnitGeneral extends WarUnit{ return $this->raw['name']; } - function getCrewType():GameUnitDetail{ - return $this->crewType; - } - - function getLogger():ActionLogger{ - return $this->logger; - } - function getSpecialDomestic():int{ return $this->raw['special']; } @@ -98,7 +92,85 @@ class WarUnitGeneral extends WarUnit{ $this->updatedVar['atmos'] = true; } + protected function getWarPowerMultiplyBySpecialWar():array{ + //TODO: 장기적으로 if문이 아니라 객체를 이용하여 처리해야함 + $myWarPowerMultiply = 1.0; + $opposeWarPowerMultiply = 1.0; + $specialWar = $this->getSpecialWar(); + + if($specialWar == 52){ + $myWarPowerMultiply *= 1.20; + } + else if($specialWar == 60){ + $myWarPowerMultiply *= 1.10; + } + else if($specialWar == 61){ + $myWarPowerMultiply *= 1.10; + } + else if($specialWar == 50){ + $opposeWarPowerMultiply *= 0.9; + } + else if($specialWar == 62){ + $opposeWarPowerMultiply *= 0.9; + } + else if($specialWar == 75){ + $opposeCrewType = $this->oppose->getCrewType(); + if($opposeCrewType->reqCities || $opposeCrewType->reqRegions){ + $myWarPowerMultiply *= 1.1; + $opposeWarPowerMultiply *= 0.9; + } + } + + + return [$myWarPowerMultiply, $opposeWarPowerMultiply]; + } + + function computeWarPower(){ + [$warPower,$opposeWarPowerMultiply] = parent::computeWarPower(); + + $genLevel = $this->raw['level']; + + if($this->isAttacker){ + if($genLevel == 12){ + $warPower *= 1.10; + } + else if($genLevel == 11 | $genLevel == 10 || $genLevel == 8 || $genLevel == 6){ + $warPower *= 1.05; + } + } + else{ + if($genLevel == 12){ + $opposeWarPowerMultiply *= 0.90; + } + else if($genLevel == 11 || $genLevel == 9 || $genLevel == 7 || $genLevel == 5){ + $opposeWarPowerMultiply *= 0.95; + } + else if($genLevel == 4 && $this->raw['no'] == $this->rawCity['gen1']){ + $opposeWarPowerMultiply *= 0.95; + } + else if($genLevel == 3 && $this->raw['no'] == $this->rawCity['gen2']){ + $opposeWarPowerMultiply *= 0.95; + } + else if($genLevel == 2 && $this->raw['no'] == $this->rawCity['gen3']){ + $opposeWarPowerMultiply *= 0.95; + } + } + + $expLevel = $this->raw['explevel']; + $warPower /= max(0.01, 1 - $expLevel / 300); + $opposeWarPowerMultiply *= max(0.01, 1 - $expLevel / 300); + + [$specialMyWarPowerMultiply, $specialOpposeWarPowerMultiply] = $this->getWarPowerMultiplyBySpecialWar(); + $warPower *= $specialMyWarPowerMultiply; + $opposeWarPowerMultiply *= $specialOpposeWarPowerMultiply; + + $this->warPower = $warPower; + $this->oppose->setWarPowerMultiply($opposeWarPowerMultiply); + return [$warPower,$opposeWarPowerMultiply]; + } + + ///전투 개시 시에 작동하여 1회에만 작동하는 아이템 function useBattleInitItem():bool{ $item = $this->getItem(); @@ -147,12 +219,74 @@ class WarUnitGeneral extends WarUnit{ $this->raw['item'] = 0; $this->updatedVar['item'] = true; $josaUl = JosaUtil::pick($itemName, '을'); - $this->getLogger()->generalActionLog("{$itemName}{$josaUl} 사용!"); + $this->getLogger()->pushGeneralActionLog("{$itemName}{$josaUl} 사용!", ActionLogger::PLAIN); } return $itemActivated; } + ///전투 개시 시에 작동하여 매 장수마다 작동하는 스킬 + function checkBattleBeginSkill():bool{ + $skillResult = false; + if (!$this->sniped && $this->oppose instanceof WarUnitGeneral) { + if($this->raw['special2'] == 70 && Util::randBool(1/3)){ + $snipe = true; + } + + if($snipe){ + $this->sniped = true; + $skillResult = true; + } + } + return $skillResult; + } + + ///전투 개시 시에 작동하여 매 장수마다 작동하는 아이템 + function checkBattleBeginItem():bool{ + $item = $this->getItem(); + if(!$item){ + return false; + } + + $itemActivated = false; + $itemConsumed = false; + $itemName = getItemName($item); + + if($item == 2){ + if(!$this->sniped && $this->oppose instanceof WarUnitGeneral && Util::randBool(1/5)){ + $itemActivated = true; + $itemConsumed = true; + $this->sniped = true; + } + } + + if($itemConsumed){ + $this->raw['item'] = 0; + $this->updatedVar['item'] = true; + $josaUl = JosaUtil::pick($itemName, '을'); + $this->getLogger()->pushGeneralActionLog("{$itemName}{$josaUl} 사용!", ActionLogger::PLAIN); + } + + return $itemActivated; + } + + function tryWound():bool{ + if(Util::randBool(0.95)){ + return false; + } + + $wound = max(80, $this->raw['injury'] + rand(10, 80)); + if($wound < $this->raw['injury']){ + return false; + } + + $this->raw['injury'] = $wound; + $this->updatedVar['injury'] = true; + $this->getLogger()->pushGeneralActionLog("전투중 부상당했다!", ActionLogger::PLAIN); + + return true; + } + function continueWar(&$noRice):bool{ if($this->raw['crew'] <= 0){ $noRice = false;