diff --git a/hwe/templates/commandButton.php b/hwe/templates/commandButton.php index 7a4f00ef..e2306d8c 100644 --- a/hwe/templates/commandButton.php +++ b/hwe/templates/commandButton.php @@ -7,7 +7,7 @@ - + diff --git a/hwe/ts/NPCControl.vue b/hwe/ts/NPCControl.vue new file mode 100644 index 00000000..8b30684b --- /dev/null +++ b/hwe/ts/NPCControl.vue @@ -0,0 +1,636 @@ + + diff --git a/hwe/ts/defs.ts b/hwe/ts/defs.ts index 5f3310f3..3cec85c7 100644 --- a/hwe/ts/defs.ts +++ b/hwe/ts/defs.ts @@ -66,4 +66,69 @@ export type NationStaticItem = { capital: number, gennum: number, power: number, +} + +export type NPCGeneralActions = + 'NPC사망대비' | + '귀환' | + '금쌀구매' | + '출병' | + '긴급내정' | + '전투준비' | + '전방워프' | + //'NPC증여'| + 'NPC헌납' | + '징병' | + '후방워프' | + '전쟁내정' | + '소집해제' | + '일반내정' | + '내정워프'; + +export type NPCChiefActions = + '불가침제의' | + '선전포고' | + '천도' | + '유저장긴급포상' | + '부대전방발령' | + '유저장구출발령' | + '유저장후방발령' | + '부대유저장후방발령' | + '유저장전방발령' | + '유저장포상' | + //'유저장몰수'| + '부대구출발령' | + '부대후방발령' | + 'NPC긴급포상' | + 'NPC구출발령' | + 'NPC후방발령' | + 'NPC포상' | + 'NPC전방발령' | + '유저장내정발령' | + 'NPC내정발령' | + 'NPC몰수'; + +export type NationPolicy = { + reqNationGold: number, + reqNationRice: number, + CombatForce: Record, + SupportForce: number[], + DevelopForce: number[], + reqHumanWarUrgentGold: number, + reqHumanWarUrgentRice: number, + reqHumanWarRecommandGold: number, + reqHumanWarRecommandRice: number, + reqHumanDevelGold: number, + reqHumanDevelRice: number, + reqNPCWarGold: number, + reqNPCWarRice: number, + reqNPCDevelGold: number, + reqNPCDevelRice: number, + minimumResourceActionAmount: number, + minNPCWarLeadership: number, + minWarCrew: number, + allowNpcAttackCity: true, + minNPCRecruitCityPopulation: number, + safeRecruitCityPopulationRatio: number, + properWarTrainAtmos: number, } \ No newline at end of file diff --git a/hwe/ts/helpTexts.ts b/hwe/ts/helpTexts.ts new file mode 100644 index 00000000..eb025dc4 --- /dev/null +++ b/hwe/ts/helpTexts.ts @@ -0,0 +1,71 @@ +import { template } from "lodash"; +import { NationPolicy, NPCChiefActions, NPCGeneralActions } from "./defs"; + +export const NPCPriorityBtnHelpMessage: { + [v in NPCChiefActions | NPCGeneralActions]: string; +} & + Record = { + 불가침제의: + "군주가 NPC이고, 타국에서 원조를 받았을 때,
세입(금/쌀) 대비 원조량에 따라 불가침제의를 합니다.", + 선전포고: + "군주가 NPC이고, 전쟁중이 아닐 때,
주변국중 하나를 골라 선포합니다.

선포 시점은 다음을 참고합니다.
- 인구율
- 도시내정률
- NPC전투장권장 금 충족률
- NPC전투장권장 쌀 충족률

국력이 낮은 국가를 조금 더 선호합니다.", + 천도: "인구가 많은 곳을 찾아 천도를 시도합니다.
영토의 가운데를 선호합니다.

도시 인구가 충분하다면, 굳이 천도하지는 않습니다.", + 유저장긴급포상: + "금/쌀이 부족한 유저전투장에게 긴급하게 포상합니다.
국고가 권장량보다 적어지더라도 시도합니다.", + 부대전방발령: + "(작동하지 않음)
전투 부대를 접경으로 발령합니다.
수도->시작점->도착점 경로를 따릅니다.", + 유저장구출발령: + "아군 영토에 있지 않은 유저장을 아군 영토로 발령합니다.
곧 집합하는 부대에 탑승한 경우는 제외합니다.", + 유저장후방발령: + "유저전투장 중에
- 병력이 충분하지 않고,
- 도시의 인구가 제자리 징병할 수 있을 정도로 충분하지 않고,
- 부대에 탑승하지 않았다면,
인구가 충분한 후방도시로 발령합니다.", + 부대유저장후방발령: + "접경에 위치한 부대에 탑승한 유저전투장 중에,
- 병력이 충분하지 않고,
- 첫 턴이 징병턴이며,
- 부대장 집합 턴 사이라면,
인구가 충분한 후방도시로 발령합니다.

부대장의 위치와 유저장의 위치가 다르다면 발령하지 않습니다.", + 유저장전방발령: + "후방에 있는 유저장이
- 병력을 가지고 있으며,
- 곧 훈련/사기진작이 완료될 것 같으면,
전방으로 발령합니다.

도시 관직이 많이 임명된 도시를 선호합니다.", + 유저장포상: + "금/쌀이 부족한 유저장에게 포상합니다.
유저전투장과 유저내정장은 각각 기준을 따릅니다.
국고 권장량을 가급적 지킵니다.", + 부대후방발령: + "(작동하지 않음)
후방 부대가 위치한 도시의 인구가 충분하지 않을 경우,
인구가 충분한 도시로 발령합니다.", + 부대구출발령: + "전투 부대, 후방 부대가 아닌 부대가 아군 영토에 있지 않을 때,
전방 도시 중 하나를 골라 발령합니다.", + NPC긴급포상: + "금/쌀이 부족한 NPC전투장에게 긴급하게 포상합니다.
국고가 권장량보다 '약간' 적어지더라도 시도합니다.", + NPC구출발령: "아군 영토에 있지 않은 NPC장을 아군 영토로 발령합니다.", + NPC후방발령: + "NPC전투장 중에
- 병력이 충분하지 않고,
- 도시의 인구가 제자리 징병할 수 있을 정도로 충분하지 않고,
- 부대에 탑승하지 않았다면,
인구가 충분한 후방도시로 발령합니다.", + NPC포상: + "금/쌀이 부족한 유저장에게 포상합니다.
NPC전투장과 NPC내정장은 각각 기준을 따릅니다.
국고 권장량을 가급적 지킵니다.", + NPC전방발령: + "후방에 있는 유저장이
- 병력을 가지고 있으며,
- 곧 훈련/사기진작이 완료될 것 같으면,
전방으로 발령합니다.

도시 관직이 많이 임명된 도시를 선호합니다.", + 유저장내정발령: + "내정중인 유저장이 위치한 도시의 내정률이 95% 이상이면
개발되지 않은 도시로 발령합니다.", + NPC내정발령: + "내정중인 NPC장이 위치한 도시의 내정률이 95% 이상이면
개발되지 않은 도시로 발령합니다.", + NPC몰수: + "국고가 부족하다면 NPC에게서 몰수합니다. 내정NPC장은 국고가 부족하지 않아도 몰수합니다.", + + NPC사망대비: + "NPC의 사망까지 5턴 이내인 경우, 헌납합니다.
헌납할 금쌀이 없다면 물자조달을 수행합니다.", + 귀환: "아국 도시에 있지 않다면 귀환합니다.", + 금쌀구매: + "전쟁 중에 금쌀의 비율이 크게 차이난다면 금쌀을 거래하여 비슷하게 맞춥니다.
금쌀 비율이 적절하는지 판단하는데 살상률을 포함합니다.
NPC는 상인이 없어도 금쌀을 구매할 수 있습니다.

또는 금쌀 한쪽이 지나치게 적은 경우에는 내정 중에도 금쌀을 거래합니다.", + 출병: "충분한 병력과 충분한 훈련/사기를 가지고 있는 경우 출병합니다.
접경이 여럿인 경우 무작위로 선택합니다.

타국과 전쟁중인 경우 공백지로는 출병하지 않습니다.", + 긴급내정: + "전쟁중에 민심이 70 미만이거나,
인구가 제자리 징병이 가능하지 않을 정도로 적을 경우,
일정확률로 주민선정과 정착장려를 수행합니다.

통솔이 높을 수록 수행할 확률이 높습니다.", + 전투준비: + "충분한 병력을 가지고 있지만 훈련과 사기가 부족한 경우 훈련과 사기진작을 수행합니다.", + 전방워프: "전투장이 충분한 병력을 가지고 있다면 전방으로 이동합니다.", + NPC헌납: + "국고가 부족한데 NPC전쟁장이 충분한 금쌀(권장량 대비 1.5배)을 가지고 있다면 일부를 헌납합니다.
NPC내정장은 국고가 넉넉하더라도 충분한 금쌀을 가지고 있다면 권장량만 유지하고 헌납합니다.", + 징병: "전쟁 중 병력을 소진하였다면 재 징병합니다.

기존에 사용한 병종군 중에서 사용가능한 병종을 랜덤하게 선택합니다.
고급 병종을 선택할 확률이 조금 더 높습니다.

NPC의 경우 도시의 인구가 충분하지 않다면 징병을 할 확률이 감소합니다.

유저장은 최대한 고급병종을 유지하며,
유저장 모병이 허용되는 경우 모병을 3회할 수 있다면 모병합니다.", + 후방워프: + "전쟁 중 병력을 소진하였는데 도시의 인구가 충분하지 않다면,
인구가 많은 도시로 이동합니다.", + 전쟁내정: + "전쟁 중 수행하는 내정입니다.
정착장려, 기술연구의 확률이 좀 더 높고,
치안강화, 농지개간, 상업투자의 확률이 낮습니다.

내정이 가능하다 하더라도 전시임을 고려해,
30% 확률로 다른 턴을 수행합니다.", + 소집해제: + "전쟁 중이 아닌 데 병력이 남아있는 경우,
3/4 확률로 소집해제합니다.", + 일반내정: + "도시에서 내정을 수행합니다. 낮은 내정일 수록 수행할 확률이 높습니다.
기술 연구는 1등급 이상 뒤쳐지지 않도록 노력합니다.", + 내정워프: + "도시에서 더이상 내정을 수행할 수 없는 경우,
일정확률로 내정이 부족한 다른 도시로 이동합니다.", +}; diff --git a/hwe/ts/v_NPCControl.ts b/hwe/ts/v_NPCControl.ts new file mode 100644 index 00000000..94fbd6ce --- /dev/null +++ b/hwe/ts/v_NPCControl.ts @@ -0,0 +1,4 @@ +import { createApp } from 'vue' +import NPCControl from './NPCControl.vue'; + +createApp(NPCControl).mount('#app') \ No newline at end of file diff --git a/hwe/v_NPCControl.php b/hwe/v_NPCControl.php new file mode 100644 index 00000000..3a732d50 --- /dev/null +++ b/hwe/v_NPCControl.php @@ -0,0 +1,383 @@ +setReadOnly(); +$userID = Session::getUserID(); + +$db = DB::db(); +$gameStor = KVStorage::getStorage($db, 'game_env'); +$gameStor->cacheValues(['autorun_user', 'develcost']); + +increaseRefresh("NPC 정책", 1); + + +$me = $db->queryFirstRow('SELECT no, npc, nation, city, officer_level, con, turntime, belong, permission, penalty FROM general WHERE owner=%i', $userID); + +$nationID = $me['nation']; +$nation = $db->queryFirstRow('SELECT nation,level,name,color,type,gold,rice,bill,tech,rate,scout,war,secretlimit,capital FROM nation WHERE nation = %i', $nationID); + +$con = checkLimit($me['con']); +if ($con >= 2) { + printLimitMsg($me['turntime']); + exit(); +} + +$permission = checkSecretPermission($me); +if ($permission < 0) { + echo '국가에 소속되어있지 않습니다.'; + die(); +} else if ($permission < 1) { + echo "권한이 부족합니다. 수뇌부가 아니거나 사관년도가 부족합니다."; + die(); +} + + +$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); +$nationStor->cacheValues(['npc_nation_policy', 'npc_general_policy']); +$gameStor->cacheAll(); + +$general = new General($me, null, null, $nation, $gameStor->year, $gameStor->month, false); + +$rawServerPolicy = $gameStor->getValue('npc_nation_policy') ?? []; +$rawNationPolicy = $nationStor->getValue('npc_nation_policy') ?? []; +$rawServerGeneralPolicy = $gameStor->getValue('npc_general_policy') ?? []; +$rawNationGeneralPolicy = $nationStor->getValue('npc_general_policy') ?? []; + +$defaultNationPolicy = ($rawServerPolicy['values'] ?? []) + AutorunNationPolicy::$defaultPolicy; +$currentNationPolicy = ($rawNationPolicy['values'] ?? []) + $defaultNationPolicy; + +$defaultNationPriority = $rawServerPolicy['priority'] ?? (AutorunNationPolicy::$defaultPriority); +$currentNationPriority = $rawNationPolicy['priority'] ?? $defaultNationPriority; + +$defaultGeneralActionPriority = $rawServerGeneralPolicy['priority'] ?? (AutorunGeneralPolicy::$default_priority); +$currentGeneralActionPriority = $rawNationGeneralPolicy['priority'] ?? $defaultGeneralActionPriority; + +$autoPolicyVariable = []; +if ($currentNationPolicy['reqHumanWarUrgentRice'] ?? 0) { + $autoPolicyVariable['reqHumanWarUrgentRice'] = $currentNationPolicy['reqHumanWarUrgentRice']; +} +if ($currentNationPolicy['reqHumanWarUrgentGold'] ?? 0) { + $autoPolicyVariable['reqHumanWarUrgentGold'] = $currentNationPolicy['reqHumanWarUrgentGold']; +} +$autoPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['options'], ['values' => $autoPolicyVariable], null, $nation, $gameStor->getAll(true)); +$zeroPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['options'], null, null, $nation, $gameStor->getAll(true)); + + +?> + + + + + + + + <?= UniqueConst::$serverName ?>: 임시 NPC 정책 +$nationID, + 'defaultNationPolicy'=>$defaultNationPolicy, + 'currentNationPolicy'=>$currentNationPolicy, + + 'defaultNationPriority'=>$defaultNationPriority, + 'currentNationPriority'=>$currentNationPriority, + 'availableNationPriorityItems'=>AutorunNationPolicy::$defaultPriority, + + 'defaultGeneralActionPriority'=>$defaultGeneralActionPriority, + 'currentGeneralActionPriority'=>$currentGeneralActionPriority, + 'availableGeneralActionPriorityItems'=>AutorunGeneralPolicy::$default_priority, + + 'defaultStatNPCMax'=>GameConst::$defaultStatNPCMax, +])?> + + + + + + + + + + + + + + + + + +
+
임시 NPC 정책
+
+ +
국가 정책
+
+ 최근 설정: () +
+
+
+
+
+ +
+ +
+
+
이보다 많으면 포상, 적으면 몰수/헌납합니다.(긴급포상 제외)
+
+ +
+
+ +
+ +
+
+
이보다 많으면 포상, 적으면 몰수/헌납합니다.(긴급포상 제외)
+
+
+
+
+
+ +
+ +
+
+
+ 유저장긴급포상시 이보다 금이 적은 장수에게 포상합니다.
+ 0이면 보병 6회 징병( * 6) 가능한 금을 기준으로 하며, 그 수치는 현재 reqHumanWarUrgentGold) ?>입니다.
+
+
+
+ +
+ +
+
+
유저장긴급포상시 이보다 쌀이 적은 장수에게 포상합니다.
0이면 기본 병종으로 명 사살 가능한 쌀을 기준으로 하며, 그 수치는 현재 reqHumanWarUrgentRice) ?>입니다.
+
+
+
+
+
+ +
+ +
+
+
유저전투장에게 주는 금입니다. 이보다 적으면 포상합니다.
+ 0이면 유저전투장 긴급포상 금의 2배를 기준으로 하며, 그 수치는 현재 reqHumanWarRecommandGold) ?>입니다.
+
+
+
+ +
+ +
+
+
유저전투장에게 주는 쌀입니다. 이보다 적으면 포상합니다.
+ 0이면 유저전투장 긴급포상 쌀의 2배를 기준으로 하며, 그 수치는 현재 reqHumanWarRecommandRice) ?>입니다.
+
+
+
+
+
+ +
+ +
+
+
유저내정장에게 주는 금입니다. 이보다 적으면 포상합니다.
+
+
+
+ +
+ +
+
+
유저내정장에게 주는 쌀입니다. 이보다 적으면 포상합니다.
+
+
+
+
+
+ +
+ +
+
+
NPC전투장에게 주는 금입니다. 이보다 적으면 포상합니다.
+ 0이면 기본 병종 4회( * 4) 징병비를 기준으로 하며, 그 수치는 현재 reqNPCWarGold) ?>입니다.
+
+
+
+ +
+ +
+
+
NPC전투장에게 주는 쌀입니다. 이보다 적으면 포상합니다.
+ 0이면 기본 병종으로 명 사살 가능한 쌀을 기준으로 하며, 그 수치는 현재 reqNPCWarRice) ?>입니다.
+
+
+
+
+
+ +
+ +
+
+
NPC내정장에게 주는 금입니다. 이보다 5배 더 많다면 헌납합니다.
0이면 30턴 내정 가능한 금을 기준으로 하며, 그 수치는 현재 reqNPCDevelGold) ?>입니다.
+
+
+
+ +
+ +
+
+
NPC내정장에게 주는 쌀입니다. 이보다 5배 더 많다면 헌납합니다.
+
+
+
+
+
+ +
+ +
+
+
연산결과가 이 단위보다 적다면 수행하지 않습니다.
+
+
+
+ +
+ +
+
+
이보다 적을 때에는 징병을 시도합니다.
+
+
+
+
+
+ +
+ +
+
+
이보다 낮으면 NPC는 도시에서 징병하지 않고 후방 워프합니다.
+
+
+
+ +
+ +
+
+
전쟁 시 후방 발령, 후방 워프의 기준 인구입니다. 이보다 많다면 '충분하다'고 판단합니다.
+
+
+
+
+
+ +
+ +
+
+
이 수치보다 같거나 높으면 NPC전투장으로 분류됩니다.
+
+
+
+ +
+ +
+
+
훈련/사기진작 기준치입니다. 이보다 같거나 높으면 출병합니다.
+
+
+
+ 전투 부대는 작업중입니다(json양식: {부대번호:[시작도시번호(아국),도착도시번호(적군)],...})
+ 후방 징병 부대는 작업중입니다(json양식: [부대번호,...])
+ 내정 부대는 작업중입니다(json양식: [부대번호,...]) + + + + + +
+
+
+ + +
+
+
+
+
+
NPC 사령턴 우선순위
+
+ 최근 설정: () +
+
예턴이 없거나, 지정되어 있더라도 실패할경우
아래 순위에 따라 사령턴을 시도합니다.
+
+
+
+
비활성
+
+
+
+
+
활성
+
+
+
+
+
+
+ + +
+
+
+
+
+
NPC 일반턴 우선순위
+
+ 최근 설정: () +
+
순위가 높은 것부터 시도합니다.
아무것도 실행할 수 없으면 물자조달이나 인재탐색을 합니다.
+
+
+
+
비활성
+
+
+
+
+
활성
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/webpack.config.cjs b/webpack.config.cjs index 05c416e6..c405f0fc 100644 --- a/webpack.config.cjs +++ b/webpack.config.cjs @@ -21,7 +21,8 @@ module.exports = (env, argv) => { mode, entry: { v_inheritPoint: `${tsDir}/v_inheritPoint.ts`, - v_board: `${tsDir}/v_board.ts` + v_board: `${tsDir}/v_board.ts`, + v_NPCControl: `${tsDir}/v_NPCControl.ts`, }, output: {