diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..beb64354 --- /dev/null +++ b/.babelrc @@ -0,0 +1,18 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "targets": { + "browsers": [ + "last 2 versions" + ] + }, + "modules":false + } + ] + ], + "plugins": [ + "lodash" + ] +} \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..8932a0de --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,22 @@ +module.exports = { + root: true, + parser: "@typescript-eslint/parser", + parserOptions: { + "project": "./tsconfig.json" + }, + ignorePatterns: ['*.test.ts', '.eslintrc.js', 'webpack.config.js', '*.js'], + overrides: [{ + files: ['*.ts', '*.tsx'], + }], + plugins: [ + "@typescript-eslint", + ], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + rules: { + '@typescript-eslint/no-floating-promises': 'error', + } + } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8c55bef0..c3129098 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,8 @@ !.vscode/launch.json !.vscode/extensions.json - +/node_modules +package-lock.json # 체섭 ignore diff --git a/hwe/_admin_force_rehall.php b/hwe/_admin_force_rehall.php index 01bb8694..9b7971f9 100644 --- a/hwe/_admin_force_rehall.php +++ b/hwe/_admin_force_rehall.php @@ -24,3 +24,7 @@ foreach ($db->queryFirstColumn( ) as $generalNo) { CheckHall($generalNo); } + +foreach(General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc = 0')) as $genObj){ + $genObj->mergeTotalInheritancePoint(); +} \ No newline at end of file diff --git a/hwe/b_inheritPoint.php b/hwe/b_inheritPoint.php new file mode 100644 index 00000000..3b15a86b --- /dev/null +++ b/hwe/b_inheritPoint.php @@ -0,0 +1,131 @@ +setReadOnly(); +$userID = Session::getUserID(); +$generalID = $session->generalID; + +$db = DB::db(); +$gameStor = KVStorage::getStorage($db, 'game_env'); + +$me = General::createGeneralObjFromDB($generalID); + + +$pointHelpText = [ + 'sum' => '다음 플레이에서 사용할 수 있는 총 포인트입니다.', + 'new' => '이번 플레이에서 얻은 총 포인트입니다.', + 'previous' => '이전에 물려받은 포인트입니다.', + 'lived_month' => '살아남은 기간입니다. (1개월 단위)', + 'max_belong' => '가장 오래 임관했던 국가의 연도입니다.', + 'max_domestic_critical' => '성공한 내정 중 최대 연속값입니다.', + 'snipe_combat' => '유리한 상성을 가지고 전투했습니다.', + 'combat' => '전투 횟수입니다.', + 'sabotage' => '계략 성공 횟수입니다.', + 'unifier' => '천통에 기여한 포인트입니다.
각 국의 군주, 천통 수뇌, 천통 군주가 받습니다.', + 'dex' => '총 숙련도합입니다.', + 'tournament' => '토너먼트 입상 포인트입니다.', + 'betting' => '성공적인 베팅을 했습니다.
수익율과 베팅 성공 횟수를 따릅니다.', +]; +$items = []; +foreach(array_keys(General::INHERITANCE_KEY) as $key){ + $items[$key] = $me->getInheritancePoint($key)??0; +} +?> + + + + + <?= UniqueConst::$serverName ?>: 유산 관리 + + + + + + + + + + + + + + + + + + + + + + +
유산 관리
+
+
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+ +
+ +
+
+ +
+ +
+
+

+ [$type, $multiplier, $name]) : ?> + +
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+ + + \ No newline at end of file diff --git a/hwe/b_npc_control.php b/hwe/b_npc_control.php index 9b79445b..aa15035d 100644 --- a/hwe/b_npc_control.php +++ b/hwe/b_npc_control.php @@ -91,6 +91,7 @@ $zeroPolicy = new AutorunNationPolicy($general, ($gameStor->autorun_user)['optio var availableGeneralActionPriorityItems = ; var btnHelpMessage = { + '불가침제의': '군주가 NPC이고, 타국에서 원조를 받았을 때,
세입(금/쌀) 대비 원조량에 따라 불가침제의를 합니다.', '선전포고': '군주가 NPC이고, 전쟁중이 아닐 때,
주변국중 하나를 골라 선포합니다.

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

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

도시 인구가 충분하다면, 굳이 천도하지는 않습니다.', '유저장긴급포상': '금/쌀이 부족한 유저전투장에게 긴급하게 포상합니다.
국고가 권장량보다 적어지더라도 시도합니다.', diff --git a/hwe/css/inheritPoint.css b/hwe/css/inheritPoint.css new file mode 100644 index 00000000..25d69429 --- /dev/null +++ b/hwe/css/inheritPoint.css @@ -0,0 +1,23 @@ +#inheritance_list{ + display: flex; + flex-wrap: wrap; +} + +.inherit_padding{ + width: 33%; + padding: 10px 2px; +} + +.inherit_item{ + width: 33%; + padding: 10px 2px; +} + +.col-form-label{ + text-align:right; + padding-right:2ch; +} + +.inherit_value{ + text-align: right; +} \ No newline at end of file diff --git a/hwe/func.php b/hwe/func.php index 2da79878..dc758aa5 100644 --- a/hwe/func.php +++ b/hwe/func.php @@ -1707,7 +1707,7 @@ function deleteNation(General $lord, bool $applyDB):array $nationID, $lordID ), - ['npc', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'aux'], 1 + ['npc', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'belong', 'aux'], 1 ); $nationGeneralList[$lordID] = $lord; @@ -1724,6 +1724,12 @@ function deleteNation(General $lord, bool $applyDB):array // 전 장수 재야로 foreach($nationGeneralList as $general){ + $general->setAuxVar('max_belong', + max( + $general->getVar('belong'), + $general->getAuxVar('max_belong')??0 + ) + ); $general->setVar('belong', 0); $general->setVar('troop', 0); $general->setVar('officer_level', 0); diff --git a/hwe/func_gamerule.php b/hwe/func_gamerule.php index 98c802cb..07d52f11 100644 --- a/hwe/func_gamerule.php +++ b/hwe/func_gamerule.php @@ -623,10 +623,14 @@ function updateNationState() $nation['nation'], $targetKillTurn ); - $nationGenList = General::createGeneralObjListFromDB($nationGenIDList, ['belong'], 2); + $nationGenList = General::createGeneralObjListFromDB($nationGenIDList, ['belong', 'npc'], 2); + $chiefObj = null; $uniqueLotteryWeightList = []; foreach ($nationGenList as $nationGen) { + if ($nationGen->getVar('officer_level') == 12) { + $chiefObj = $nationGen; + } $trialCnt = count(GameConst::$allItems); foreach ($nationGen->getItems() as $item) { @@ -665,6 +669,10 @@ function updateNationState() giveRandomUniqueItem($winnerObj, '작위보상'); $winnerObj->applyDB($db); } + + if($chiefObj){ + $chiefObj->increaseInheritancePoint('unifier', 250 * $levelDiff); + } } } @@ -982,6 +990,15 @@ function checkEmperior() $nationLogger = new ActionLogger(0, $nationID, $admin['year'], $admin['month']); $nationLogger->pushNationalHistoryLog("{$nationName}{$josaYi} 전토를 통일"); + foreach(General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc = 0')) as $genObj){ + if($genObj->getNationID() == $nationID){ + if($genObj->getVar('officer_level') > 4){ + $genObj->increaseInheritancePoint('unifier', 2000); + }; + } + $genObj->mergeTotalInheritancePoint(); + } + $gameStor->isunited = 2; $gameStor->conlimit = $gameStor->conlimit * 100; @@ -1132,3 +1149,25 @@ function checkEmperior() //연감 월결산 LogHistory(); } + +function resetInheritanceUser(int $userID){ + $inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}"); + $totalPoint = 0; + foreach($inheritStor->getAll() as [$value,]){ + $totalPoint += $value; + } + $totalPoint = Util::toInt($totalPoint); + $inheritStor->resetValues(); + $inheritStor->setValue('previous', [$totalPoint, null]); +} + +function updateMaxDomesticCritical(General $general, $score){ + $maxDomesticCritical = $general->getAuxVar('max_domestic_critical')??0; + $maxDomesticCritical += $score / 2; + $general->setAuxVar('max_domestic_critical', $maxDomesticCritical); + + $oldMaxDomesticCritical = $general->getInheritancePoint('max_domestic_critical'); + if($maxDomesticCritical > $oldMaxDomesticCritical){ + $general->setInheritancePoint('max_domestic_critical', $maxDomesticCritical); + } +} \ No newline at end of file diff --git a/hwe/func_tournament.php b/hwe/func_tournament.php index 5a94b016..5039aa47 100644 --- a/hwe/func_tournament.php +++ b/hwe/func_tournament.php @@ -689,7 +689,8 @@ function setGift($tnmt_type, $tnmt, $phase) { 'grp_no'=>$general['grp_no'], 'reward'=>$cost, 'msg'=>"16강 진출", - 'logger'=>$logger + 'logger'=>$logger, + 'inheritance_point'=>10, ]; } //8강자 명성 돈 @@ -723,6 +724,7 @@ function setGift($tnmt_type, $tnmt, $phase) { //포상 장수 이름, 금액 $resultHelper[$generalID]['reward'] += $cost; $resultHelper[$generalID]['msg'] = "4강 진출"; + General::createGeneralObjFromDB($generalID)->increaseInheritancePoint('tournament', 10); } //결승자 명성 돈 $cost = $admin['develcost'] * 6; @@ -739,6 +741,7 @@ function setGift($tnmt_type, $tnmt, $phase) { //포상 장수 이름, 금액 $resultHelper[$generalID]['reward'] += $cost; $resultHelper[$generalID]['msg'] = "준우승으"; + $resultHelper[$generalID]['inheritance_point'] = 50; if($general['lose'] > 0){ $runnerUp = $general; } @@ -761,6 +764,7 @@ function setGift($tnmt_type, $tnmt, $phase) { //포상 장수 이름, 금액 $resultHelper[$generalID]['reward'] += $cost; $resultHelper[$generalID]['msg'] = "우승으"; + $resultHelper[$generalID]['inheritance_point'] = 100; $winner = $general; } @@ -775,9 +779,6 @@ function setGift($tnmt_type, $tnmt, $phase) { $runnerUpLogger = $resultHelper[$runnerUp['no']]['logger']; $runnerUpLogger->pushGeneralHistoryLog("{$tp} 대회에서 준우승"); - - - $winnerRewardText = number_format($resultHelper[$winner['no']]['reward']); $runnerUpRewardText = number_format($resultHelper[$runnerUp['no']]['reward']); @@ -786,12 +787,16 @@ function setGift($tnmt_type, $tnmt, $phase) { $winnerLogger->pushGlobalHistoryLog("{$tp} 대회에서 {$winner['name']}{$josaYiWinner} 우승, {$runnerUp['name']}{$josaYiRunnerUp} 준우승을 차지하여 천하에 이름을 떨칩니다!", ActionLogger::EVENT_YEAR_MONTH); $winnerLogger->pushGlobalHistoryLog("{$tp} 대회의 우승자에게는 {$winnerRewardText}, 준우승자에겐 {$runnerUpRewardText}의 상금과 약간의 명성이 주어집니다!", ActionLogger::EVENT_YEAR_MONTH); - - foreach($resultHelper as $general){ + + $generalObjList = General::createGeneralObjListFromDB(array_keys($resultHelper)); + + foreach($resultHelper as $generalID=>$general){ $rewardText = number_format($general['reward']); /** @var ActionLogger */ $logger = $general['logger']; $logger->pushGeneralActionLog("{$tp} 대회의 {$general['msg']}로 {$rewardText}의 상금, 약간의 명성 획득!", ActionLogger::EVENT_PLAIN); + //TODO: 토너먼트의 다른 값이 모두 sql에 직접 입력하므로 기반을 바꿔야함. + $generalObjList[$generalID]->increaseInheritancePoint('tournament', $general['inheritance_point']); } //우승자 번호 diff --git a/hwe/j_simulate_battle.php b/hwe/j_simulate_battle.php index 89edb9cc..85acd68e 100644 --- a/hwe/j_simulate_battle.php +++ b/hwe/j_simulate_battle.php @@ -140,6 +140,7 @@ if(!$v->validate()){ 'reason'=>'[출병자]'.$v->errorStr() ]); } +$rawAttacker['owner'] = 0; $defenderList = []; foreach($rawDefenderList as $idx=>$rawDefenderGeneral){ @@ -152,6 +153,7 @@ foreach($rawDefenderList as $idx=>$rawDefenderGeneral){ 'reason'=>"[수비자{$idx}]".$v->errorStr() ]); } + $rawDefenderGeneral['owner'] = 0; $defenderList[] = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true); } diff --git a/hwe/join_post.php b/hwe/join_post.php index 423ecbf6..fbd6b58a 100644 --- a/hwe/join_post.php +++ b/hwe/join_post.php @@ -266,6 +266,8 @@ foreach(Util::range(GameConst::$maxTurn) as $turnIdx){ } $db->insert('general_turn', $turnRows); +resetInheritanceUser($userID); + $rank_data = []; foreach(array_keys(General::RANK_COLUMN) as $rankColumn){ $rank_data[] = [ diff --git a/hwe/js/inheritPoint.js b/hwe/js/inheritPoint.js new file mode 100644 index 00000000..e0223ef3 --- /dev/null +++ b/hwe/js/inheritPoint.js @@ -0,0 +1,2 @@ +(()=>{var t={762:t=>{t.exports=function(t,e){for(var r,n=-1,o=t.length;++n{t.exports=function(t){return t}},297:(t,e,r)=>{var n=r(762),o=r(557);t.exports=function(t){return t&&t.length?n(t,o):0}}},e={};function r(n){var o=e[n];if(void 0!==o)return o.exports;var u=e[n]={exports:{}};return t[n](u,u.exports,r),u.exports}r.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return r.d(e,{a:e}),e},r.d=(t,e)=>{for(var n in e)r.o(e,n)&&!r.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},r.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=r(297),e=r.n(t);function n(t){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){for(var r=0;r0&&void 0!==arguments[0]?arguments[0]:"";return o(this,a),h(l(t=n.call(this,e)),"name","RuntimeError"),t.message=e,t}return e=a,(r=[{key:"toString",value:function(){return this.message?this.name+": "+this.message:this.name}}])&&u(e.prototype,r),a}(f(Error)));function m(t){if(null==t)throw new b;return t}function d(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var r=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=r){var n,o,u=[],i=!0,c=!1;try{for(r=r.call(t);!(i=(n=r.next()).done)&&(u.push(n.value),!e||u.length!==e);i=!0);}catch(t){c=!0,o=t}finally{try{i||null==r.return||r.return()}finally{if(c)throw o}}return u}}(t,e)||function(t,e){if(t){if("string"==typeof t)return w(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?w(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function w(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ diff --git a/hwe/js/inheritPoint.js.map b/hwe/js/inheritPoint.js.map new file mode 100644 index 00000000..b5ef15bf --- /dev/null +++ b/hwe/js/inheritPoint.js.map @@ -0,0 +1 @@ +{"version":3,"file":"inheritPoint.js","mappings":"qBAuBAA,EAAOC,QAdP,SAAiBC,EAAOC,GAKtB,IAJA,IAAIC,EACAC,GAAS,EACTC,EAASJ,EAAMI,SAEVD,EAAQC,GAAQ,CACvB,IAAIC,EAAUJ,EAASD,EAAMG,SACbG,IAAZD,IACFH,OAAoBI,IAAXJ,EAAuBG,EAAWH,EAASG,GAGxD,OAAOH,I,QCATJ,EAAOC,QAJP,SAAkBQ,GAChB,OAAOA,I,cCjBT,IAAIC,EAAU,EAAQ,KAClBC,EAAW,EAAQ,KAsBvBX,EAAOC,QANP,SAAaC,GACX,OAAQA,GAASA,EAAMI,OACnBI,EAAQR,EAAOS,GACf,KCnBFC,EAA2B,GAG/B,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBN,IAAjBO,EACH,OAAOA,EAAad,QAGrB,IAAID,EAASY,EAAyBE,GAAY,CAGjDb,QAAS,IAOV,OAHAe,EAAoBF,GAAUd,EAAQA,EAAOC,QAASY,GAG/Cb,EAAOC,QCpBfY,EAAoBI,EAAKjB,IACxB,IAAIkB,EAASlB,GAAUA,EAAOmB,WAC7B,IAAOnB,EAAiB,QACxB,IAAM,EAEP,OADAa,EAAoBO,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,GCLRL,EAAoBO,EAAI,CAACnB,EAASqB,KACjC,IAAI,IAAIC,KAAOD,EACXT,EAAoBW,EAAEF,EAAYC,KAASV,EAAoBW,EAAEvB,EAASsB,IAC5EE,OAAOC,eAAezB,EAASsB,EAAK,CAAEI,YAAY,EAAMC,IAAKN,EAAWC,MCJ3EV,EAAoBW,EAAI,CAACK,EAAKC,IAAUL,OAAOM,UAAUC,eAAeC,KAAKJ,EAAKC,G,o2ECG3E,IAeMI,EAAb,yLACkB,mBADlB,YAfA,uB,IAAA,OAEI,aAAyC,MAAtBC,EAAsB,uDAAJ,GAAI,qBACrC,cAAMA,IAD+B,OAD3B,gBAC2B,EAAtBA,QAAAA,EAAsB,EAF7C,O,EAAA,G,EAAA,uBAKI,WACI,OAAIC,KAAKD,QACEC,KAAKC,KAAO,KAAOD,KAAKD,QAGxBC,KAAKC,U,iBAVxB,KAAkCC,SAmB3B,SAASC,EAAUnC,GACtB,GAAIA,MAAAA,EACA,MAAM,IAAI8B,EAEd,OAAO9B,E,87BCWXoC,OAAOC,UAzBP,WAEI,IAAMC,EAAOH,EAAOI,SAASC,cAAc,uBACrCC,EAAON,EAAOI,SAASC,cAAc,4BACrCE,EAAOP,EAAOI,SAASC,cAAc,uBAErCG,EAAWC,KAAKC,MAAM,IAAIxB,OAAOyB,OAAOV,OAAOW,SAC/CC,EAAWJ,KAAKC,MAAMT,OAAOW,MAAP,UACtBE,EAAcN,EAAWK,EAE/BV,EAAKjC,MAAQsC,EAASO,iBACtBT,EAAKpC,MAAQ2C,EAASE,iBACtBR,EAAKrC,MAAQ4C,EAAYC,iBAEzB,cAAwB7B,OAAO8B,QAAQf,OAAOW,OAA9C,eAAqD,CAAjD,gBAAO5B,EAAP,KAAYiC,EAAZ,KACcjB,EAAOI,SAASC,cAAT,mBAAmCrB,EAAnC,YACfd,MAAQuC,KAAKC,MAAMO,GAAKF,iBAGlC,cAAyB7B,OAAO8B,QAAQf,OAAOiB,UAA/C,eAAyD,CAArD,gBAAOlC,EAAP,KAAYmC,EAAZ,KACcnB,EAAOI,SAASC,cAAT,mBAAmCrB,EAAnC,sBACfoC,UAAYD,K","sources":["webpack://hidche_lib/./node_modules/lodash/_baseSum.js","webpack://hidche_lib/./node_modules/lodash/identity.js","webpack://hidche_lib/./node_modules/lodash/sum.js","webpack://hidche_lib/webpack/bootstrap","webpack://hidche_lib/webpack/runtime/compat get default export","webpack://hidche_lib/webpack/runtime/define property getters","webpack://hidche_lib/webpack/runtime/hasOwnProperty shorthand","webpack://hidche_lib/./hwe/ts/util.ts","webpack://hidche_lib/./hwe/ts/inheritPoint.ts"],"sourcesContent":["/**\n * The base implementation of `_.sum` and `_.sumBy` without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {number} Returns the sum.\n */\nfunction baseSum(array, iteratee) {\n var result,\n index = -1,\n length = array.length;\n\n while (++index < length) {\n var current = iteratee(array[index]);\n if (current !== undefined) {\n result = result === undefined ? current : (result + current);\n }\n }\n return result;\n}\n\nmodule.exports = baseSum;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nmodule.exports = identity;\n","var baseSum = require('./_baseSum'),\n identity = require('./identity');\n\n/**\n * Computes the sum of the values in `array`.\n *\n * @static\n * @memberOf _\n * @since 3.4.0\n * @category Math\n * @param {Array} array The array to iterate over.\n * @returns {number} Returns the sum.\n * @example\n *\n * _.sum([4, 2, 8, 6]);\n * // => 20\n */\nfunction sum(array) {\n return (array && array.length)\n ? baseSum(array, identity)\n : 0;\n}\n\nmodule.exports = sum;\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","type ErrType = { new(msg?: string): T }\ntype Nullable = T | null | undefined\n\nexport class RuntimeError extends Error {\n public name = 'RuntimeError';\n constructor(public message: string = '') {\n super(message);\n }\n toString(): string {\n if (this.message) {\n return this.name + ': ' + this.message;\n }\n else {\n return this.name;\n }\n }\n}\n\nexport class NotNullExpected extends RuntimeError {\n public name = 'NotNullExpected';\n}\n\nexport function unwrap(result: Nullable): T {\n if (result === null || result === undefined) {\n throw new NotNullExpected();\n }\n return result;\n}\n\nexport function unwrap_err(result: Nullable, errType: ErrType, errMsg?: string): T {\n if (result === null || result === undefined) {\n throw new errType(errMsg);\n }\n return result;\n}","import { sum } from \"lodash\";\nimport { unwrap } from \"./util\";\ndeclare global {\n interface Window { \n formStart: ()=>void;\n items: {[name: string]:number};\n helpText: {[name: string]:string};\n }\n}\n\nexport {}\n\nfunction formStart() {\n\n const dSum = unwrap(document.querySelector('#inherit_sum_value')) as HTMLInputElement ;\n const dOld = unwrap(document.querySelector('#inherit_previous_value')) as HTMLInputElement;\n const dNew = unwrap(document.querySelector('#inherit_new_value')) as HTMLInputElement;\n\n const sumPoint = Math.floor(sum(Object.values(window.items)));\n const oldPoint = Math.floor(window.items['previous']);\n const sumNewPoint = sumPoint - oldPoint;\n\n dSum.value = sumPoint.toLocaleString();\n dOld.value = oldPoint.toLocaleString();\n dNew.value = sumNewPoint.toLocaleString();\n\n for(const [key, val] of Object.entries(window.items)){\n const dItem = unwrap(document.querySelector(`#inherit_${key}_value`)) as HTMLInputElement ;\n dItem.value = Math.floor(val).toLocaleString();\n }\n\n for(const [key, text] of Object.entries(window.helpText)){\n const dText = unwrap(document.querySelector(`#inherit_${key} small.form-text`)) as HTMLElement;\n dText.innerHTML = text;\n }\n}\n\nwindow.formStart = formStart;"],"names":["module","exports","array","iteratee","result","index","length","current","undefined","value","baseSum","identity","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","n","getter","__esModule","d","a","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","NotNullExpected","message","this","name","Error","unwrap","window","formStart","dSum","document","querySelector","dOld","dNew","sumPoint","Math","floor","values","items","oldPoint","sumNewPoint","toLocaleString","entries","val","helpText","text","innerHTML"],"sourceRoot":""} \ No newline at end of file diff --git a/hwe/process_war.php b/hwe/process_war.php index 3eee843a..88d94666 100644 --- a/hwe/process_war.php +++ b/hwe/process_war.php @@ -261,6 +261,15 @@ function processWar_NG( $attacker->addTrain(1); $defender->addTrain(1); + + $attackerCrewTypeCoef = $attacker->getCrewType()->getAttackCoef($defender->getCrewType()) * $defender->getCrewType()->getDefenceCoef($attacker->getCrewType()); + $defenderCrewTypeCoef = $defender->getCrewType()->getAttackCoef($attacker->getCrewType()) * $attacker->getCrewType()->getDefenceCoef($defender->getCrewType()); + if($attackerCrewTypeCoef > $defenderCrewTypeCoef && $attacker instanceof WarUnitGeneral){ + $attacker->getGeneral()->increaseInheritancePoint('snipe_combat', 1); + } + if($defenderCrewTypeCoef > $attackerCrewTypeCoef && $defender instanceof WarUnitGeneral){ + $defender->getGeneral()->increaseInheritancePoint('snipe_combat', 1); + } $attackerName = $attacker->getName(); $attackerCrewTypeName = $attacker->getCrewTypeName(); @@ -522,7 +531,7 @@ function ConquerCity(array $admin, General $general, array $city) { $lord = new General($db->queryFirstRow( 'SELECT %l FROM general WHERE nation = %i AND officer_level = %i LIMIT 1', - Util::formatListOfBackticks(General::mergeQueryColumn(['npc', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'aux'], 1)[0]), + Util::formatListOfBackticks(General::mergeQueryColumn(['npc', 'gold', 'rice', 'experience', 'explevel', 'belong', 'dedication', 'dedlevel', 'aux'], 1)[0]), $defenderNationID, 12 ), null, $city, $loseNation, $year, $month, false); diff --git a/hwe/sammo/AutorunNationPolicy.php b/hwe/sammo/AutorunNationPolicy.php index 079b2547..2641048d 100644 --- a/hwe/sammo/AutorunNationPolicy.php +++ b/hwe/sammo/AutorunNationPolicy.php @@ -28,6 +28,7 @@ class AutorunNationPolicy { static $NPC몰수 = 'NPC몰수'; // 군주 행동 + static $불가침제의 = '불가침제의'; static $선전포고 = '선전포고'; static $천도 = '천도'; @@ -35,6 +36,7 @@ class AutorunNationPolicy { //실제 행동 static public $defaultPriority = [ + '불가침제의', '선전포고', '천도', @@ -106,6 +108,7 @@ class AutorunNationPolicy { public $canNPC포상 = true; public $canNPC몰수 = true; + public $can불가침제의 = true; public $can선전포고 = true; public $can천도 = true; diff --git a/hwe/sammo/Command/General/che_기술연구.php b/hwe/sammo/Command/General/che_기술연구.php index 6c9f9a2a..9c8cb1db 100644 --- a/hwe/sammo/Command/General/che_기술연구.php +++ b/hwe/sammo/Command/General/che_기술연구.php @@ -14,7 +14,8 @@ use function sammo\{ getDomesticExpLevelBonus, CriticalRatioDomestic, CriticalScoreEx, - tryUniqueItemLottery + tryUniqueItemLottery, + updateMaxDomesticCritical }; use \sammo\Constraint\Constraint; @@ -93,6 +94,13 @@ class che_기술연구 extends che_상업투자{ $exp = $score * 0.7; $ded = $score * 1.0; + if($pick == 'success'){ + updateMaxDomesticCritical($general, $score); + } + else{ + $general->setAuxVar('max_domestic_critical', 0); + } + $scoreText = number_format($score, 0); $josaUl = JosaUtil::pick(static::$actionName, '을'); diff --git a/hwe/sammo/Command/General/che_랜덤임관.php b/hwe/sammo/Command/General/che_랜덤임관.php index e0dd31f9..eac97fac 100644 --- a/hwe/sammo/Command/General/che_랜덤임관.php +++ b/hwe/sammo/Command/General/che_랜덤임관.php @@ -1,21 +1,22 @@ arg = null; return true; @@ -71,7 +74,7 @@ class che_랜덤임관 extends Command\GeneralCommand{ $relYear = $env['year'] - $env['startyear']; - $this->fullConditionConstraints=[ + $this->fullConditionConstraints = [ ConstraintHelper::BeNeutral(), ConstraintHelper::AllowJoinAction(), ]; @@ -83,28 +86,34 @@ class che_랜덤임관 extends Command\GeneralCommand{ */ } - public function getCommandDetailTitle():string{ + public function getCommandDetailTitle(): string + { return '무작위 국가로 임관'; } - public function getBrief():string{ + public function getBrief(): string + { return '무작위 국가로 임관'; } - public function getCost():array{ + public function getCost(): array + { return [0, 0]; } - - public function getPreReqTurn():int{ + + public function getPreReqTurn(): int + { return 0; } - public function getPostReqTurn():int{ + public function getPostReqTurn(): int + { return 0; } - public function run():bool{ - if(!$this->hasFullConditionMet()){ + public function run(): bool + { + if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -126,108 +135,107 @@ class che_랜덤임관 extends Command\GeneralCommand{ $destNation = null; if ($general->getNPCType() >= 2 && !$env['fiction'] && 1000 <= $env['scenario'] && $env['scenario'] < 2000) { - if($notIn){ + if ($notIn) { $nations = $db->query( 'SELECT nation.`name` as `name`,nation.nation as nation,scout,gennum,`affinity` FROM nation join general on general.nation = nation.nation and general.officer_level = 12 WHERE scout=0 and gennum<%i and nation.nation not in %li', - $relYear<3?GameConst::$initialNationGenLimit:GameConst::$defaultMaxGeneral, + $relYear < 3 ? GameConst::$initialNationGenLimit : GameConst::$defaultMaxGeneral, $notIn ); - } - else{ + } else { $nations = $db->query( 'SELECT nation.`name` as `name`,nation.nation as nation,scout,gennum,`affinity` FROM nation join general on general.nation = nation.nation and general.officer_level = 12 WHERE scout=0 and gennum<%i', - $relYear<3?GameConst::$initialNationGenLimit:GameConst::$defaultMaxGeneral + $relYear < 3 ? GameConst::$initialNationGenLimit : GameConst::$defaultMaxGeneral ); } - + shuffle($nations); $allGen = Util::arraySum($nations, 'gennum'); - - $maxScore = 1<<30; + + $maxScore = 1 << 30; $affinity = $general->getVar('affinity'); - - foreach($nations as $testNation){ + + foreach ($nations as $testNation) { $affinity = abs($affinity - $testNation['affinity']); $affinity = min($affinity, abs($affinity - 150)); - - $score = log($affinity + 1, 2);//0~ - + + $score = log($affinity + 1, 2); //0~ + //쉐킷쉐킷 $score += Util::randF(); - - $score += sqrt($testNation['gennum']/$allGen); - - if($score < $maxScore){ + + $score += sqrt($testNation['gennum'] / $allGen); + + if ($score < $maxScore) { $maxScore = $score; $destNation = $testNation; } } - } - else{ + } else { $onlyRandom = $env['join_mode'] == 'onlyRandom'; $genLimit = GameConst::$defaultMaxGeneral; - if($onlyRandom && TimeUtil::IsRangeMonth($env['init_year'], $env['init_month'], 1, $env['year'], $env['month'])){ + if ($onlyRandom && TimeUtil::IsRangeMonth($env['init_year'], $env['init_month'], 1, $env['year'], $env['month'])) { $genLimit = GameConst::$initialNationGenLimitForRandInit; - } - else if($relYear < 3){ + } else if ($relYear < 3) { $genLimit = GameConst::$initialNationGenLimit; } $generalsCnt = []; - if($notIn){ + if ($notIn) { $rawGeneralsCnt = $db->query( - 'SELECT general.nation as nation, nation.gennum, nation.name, npc, count(*) as cnt FROM general JOIN nation ON general.nation = nation.nation WHERE npc < 4 AND nation.gennum < %i AND nation.scout=0 AND nation.nation NOT IN %li GROUP BY general.nation, general.npc', + 'SELECT general.nation as nation, nation.gennum, nation.name, npc, count(*) as cnt FROM general JOIN nation ON general.nation = nation.nation WHERE npc != 9 AND nation.gennum < %i AND nation.scout=0 AND nation.nation NOT IN %li GROUP BY general.nation, general.npc', $genLimit, $notIn ); - } - else{ + } else { $rawGeneralsCnt = $db->query( - 'SELECT general.nation as nation, nation.gennum, nation.name, npc, count(*) as cnt FROM general JOIN nation ON general.nation = nation.nation WHERE npc < 4 AND nation.gennum < %i AND nation.scout=0 GROUP BY general.nation, general.npc', + 'SELECT general.nation as nation, nation.gennum, nation.name, npc, count(*) as cnt FROM general JOIN nation ON general.nation = nation.nation WHERE npc != 9 AND nation.gennum < %i AND nation.scout=0 GROUP BY general.nation, general.npc', $genLimit ); } - - foreach($rawGeneralsCnt as $nation){ + + foreach ($rawGeneralsCnt as $nation) { $nationID = $nation['nation']; - if(!\key_exists($nationID, $generalsCnt)){ + if (!\key_exists($nationID, $generalsCnt)) { $generalsCnt[$nationID] = [ - 'nation'=>$nationID, - 'gennum'=>$nation['gennum'], - 'name'=>$nation['name'], - 'cnt'=>0, + 'nation' => $nationID, + 'gennum' => $nation['gennum'], + 'name' => $nation['name'], + 'cnt' => 0, ]; $generalsCnt[$nationID]['cnt'] = 0; } - - if($nation['npc'] <= 2){ + + if ($nation['npc'] <= 2) { $calcCnt = $nation['cnt']; - } - else{ + } else { $calcCnt = $nation['cnt'] / 2; } + if ($general->getNPCType() < 2 && Util::starts_with($nation['name'], 'ⓤ')) { + $calcCnt *= 100; + } + $generalsCnt[$nationID]['cnt'] += $calcCnt; } $randVals = []; - foreach($generalsCnt as $testNation){ - $randVals[] = [$testNation, 1/$testNation['cnt']]; + foreach ($generalsCnt as $testNation) { + $randVals[] = [$testNation, 1 / $testNation['cnt']]; } - if($randVals){ + if ($randVals) { $destNation = Util::choiceRandomUsingWeightPair($randVals); } } $logger = $general->getLogger(); - if(!$destNation){ + if (!$destNation) { //임관 가능한 국가가 없다! - $logger->pushGeneralActionLog("임관 가능한 국가가 없습니다. <1>$date"); + $logger->pushGeneralActionLog("임관 가능한 국가가 없습니다. <1>$date"); $this->alternative = new che_요양($general, $this->env, null); return false; } @@ -236,7 +244,7 @@ class che_랜덤임관 extends Command\GeneralCommand{ $destNationID = $destNation['nation']; $destNationName = $destNation['name']; - + $talkList = [ '어쩌다 보니', @@ -257,10 +265,9 @@ class che_랜덤임관 extends Command\GeneralCommand{ $logger->pushGeneralHistoryLog("{$destNationName}에 랜덤 임관"); $logger->pushGlobalActionLog("{$generalName}{$josaYi} {$randomTalk} {$destNationName}임관했습니다."); - if($gennum < GameConst::$initialNationGenLimit) { + if ($gennum < GameConst::$initialNationGenLimit) { $exp = 700; - } - else { + } else { $exp = 100; } @@ -268,22 +275,21 @@ class che_랜덤임관 extends Command\GeneralCommand{ $general->setVar('officer_level', 1); $general->setVar('officer_city', 0); $general->setVar('belong', 1); - - if($this->destGeneralObj !== null){ + + if ($this->destGeneralObj !== null) { $general->setVar('city', $this->destGeneralObj->getCityID()); - } - else{ + } else { $targetCityID = $db->queryFirstField('SELECT city FROM general WHERE nation = %i AND officer_level=12', $destNationID); $general->setVar('city', $targetCityID); } $db->update('nation', [ - 'gennum'=>$db->sqleval('gennum + 1') + 'gennum' => $db->sqleval('gennum + 1') ], 'nation=%i', $destNationID); $relYear = $env['year'] - $env['startyear']; - if($general->getNPCType() == 1 || $relYear >= 3){ - $joinedNations = $general->getAuxVar('joinedNations')??[]; + if ($general->getNPCType() == 1 || $relYear >= 3) { + $joinedNations = $general->getAuxVar('joinedNations') ?? []; $joinedNations[] = $destNationID; $general->setAuxVar('joinedNations', $joinedNations); } @@ -296,5 +302,4 @@ class che_랜덤임관 extends Command\GeneralCommand{ return true; } - -} \ No newline at end of file +} diff --git a/hwe/sammo/Command/General/che_상업투자.php b/hwe/sammo/Command/General/che_상업투자.php index 9643a3e2..6d6fe8d2 100644 --- a/hwe/sammo/Command/General/che_상업투자.php +++ b/hwe/sammo/Command/General/che_상업투자.php @@ -15,7 +15,8 @@ use function \sammo\{ getDomesticExpLevelBonus, CriticalRatioDomestic, CriticalScoreEx, - tryUniqueItemLottery + tryUniqueItemLottery, + updateMaxDomesticCritical }; use \sammo\Constraint\Constraint; @@ -165,6 +166,13 @@ class che_상업투자 extends Command\GeneralCommand{ $exp = $score * 0.7; $ded = $score * 1.0; + if($pick == 'success'){ + updateMaxDomesticCritical($general, $score); + } + else{ + $general->setAuxVar('max_domestic_critical', 0); + } + $scoreText = number_format($score, 0); $josaUl = JosaUtil::pick(static::$actionName, '을'); @@ -203,6 +211,4 @@ class che_상업투자 extends Command\GeneralCommand{ return true; } - - } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_임관.php b/hwe/sammo/Command/General/che_임관.php index 15175e7e..d0c0041d 100644 --- a/hwe/sammo/Command/General/che_임관.php +++ b/hwe/sammo/Command/General/che_임관.php @@ -202,6 +202,8 @@ class che_임관 extends Command\GeneralCommand{ $nationList[$nationID]['scoutmsg'] = $scoutMsg; } + $hiddenItems = []; + foreach($nationList as &$nation){ if($env['year'] < $env['startyear']+3 && $nation['gennum'] >= GameConst::$initialNationGenLimit){ $nation['availableJoin'] = false; @@ -217,7 +219,9 @@ class che_임관 extends Command\GeneralCommand{ $nation['availableJoin'] = false; } - + if(Util::starts_with($nation['name'], 'ⓤ')){ + $hiddenItems[$nation['nation']] = $nation['nation']; + } } unset($nation); ob_start(); @@ -228,6 +232,7 @@ class che_임관 extends Command\GeneralCommand{ 임관할 국가를 목록에서 선택하세요.
+ diff --git a/hwe/sammo/Command/General/che_정착장려.php b/hwe/sammo/Command/General/che_정착장려.php index 60f5ba7a..97d0b837 100644 --- a/hwe/sammo/Command/General/che_정착장려.php +++ b/hwe/sammo/Command/General/che_정착장려.php @@ -15,7 +15,8 @@ use function \sammo\{ getDomesticExpLevelBonus, CriticalRatioDomestic, CriticalScoreEx, - tryUniqueItemLottery + tryUniqueItemLottery, + updateMaxDomesticCritical }; use \sammo\Constraint\Constraint; @@ -150,6 +151,13 @@ class che_정착장려 extends Command\GeneralCommand{ $exp = $score * 0.7; $ded = $score * 1.0; + if($pick == 'success'){ + updateMaxDomesticCritical($general, $score); + } + else{ + $general->setAuxVar('max_domestic_critical', 0); + } + $score *= 10; $scoreText = number_format($score, 0); @@ -187,5 +195,5 @@ class che_정착장려 extends Command\GeneralCommand{ return true; } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_주민선정.php b/hwe/sammo/Command/General/che_주민선정.php index 85335d76..eefc3440 100644 --- a/hwe/sammo/Command/General/che_주민선정.php +++ b/hwe/sammo/Command/General/che_주민선정.php @@ -15,7 +15,8 @@ use function \sammo\{ getDomesticExpLevelBonus, CriticalRatioDomestic, CriticalScoreEx, - tryUniqueItemLottery + tryUniqueItemLottery, + updateMaxDomesticCritical }; use \sammo\Constraint\Constraint; @@ -150,6 +151,13 @@ class che_주민선정 extends Command\GeneralCommand{ $exp = $score * 0.7; $ded = $score * 1.0; + if($pick == 'success'){ + updateMaxDomesticCritical($general, $score); + } + else{ + $general->setAuxVar('max_domestic_critical', 0); + } + $score /= 10; $scoreText = number_format($score, 1); diff --git a/hwe/sammo/Command/Nation/che_물자원조.php b/hwe/sammo/Command/Nation/che_물자원조.php index 9bae2441..8e7cbef4 100644 --- a/hwe/sammo/Command/Nation/che_물자원조.php +++ b/hwe/sammo/Command/Nation/che_물자원조.php @@ -9,16 +9,17 @@ use \sammo\{ LastTurn, GameUnitConst, Command, + Json, + KVStorage, StringUtil }; -use function \sammo\{ - getDomesticExpLevelBonus, - CriticalRatioDomestic, - CriticalScoreEx, - getAllNationStaticInfo, - getNationStaticInfo -}; +use function \sammo\getDomesticExpLevelBonus; +use function \sammo\CriticalRatioDomestic; +use function \sammo\CriticalScoreEx; +use function \sammo\getAllNationStaticInfo; +use function \sammo\getNationStaticInfo; + use \sammo\Constraint\Constraint; use \sammo\Constraint\ConstraintHelper; @@ -223,7 +224,10 @@ class che_물자원조 extends Command\NationCommand{ $destNationLogger = new ActionLogger(0, $destChiefID, $year, $month); $destNationLogger->pushNationalHistoryLog("{$nationName}{$josaRoSrc}부터 금{$goldAmountText} 쌀{$riceAmountText}을 지원 받음"); - + $destNationStor = KVStorage::getStorage(DB::db(), $destNationID, 'nation_env'); + $destRecvAssist = $destNationStor->getValue('recv_assist')??[]; + $destRecvAssist["n{$nationID}"] = [$nationID, ($destRecvAssist["n{$nationID}"][1]??0) + $goldAmount + $riceAmount]; + $destNationStor->setValue('recv_assist', $destRecvAssist); $db->update('nation', [ 'gold'=>$db->sqleval('gold - %i', $goldAmount), diff --git a/hwe/sammo/Command/Nation/che_불가침수락.php b/hwe/sammo/Command/Nation/che_불가침수락.php index a739f77b..74972570 100644 --- a/hwe/sammo/Command/Nation/che_불가침수락.php +++ b/hwe/sammo/Command/Nation/che_불가침수락.php @@ -2,33 +2,31 @@ namespace sammo\Command\Nation; -use\sammo\{ - DB, - Util, - JosaUtil, - General, - DummyGeneral, - ActionLogger, - GameConst, - LastTurn, - GameUnitConst, - Command, - MessageTarget, - DiplomaticMessage, - Message, -}; +use \sammo\DB; +use \sammo\Util; +use \sammo\JosaUtil; +use \sammo\General; +use \sammo\DummyGeneral; +use \sammo\ActionLogger; +use \sammo\GameConst; +use \sammo\LastTurn; +use \sammo\GameUnitConst; +use \sammo\Command; +use \sammo\MessageTarget; +use \sammo\DiplomaticMessage; +use \sammo\Message; -use function\sammo\{ - getDomesticExpLevelBonus, - CriticalRatioDomestic, - CriticalScoreEx, - getAllNationStaticInfo, - getNationStaticInfo, - GetImageURL -}; +use function \sammo\getDomesticExpLevelBonus; +use function \sammo\CriticalRatioDomestic; +use function \sammo\CriticalScoreEx; +use function \sammo\getAllNationStaticInfo; +use function \sammo\getNationStaticInfo; +use function \sammo\GetImageUR; use \sammo\Constraint\Constraint; use \sammo\Constraint\ConstraintHelper; +use sammo\Json; +use sammo\KVStorage; class che_불가침수락 extends Command\NationCommand { @@ -191,6 +189,13 @@ class che_불가침수락 extends Command\NationCommand $destNationID = $destNation['nation']; $destNationName = $destNation['name']; + $destNationStor = KVStorage::getStorage(DB::db(), $destNationID, 'nation_env'); + $destRecvAssist = $destNationStor->getValue('recv_assist')??[]; + $destRespAssist = $destNationStor->getValue('resp_assist')??[]; + + $destRespAssist["n{$nationID}"] = [$nationID, $destRecvAssist["n{$nationID}"][1]??0]; + $destNationStor->setValue('resp_assist', $destRespAssist); + $year = $this->arg['year']; $month = $this->arg['month']; diff --git a/hwe/sammo/Constraint/AllowJoinDestNation.php b/hwe/sammo/Constraint/AllowJoinDestNation.php index d0b0dcdb..f7e9ac9b 100644 --- a/hwe/sammo/Constraint/AllowJoinDestNation.php +++ b/hwe/sammo/Constraint/AllowJoinDestNation.php @@ -50,6 +50,11 @@ class AllowJoinDestNation extends Constraint{ return false; } + if($this->general['npc']??2 < 2 && \sammo\Util::starts_with($this->destNation['name'], 'ⓤ')){ + $this->reason = "유저장은 태수국에 임관할 수 없습니다."; + return false; + } + $joinedNations = $this->general['auxVar']['joinedNations']??[]; if(in_array($this->destNation['nation'], $joinedNations)){ $this->reason = "이미 임관했었던 국가입니다."; diff --git a/hwe/sammo/Event/Action/RaiseNPCNation.php b/hwe/sammo/Event/Action/RaiseNPCNation.php new file mode 100644 index 00000000..d1de4ac6 --- /dev/null +++ b/hwe/sammo/Event/Action/RaiseNPCNation.php @@ -0,0 +1,282 @@ + $rhs['sum']; + }); + + + //최소, 최대 도시 몇개를 뺀다. 정렬은 신경쓰지 않는다. + + if ($cityCnt >= 3) { + $reduceCnt = Util::valueFit(Util::round($cityCnt / 6, 0), 1); + foreach (Util::range($reduceCnt) as $_idx) { + array_pop($targetCities); + } + + foreach (Util::range($reduceCnt) as $idx) { + $targetCities[$idx] = array_pop($targetCities); + } + + $cityCnt -= $reduceCnt * 2; + } + + $avgCity = []; + foreach ($targetCities as $city) { + foreach (static::CITY_KEYS as $key) { + $avgCity[$key] = ($avgCity[$key] ?? 0) + $city[$key]; + } + } + + foreach (static::CITY_KEYS as $key) { + $avgCity[$key] = Util::toInt($avgCity[$key] / $cityCnt); + } + return $avgCity; + } + + public function calcAvgNationGeneralCnt(): int + { + $nationUsers = []; + foreach (\sammo\getAllNationStaticInfo() as $nation) { + if ($nation['level'] == 0) { + continue; + } + $nationUsers[] = $nation['gennum']; + } + + $nationCnt = count($nationUsers); + if ($nationCnt == 0) { + return GameConst::$initialNationGenLimit; + } + + sort($nationUsers); + if ($nationCnt >= 3) { + $reduceCnt = Util::valueFit(Util::round($nationCnt / 6, 0), 1); + foreach (Util::range($reduceCnt) as $_idx) { + array_pop($nationUsers); + } + + foreach (Util::range($reduceCnt) as $idx) { + $nationUsers[$idx] = array_pop($nationUsers); + } + $nationCnt -= $reduceCnt * 2; + } + + return Util::round(array_sum($nationUsers) / $nationCnt); + } + + public function calcAvgTech(): int + { + $techSum = 0; + $nationCnt = 0; + foreach (\sammo\getAllNationStaticInfo() as $nation) { + if ($nation['level'] == 0) { + continue; + } + $techSum += $nation['tech']; + $nationCnt += 1; + } + if ($nationCnt == 0) { + return 0; + } + return Util::toInt($techSum / $nationCnt); + } + + private function buildNation(int $nationID, int $tech, array $baseCity, array $avgCity, int $genCnt, $env) + { + $db = DB::db(); + + $targetCity = [ + 'trust' => 100 + ]; + foreach (static::CITY_KEYS as $key) { + $targetCity[$key] = min($baseCity["{$key}_max"], $avgCity[$key]); + } + + $pickTypeList = ['무' => 1, '지' => 1]; + + $cityID = $baseCity['city']; + $cityName = $baseCity['name']; + $nationName = "ⓤ{$cityName}"; + + $color = Util::choiceRandom(GetNationColors()); + $nationObj = new Nation($nationID, $nationName, $color, 0, 2000, "우리도 할 수 있다! {$cityName}군", $tech, null, 2, [$cityName]); + $nationObj->build($env); + + $ruler = (new GeneralBuilder("{$cityName}태수", false, null, $nationID)) + ->setOfficerLevel(12) + ->setCityID($cityID) + ->setNPCType(6) + ->setGoldRice(1000, 1000) + ->fillRandomStat($pickTypeList) + ->setKillturn(240) + ->fillRemainSpecAsZero($env); + $ruler->build($env); + + $nationObj->addGeneral($ruler); + + $birthYear = $env['year'] - 20; + $deadYearMin = $env['year'] + 10; + + foreach (pickGeneralFromPool(DB::db(), 0, $genCnt - 1) as $pickedNPC) { + //대충 10년후부터 6년마다 절반? + $deadYear = $deadYearMin + Util::toInt(60 * (1 - log(Util::randRange(1, 1024), 2)/10)); + $newNPC = $pickedNPC->getGeneralBuilder(); + $newNPC->setNationID($nationID) + ->setCityID($cityID) + ->setNPCType(6) + ->setGoldRice(1000, 1000) + ->setLifeSpan($birthYear, $deadYear) + ->fillRandomStat($pickTypeList) + ->fillRemainSpecAsZero($env); + $newNPC->build($env); + $pickedNPC->occupyGeneralName(); + + $nationObj->addGeneral($newNPC); + } + + $nationObj->postBuild($env); + $db->update('city', $targetCity, 'city = %i', $cityID); + refreshNationStaticInfo(); + } + + public function run(array $env) + { + $db = DB::db(); + + $allCities = $db->query('SELECT * FROM city WHERE 5 <= level AND level <= 6'); //소, 중 성만 선택 + + $emptyCities = []; + $occupiedCities = []; + $npcCities = []; + + $avgCity = $this->calcAvgNationCity($allCities); + + foreach ($allCities as $city) { + if ($city['nation'] == 0) { + $emptyCities[$city['city']] = $city; + } else { + $occupiedCities[$city['city']] = $city; + } + } + + $avgGenCnt = $this->calcAvgNationGeneralCnt(); + + $serverID = UniqueConst::$serverID; + $lastNationID = max( + $db->queryFirstField("SELECT max(`nation`) FROM `nation`"), + $db->queryFirstField("SELECT max(`nation`) FROM `ng_old_nations` WHERE server_id = %s", $serverID), + ); + + $avgTech = $this->calcAvgTech(); + Util::shuffle_assoc($emptyCities); + + $occupiedCitiesID = array_keys($occupiedCities); + $npcCitiesID = []; + + refreshNationStaticInfo(); + + foreach ($emptyCities as $emptyCity) { + $cityID = $emptyCity['city']; + + $minDistance = 999; + foreach ($occupiedCitiesID as $targetCityID) { + $minDistance = min(\sammo\calcCityDistance($cityID, $targetCityID, null), $minDistance); + if ($minDistance < static::MIN_DIST_USERNATION) { + break; + } + } + if ($minDistance < static::MIN_DIST_USERNATION) { + continue; + } + + $minDistance = 999; + foreach ($npcCitiesID as $targetCityID) { + $minDistance = min(\sammo\calcCityDistance($cityID, $targetCityID, null), $minDistance); + if ($minDistance < static::MIN_DIST_NPCNATION) { + break; + } + } + if ($minDistance < static::MIN_DIST_NPCNATION) { + continue; + } + + //TODO: 거리 측정 + $lastNationID += 1; + $this->buildNation($lastNationID, $avgTech, $emptyCity, $avgCity, $avgGenCnt, $env); + $npcCities[$cityID] = $emptyCity; + $npcCitiesID[] = $cityID; + } + + if (count($npcCities) > 0) { + $logger = new ActionLogger(0, 0, $env['year'], $env['month']); + $logger->pushGlobalHistoryLog("【공지】공백지에 임의의 국가가 생성되었습니다."); + $logger->flush(); + } + + return [__CLASS__, count($npcCities)]; + } +} diff --git a/hwe/sammo/Event/Condition/Logic.php b/hwe/sammo/Event/Condition/Logic.php index f521e6f0..9e042606 100644 --- a/hwe/sammo/Event/Condition/Logic.php +++ b/hwe/sammo/Event/Condition/Logic.php @@ -1,6 +1,8 @@ mode = $mode; - $this->conditions = $conditions; + $this->conditions = array_map(function($condition){ + return Condition::build($condition); + }, $conditions); } public function eval($env=null){ diff --git a/hwe/sammo/General.php b/hwe/sammo/General.php index af7a2193..a957a811 100644 --- a/hwe/sammo/General.php +++ b/hwe/sammo/General.php @@ -50,6 +50,20 @@ class General implements iAction{ 'occupied'=>1, ]; + const INHERITANCE_KEY = [ + 'previous'=>[true, 1, '기존 포인트'], + 'lived_month'=>[true, 1, '생존'], + 'max_belong'=>[false, 10, '최대 임관년 수'], + 'max_domestic_critical'=>[true, 1, '최대 연속 내정 성공'], + 'snipe_combat'=>[true, 10, '병종 상성 우위 횟수'], + 'combat'=>[['rank', 'warnum'], 5, '전투 횟수'], + 'sabotage'=>[['rank', 'firenum'], 20, '계략 성공 횟수'], + 'unifier'=>[true, 1, '천통 기여'], + 'dex'=>[false, 0.001, '숙련도'], + 'tournament'=>[true, 1, '토너먼트'], + 'betting'=>[false, 10, '베팅 당첨'], + ]; + const TURNTIME_FULL_MS = -1; const TURNTIME_FULL = 0; const TURNTIME_HMS = 1; @@ -539,6 +553,8 @@ class General implements iAction{ $generalName = $this->getName(); + $this->mergeTotalInheritancePoint(); + // 군주였으면 유지 이음 $officerLevel = $this->getVar('officer_level'); if($officerLevel == 12) { @@ -592,6 +608,12 @@ class General implements iAction{ $generalName = $this->getName(); + $ownerID = $this->getVar('owner'); + if($ownerID){ + $this->mergeTotalInheritancePoint(); + resetInheritanceUser($ownerID); + } + $this->multiplyVarWithLimit('leadership', 0.85, 10); $this->multiplyVarWithLimit('strength', 0.85, 10); $this->multiplyVarWithLimit('intel', 0.85, 10); @@ -919,19 +941,19 @@ class General implements iAction{ static public function mergeQueryColumn(?array $reqColumns=null, int $constructMode=2):array{ $minimumColumn = ['no', 'name', 'city', 'nation', 'officer_level', 'officer_city']; $defaultEventColumn = [ - 'no', 'name', 'city', 'nation', 'officer_level', 'officer_city', + 'no', 'name', 'owner', 'city', 'nation', 'officer_level', 'officer_city', 'special', 'special2', 'personal', 'horse', 'weapon', 'book', 'item', 'last_turn' ]; $fullColumn = [ - 'no', 'name', 'owner_name', 'picture', 'imgsvr', 'nation', 'city', 'troop', 'injury', 'affinity', + 'no', 'name', 'owner', 'owner_name', 'picture', 'imgsvr', 'nation', 'city', 'troop', 'injury', 'affinity', 'leadership', 'leadership_exp', 'strength', 'strength_exp', 'intel', 'intel_exp', 'weapon', 'book', 'horse', 'item', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'crew', 'crewtype', 'train', 'atmos', 'turntime', 'makelimit', 'killturn', 'block', 'dedlevel', 'explevel', 'age', 'startage', 'belong', 'personal', 'special', 'special2', 'defence_train', 'tnmt', 'npc', 'npc_org', 'deadyear', 'npcmsg', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5', 'betray', 'recent_war', 'last_turn', 'myset', - 'specage', 'specage2', 'con', 'connect', 'owner', 'aux', 'lastrefresh', + 'specage', 'specage2', 'con', 'connect', 'aux', 'lastrefresh', ]; if($reqColumns === null){ @@ -1141,4 +1163,186 @@ class General implements iAction{ } return $result; } + + /** + * @return int|float + */ + public function getInheritancePoint(string $key, &$aux=null, bool $forceCalc=false){ + $inheritType = static::INHERITANCE_KEY[$key]??null; + if($inheritType === null){ + throw new \OutOfRangeException("{$key}는 유산 타입이 아님"); + } + + $ownerID = $this->getVar('owner'); + if(!$ownerID){ + return 0; + } + + if($this->getVar('npc') != 0){ + return 0; + } + + [$storeType, $multiplier, ] = $inheritType; + + $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); + if($storeType === true || ($gameStor->isunited != 0 && !$forceCalc)){ + $inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$ownerID}"); + [$value, $aux] = $inheritStor->getValue($key); + return $value; + } + + if(is_array($storeType)){ + [$storSubType, $storSubKey] = $storeType; + if($storSubType === 'rank'){ + return $this->getRankVar($storSubKey) * $multiplier; + } + if($storSubType === 'raw'){ + return $this->getVar($storSubKey) * $multiplier; + } + if($storSubType === 'aux'){ + return ($this->getAuxVar($storSubKey)??0) * $multiplier; + } + throw new \InvalidArgumentException("{$storSubType}은 참조 할 수 없는 유산 세부키임"); + } + + if($storeType !== false){ + throw new \InvalidArgumentException("{$storeType}은 올바르지 않은 유산 키임"); + } + + $extractFn = function(){ return [0, null];}; + switch($key){ + case 'dex': + $extractFn = function() use ($multiplier){ + $totalDex = 0; + foreach(array_keys(GameUnitConst::allType()) as $armType){ + $totalDex += $this->getVar("dex{$armType}"); + } + return [$totalDex * $multiplier, null]; + }; + break; + case 'betting': + $extractFn = function() use ($multiplier){ + $betWin = $this->getRankVar('betwin'); + $betWinRate = $this->getRankVar('betwingold')/max(1, $this->getRankVar('betgold')); + + return [$betWin * $multiplier * pow($betWinRate, 2), null]; + }; + break; + case 'max_belong': + $extractFn = function() use ($multiplier){ + $maxBelong = max($this->getVar('belong'), $this->getAuxVar('max_belong')??0); + return [$maxBelong * $multiplier, null]; + }; + break; + default: + throw new \InvalidArgumentException("{$key}는 유산 추출기를 보유하고 있지 않음"); + } + + [$value, $aux] = ($extractFn)(); + return $value; + } + + public function setInheritancePoint(string $key, $value, $aux=null){ + if(!is_int($value) && !is_float($value)){ + throw new \InvalidArgumentException("{$value}는 숫자가 아님"); + } + $inheritType = static::INHERITANCE_KEY[$key]??null; + if($inheritType === null){ + throw new \OutOfRangeException("{$key}는 유산 타입이 아님"); + } + + [$storeType, $multiplier, ] = $inheritType; + if($storeType !== true){ + throw new \InvalidArgumentException("{$key}는 직접 저장형 유산 포인트가 아님"); + } + if($multiplier != 1 && $value != 0){ + throw new \InvalidArgumentException("{$key}는 1:1 유산 포인트가 아님"); + } + + $ownerID = $this->getVar('owner'); + if(!$ownerID){ + return; + } + + if($this->getVar('npc') != 0){ + return; + } + + $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); + if($gameStor->isunited != 0){ + return; + } + + $inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$ownerID}"); + $inheritStor->setValue($key, [$value, $aux]); + } + + public function increaseInheritancePoint(string $key, $value, $aux=null){ + if(!is_int($value) && !is_float($value)){ + throw new \InvalidArgumentException("{$value}는 숫자가 아님"); + } + + $inheritType = static::INHERITANCE_KEY[$key]??null; + if($inheritType === null){ + throw new \OutOfRangeException("{$key}는 유산 타입이 아님"); + } + + [$storeType, $multiplier, ] = $inheritType; + if($storeType !== true){ + throw new \InvalidArgumentException("{$key}는 직접 저장형 유산 포인트가 아님"); + } + + $ownerID = $this->getVar('owner'); + if(!$ownerID){ + return; + } + + if($this->getVar('npc') != 0){ + return; + } + + $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); + if($gameStor->isunited != 0){ + return; + } + + $inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$ownerID}"); + [$oldValue, $oldAux] = $inheritStor->getValue($key)??[0, null]; + + if($oldAux !== $aux){ + $oldValue = 0; + } + + $newValue = $oldValue + $value * $multiplier; + $inheritStor->setValue($key, [$newValue, $aux]); + } + + public function mergeTotalInheritancePoint(){ + $ownerID = $this->getVar('owner'); + if(!$ownerID){ + return; + } + + if($this->getVar('npc') != 0){ + return; + } + + $inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$ownerID}"); + $inheritStor->cacheAll(); + foreach(static::INHERITANCE_KEY as $key=>[$storType, ,]){ + $aux = null; + $point = $this->getInheritancePoint($key, $aux, true); + if($storType === true){ + continue; + } + $inheritStor->setValue($key, [$point, $aux]); + } + + $oldInheritStor = KVStorage::getStorage(DB::db(), "inheritance_result"); + $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); + $serverID = UniqueConst::$serverID; + $year = $gameStor->year; + $month = $gameStor->month; + $oldInheritStor->setValue("{$serverID}_{$ownerID}_{$this->getID()}_{$year}_{$month}", $inheritStor->getAll(true)); + } } \ No newline at end of file diff --git a/hwe/sammo/GeneralAI.php b/hwe/sammo/GeneralAI.php index 29b679b6..511cf223 100644 --- a/hwe/sammo/GeneralAI.php +++ b/hwe/sammo/GeneralAI.php @@ -1712,6 +1712,88 @@ class GeneralAI return $cmd; } + // 군주 행동 + protected function do불가침제의(LastTurn $lastTurn): ?NationCommand + { + $general = $this->general; + + if($general->getVar('officer_level') < 12){ + return null; + } + + $nation = $this->nation; + $nationID = $nation['nation']; + + $nationStor = KVStorage::getStorage(DB::db(), $nationID, 'nation_env'); + $recvAssist = $nationStor->getValue('recv_assist')??[]; + $respAssist = $nationStor->getValue('resp_assist')??[]; + $respAssistTry = $nationStor->getValue('resp_assist_try')??[]; + + $yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']); + + $candidateList = []; + foreach($recvAssist as [$candNationID, $amount]){ + $amount -= $respAssist["n{$candNationID}"][1]??0; + if($amount <= 0){ + continue; + } + if(key_exists($candNationID, $this->warTargetNation)){ + continue; + } + if(($respAssistTry["n{$candNationID}"][1]??0) >= $yearMonth - 8){ + continue; + } + $candidateList[$candNationID] = $amount; + } + + if(!$candidateList){ + return null; + } + + $cityList = $this->supplyCities; + + if (!$cityList) { + return null; + } + + $goldIncome = getGoldIncome($nation['nation'], $nation['level'], 15, $nation['capital'], $nation['type'], $cityList); + $riceIncome = getRiceIncome($nation['nation'], $nation['level'], 15, $nation['capital'], $nation['type'], $cityList); + $wallIncome = getWallIncome($nation['nation'], $nation['level'], 15, $nation['capital'], $nation['type'], $cityList); + $income = $goldIncome + $riceIncome + $wallIncome; + + arsort($candidateList); + $destNationID = null; + $diplomatMonth = 0; + foreach($candidateList as $candNationID => $amount){ + if($amount * 4 < $income){ + break; + } + $destNationID = $candNationID; + $diplomatMonth = 24 * $amount / $income; + break; + } + + if($destNationID === null){ + return null; + } + + + [$targetYear, $targetMonth] = Util::parseYearMonth($yearMonth + $diplomatMonth); + + $cmd = buildNationCommandClass('che_불가침제의', $this->general, $this->env, $lastTurn, [ + 'destNationID' => $destNationID, + 'year' => $targetYear, + 'month' => $targetMonth, + ]); + if(!$cmd->hasFullConditionMet()){ + return null; + } + + $respAssistTry["n{$destNationID}"] = [$destNationID, $yearMonth]; + $nationStor->setValue('resp_assist_try', $respAssistTry); + + return $cmd; + } // 군주 행동 protected function do선전포고(LastTurn $lastTurn): ?NationCommand @@ -3067,6 +3149,9 @@ class GeneralAI if($general->getVar('makelimit')){ return null; } + if($general->getNPCType() > 2){ + return null; + } if(!$this->generalPolicy->can건국){ return null; } @@ -3167,8 +3252,7 @@ class GeneralAI return null; } - if (Util::randBool(pow(1 / $nationCnt / pow($notFullNationCnt, 3), 1 / 4))) { - //국가가 1개일 경우에는 '임관하지 않음' + if (Util::randBool(pow(1 / ($nationCnt + 1) / pow($notFullNationCnt, 3), 1 / 4))) { return null; } } diff --git a/hwe/sammo/Scenario/Nation.php b/hwe/sammo/Scenario/Nation.php index b8a8ad95..4ddfc83a 100644 --- a/hwe/sammo/Scenario/Nation.php +++ b/hwe/sammo/Scenario/Nation.php @@ -76,7 +76,10 @@ class Nation{ $capital = 0; } - if(strpos($this->type, '_') === FALSE){ + if($this->type === null){ + $type = Util::choiceRandom(GameConst::$availableNationType); + } + else if(strpos($this->type, '_') === FALSE){ $type = 'che_'.$this->type; } else{ diff --git a/hwe/sammo/TurnExecutionHelper.php b/hwe/sammo/TurnExecutionHelper.php index 50d051d7..077e4ac2 100644 --- a/hwe/sammo/TurnExecutionHelper.php +++ b/hwe/sammo/TurnExecutionHelper.php @@ -257,6 +257,8 @@ class TurnExecutionHelper $autorunMode = false; $ai = null; + $general->increaseInheritancePoint('lived_month', 1); + $turnObj->preprocessCommand($env); $generalCommandObj = $general->getReservedTurn(0, $env); diff --git a/hwe/scenario/scenario_0.json b/hwe/scenario/scenario_0.json index 143f1bb6..d44a61f1 100644 --- a/hwe/scenario/scenario_0.json +++ b/hwe/scenario/scenario_0.json @@ -5,5 +5,17 @@ ], "const": { "joinRuinedNPCProp":0 - } + }, + "events":[ + [ + ["or", ["Date", "==", null, 12], ["Date", "==", null, 6]], + ["CreateManyNPC", 30], + ["DeleteEvent"] + ], + [ + ["Date", "==", 181, 1], + ["RaiseNPCNation"], + ["DeleteEvent"] + ] + ] } \ No newline at end of file diff --git a/hwe/scenario/scenario_1.json b/hwe/scenario/scenario_1.json index 5a7161e5..31f45dd6 100644 --- a/hwe/scenario/scenario_1.json +++ b/hwe/scenario/scenario_1.json @@ -8,5 +8,17 @@ ], "const": { "joinRuinedNPCProp":0 - } + }, + "events":[ + [ + ["or", ["Date", "==", null, 12], ["Date", "==", null, 6]], + ["CreateManyNPC", 30], + ["DeleteEvent"] + ], + [ + ["Date", "==", 181, 1], + ["RaiseNPCNation"], + ["DeleteEvent"] + ] + ] } \ No newline at end of file diff --git a/hwe/scenario/scenario_2.json b/hwe/scenario/scenario_2.json index fcffdf98..e6f8f410 100644 --- a/hwe/scenario/scenario_2.json +++ b/hwe/scenario/scenario_2.json @@ -15,9 +15,14 @@ }, "events":[ [ - ["Date", "==", null, 12], + ["or", ["Date", "==", null, 12], ["Date", "==", null, 6]], ["CreateManyNPC", 30], ["DeleteEvent"] + ], + [ + ["Date", "==", 181, 1], + ["RaiseNPCNation"], + ["DeleteEvent"] ] ] } \ No newline at end of file diff --git a/hwe/templates/commandButton.php b/hwe/templates/commandButton.php index 5aae5dad..045813af 100644 --- a/hwe/templates/commandButton.php +++ b/hwe/templates/commandButton.php @@ -16,7 +16,7 @@ - + diff --git a/hwe/ts/inheritPoint.ts b/hwe/ts/inheritPoint.ts new file mode 100644 index 00000000..07f01e30 --- /dev/null +++ b/hwe/ts/inheritPoint.ts @@ -0,0 +1,38 @@ +import { sum } from "lodash"; +import { unwrap } from "./util"; +declare global { + interface Window { + formStart: ()=>void; + items: {[name: string]:number}; + helpText: {[name: string]:string}; + } +} + +export {} + +function formStart() { + + const dSum = unwrap(document.querySelector('#inherit_sum_value')) as HTMLInputElement ; + const dOld = unwrap(document.querySelector('#inherit_previous_value')) as HTMLInputElement; + const dNew = unwrap(document.querySelector('#inherit_new_value')) as HTMLInputElement; + + const sumPoint = Math.floor(sum(Object.values(window.items))); + const oldPoint = Math.floor(window.items['previous']); + const sumNewPoint = sumPoint - oldPoint; + + dSum.value = sumPoint.toLocaleString(); + dOld.value = oldPoint.toLocaleString(); + dNew.value = sumNewPoint.toLocaleString(); + + for(const [key, val] of Object.entries(window.items)){ + const dItem = unwrap(document.querySelector(`#inherit_${key}_value`)) as HTMLInputElement ; + dItem.value = Math.floor(val).toLocaleString(); + } + + for(const [key, text] of Object.entries(window.helpText)){ + const dText = unwrap(document.querySelector(`#inherit_${key} small.form-text`)) as HTMLElement; + dText.innerHTML = text; + } +} + +window.formStart = formStart; \ No newline at end of file diff --git a/hwe/ts/util.ts b/hwe/ts/util.ts new file mode 100644 index 00000000..99a04ab5 --- /dev/null +++ b/hwe/ts/util.ts @@ -0,0 +1,35 @@ +type ErrType = { new(msg?: string): T } +type Nullable = T | null | undefined + +export class RuntimeError extends Error { + public name = 'RuntimeError'; + constructor(public message: string = '') { + super(message); + } + toString(): string { + if (this.message) { + return this.name + ': ' + this.message; + } + else { + return this.name; + } + } +} + +export class NotNullExpected extends RuntimeError { + public name = 'NotNullExpected'; +} + +export function unwrap(result: Nullable): T { + if (result === null || result === undefined) { + throw new NotNullExpected(); + } + return result; +} + +export function unwrap_err(result: Nullable, errType: ErrType, errMsg?: string): T { + if (result === null || result === undefined) { + throw new errType(errMsg); + } + return result; +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..698f6880 --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "hidche_lib", + "version": "1.0.0", + "description": "", + "main": "js/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack", + "lint": "eslint hwe/ts ts" + }, + "repository": { + "type": "git", + "url": "ssh://git@storage.hided.net:2525/devsam/core.git" + }, + "author": "Hide_D", + "license": "MIT", + "dependencies": { + "@types/lodash": "^4.14.172", + "lodash": "^4.17.21" + }, + "devDependencies": { + "@babel/cli": "^7.14.8", + "@babel/core": "^7.15.0", + "@babel/preset-env": "^7.15.0", + "@babel/preset-typescript": "^7.15.0", + "@typescript-eslint/eslint-plugin": "^4.29.1", + "@typescript-eslint/parser": "^4.29.1", + "babel-loader": "^8.2.2", + "babel-plugin-lodash": "^3.3.4", + "eslint": "^7.32.0", + "pre-commit": "^1.2.2", + "typescript": "^4.3.5", + "webpack": "^5.49.0", + "webpack-cli": "^4.7.2" + }, + "pre-commit": [ + "lint" + ] +} diff --git a/ts/common_path.d.ts b/ts/common_path.d.ts new file mode 100644 index 00000000..05260e4b --- /dev/null +++ b/ts/common_path.d.ts @@ -0,0 +1,7 @@ +interface Window { + pathConfig: { + root: string, + sharedIcon: string, + gameImage: string, + } +} \ No newline at end of file diff --git a/ts/util.ts b/ts/util.ts new file mode 100644 index 00000000..99a04ab5 --- /dev/null +++ b/ts/util.ts @@ -0,0 +1,35 @@ +type ErrType = { new(msg?: string): T } +type Nullable = T | null | undefined + +export class RuntimeError extends Error { + public name = 'RuntimeError'; + constructor(public message: string = '') { + super(message); + } + toString(): string { + if (this.message) { + return this.name + ': ' + this.message; + } + else { + return this.name; + } + } +} + +export class NotNullExpected extends RuntimeError { + public name = 'NotNullExpected'; +} + +export function unwrap(result: Nullable): T { + if (result === null || result === undefined) { + throw new NotNullExpected(); + } + return result; +} + +export function unwrap_err(result: Nullable, errType: ErrType, errMsg?: string): T { + if (result === null || result === undefined) { + throw new errType(errMsg); + } + return result; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..9d503991 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,72 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ + "module": "ESNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "../js", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + "rootDirs": ["./ts", "./hwe/ts"], /* List of root folders whose combined content represents the structure of the project at runtime. */ + //"typeRoots": ["./typings"], /* List of folders to include type definitions from. */ + //"types": ["ts/common_path.d.ts"], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..f8e4e6ba --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,64 @@ +const path = require('path'); + +module.exports = [ + { + name: 'ingame', + resolve: { + extensions: [".js", ".ts", ".tsx"] + }, + entry: { + inheritPoint: './hwe/ts/inheritPoint.ts', + }, + output: { + filename: '[name].js', + path: path.resolve(__dirname, 'hwe/js'), + }, + mode: 'production', + devtool: 'source-map', + module: { + rules: [{ + test: /\.(ts|tsx)$/, + exclude: /(node_modules)/, + use: { + loader: 'babel-loader', + options: { + presets: [ + '@babel/preset-env', + '@babel/preset-typescript' + ] + } + } + }] + }, + }, + { + name: 'gateway', + resolve: { + extensions: [".js", ".ts", ".tsx"] + }, + entry: { + //test: './ts/test.ts', + }, + output: { + filename: '[name].js', + path: path.resolve(__dirname, 'js'), + }, + mode: 'none', + devtool: 'source-map', + module: { + rules: [{ + test: /\.(ts|tsx)$/, + exclude: /(node_modules)/, + use: { + loader: 'babel-loader', + options: { + presets: [ + '@babel/preset-env', + '@babel/preset-typescript' + ] + } + } + }] + }, + }, +]