feat: 턴 당기기, 턴 미루기 사령턴
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\Command\Nation;
|
||||
|
||||
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\Constraint\Constraint;
|
||||
use \sammo\Constraint\ConstraintHelper;
|
||||
use sammo\Enums\GeneralQueryMode;
|
||||
use sammo\StaticEventHandler;
|
||||
|
||||
use function sammo\pullGeneralCommand;
|
||||
use function sammo\pushGeneralCommand;
|
||||
|
||||
class che_행동지시 extends Command\NationCommand
|
||||
{
|
||||
static protected $actionName = '행동 지시';
|
||||
static public $reqArg = true;
|
||||
|
||||
protected function argTest(): bool
|
||||
{
|
||||
if ($this->arg === null) {
|
||||
return false;
|
||||
}
|
||||
if (!key_exists('isPull', $this->arg)) {
|
||||
return false;
|
||||
}
|
||||
if (!key_exists('amount', $this->arg)) {
|
||||
return false;
|
||||
}
|
||||
if (!key_exists('destGeneralID', $this->arg)) {
|
||||
return false;
|
||||
}
|
||||
$isPull = $this->arg['isPull'];
|
||||
$amount = $this->arg['amount'];
|
||||
$destGeneralID = $this->arg['destGeneralID'];
|
||||
if (!is_numeric($amount)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($amount <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (!is_bool($isPull)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_int($destGeneralID)) {
|
||||
return false;
|
||||
}
|
||||
if ($destGeneralID <= 0) {
|
||||
return false;
|
||||
}
|
||||
$amount = Util::clamp($amount, 1, 5);
|
||||
|
||||
$this->arg = [
|
||||
'isPull' => $isPull,
|
||||
'amount' => $amount,
|
||||
'destGeneralID' => $destGeneralID
|
||||
];
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
$general = $this->generalObj;
|
||||
|
||||
$this->setCity();
|
||||
$this->setNation();
|
||||
|
||||
$this->minConditionConstraints = [
|
||||
ConstraintHelper::NotBeNeutral(),
|
||||
ConstraintHelper::OccupiedCity(),
|
||||
ConstraintHelper::BeChief(),
|
||||
ConstraintHelper::SuppliedCity(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function initWithArg()
|
||||
{
|
||||
$destGeneral = General::createObjFromDB($this->arg['destGeneralID']);
|
||||
$this->setDestGeneral($destGeneral);
|
||||
|
||||
if($this->arg['destGeneralID'] == $this->getGeneral()->getID()){
|
||||
$this->fullConditionConstraints=[
|
||||
ConstraintHelper::AlwaysFail('본인입니다')
|
||||
];
|
||||
return;
|
||||
}
|
||||
|
||||
$this->fullConditionConstraints = [
|
||||
ConstraintHelper::NotBeNeutral(),
|
||||
ConstraintHelper::OccupiedCity(),
|
||||
ConstraintHelper::BeChief(),
|
||||
ConstraintHelper::SuppliedCity(),
|
||||
ConstraintHelper::ExistsDestGeneral(),
|
||||
ConstraintHelper::FriendlyDestGeneral()
|
||||
];
|
||||
}
|
||||
|
||||
public function getCost(): array
|
||||
{
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
public function getPreReqTurn(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getPostReqTurn(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getBrief(): string
|
||||
{
|
||||
$isPull = $this->arg['isPull'];
|
||||
$amount = $this->arg['amount'];
|
||||
$actSpecificName = $isPull ? '당기기' : '미루기';
|
||||
$destGeneral = $this->destGeneralObj;
|
||||
return "【{$destGeneral->getName()}】 {$amount}턴 {$actSpecificName}";
|
||||
}
|
||||
|
||||
|
||||
public function run(\Sammo\RandUtil $rng): bool
|
||||
{
|
||||
if (!$this->hasFullConditionMet()) {
|
||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$general = $this->generalObj;
|
||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||
|
||||
$isPull = $this->arg['isPull'];
|
||||
$amount = $this->arg['amount'];
|
||||
$destGeneral = $this->destGeneralObj;
|
||||
|
||||
if($isPull){
|
||||
pullGeneralCommand($destGeneral->getID(), $amount);
|
||||
}
|
||||
else{
|
||||
pushGeneralCommand($destGeneral->getID(), $amount);
|
||||
}
|
||||
|
||||
$logger = $general->getLogger();
|
||||
|
||||
$actDestText = $isPull ? '당겼습니다.' : '미루었습니다.';
|
||||
$actText = $isPull ? '당기도록' : '미루도록';
|
||||
$destGeneral->getLogger()->pushGeneralActionLog("<Y>{$general->getName()}</>의 지시로 <C>{$amount}</>턴을 {$actDestText}", ActionLogger::PLAIN);
|
||||
$logger->pushGeneralActionLog("<Y>{$destGeneral->getName()}</>에게 <C>{$amount}</>턴을 {$actText} 지시했습니다. <1>$date</>");
|
||||
|
||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||
StaticEventHandler::handleEvent($this->generalObj, $this->destGeneralObj, $this::class, $this->env, $this->arg ?? []);
|
||||
$general->applyDB($db);
|
||||
$destGeneral->applyDB($db);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function exportJSVars(): array
|
||||
{
|
||||
$db = DB::db();
|
||||
$nationID = $this->getNationID();
|
||||
$troops = Util::convertArrayToDict($db->query('SELECT * FROM troop WHERE nation=%i', $nationID), 'troop_leader');
|
||||
$destRawGenerals = Util::convertArrayToDict($db->queryAllLists('SELECT no,name,officer_level,npc,gold,rice,leadership,strength,intel,city,crew,train,atmos,troop FROM general WHERE nation = %i ORDER BY npc,binary(name)', $nationID), 0);
|
||||
|
||||
if($destRawGenerals){
|
||||
foreach ($db->queryAllLists(
|
||||
'SELECT general_id, brief FROM general_turn WHERE general_id IN %li AND turn_idx = 0',
|
||||
array_keys($destRawGenerals)
|
||||
) as [$generalID, $brief]) {
|
||||
if (!key_exists($generalID, $destRawGenerals)) {
|
||||
continue;
|
||||
}
|
||||
$destRawGenerals[$generalID][] = $brief;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return [
|
||||
'procRes' => [
|
||||
'troops' => $troops,
|
||||
'generals' => array_values($destRawGenerals),
|
||||
'generalsKey' => ['no', 'name', 'officerLevel', 'npc', 'gold', 'rice', 'leadership', 'strength', 'intel', 'cityID', 'crew', 'train', 'atmos', 'troopID', 'turn0Brief'],
|
||||
'cities' => \sammo\JSOptionsForCities(),
|
||||
'amountGuide' => [1, 2, 3, 4, 5],
|
||||
'minAmount' => 1,
|
||||
'maxAmount' => 5,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -384,6 +384,7 @@ class GameConstBase
|
||||
'che_포상',
|
||||
'che_몰수',
|
||||
'che_부대탈퇴지시',
|
||||
'che_행동지시',
|
||||
],
|
||||
'외교' => [
|
||||
'che_물자원조',
|
||||
|
||||
@@ -10,7 +10,6 @@ import { default as che_장수대상임관 } from "./che_장수대상임관.vue"
|
||||
import { default as che_징병 } from "./che_징병.vue";
|
||||
import { default as che_헌납 } from "./che_헌납.vue";
|
||||
import { default as cr_건국 } from "./cr_건국.vue";
|
||||
|
||||
import { default as ProcessCity } from "../ProcessCity.vue";
|
||||
import { default as ProcessGeneralAmount } from "../ProcessGeneralAmount.vue";
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<TopBackBar v-model:searchable="searchable" :title="commandName" :type="procEntryMode" />
|
||||
<div class="bg0">
|
||||
<div>장수에게 턴을 당기거라 미루라고 지시합니다.</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-5">
|
||||
장수 :
|
||||
<SelectGeneral
|
||||
v-model="selectedGeneralID"
|
||||
:cities="citiesMap"
|
||||
:generals="generalList"
|
||||
:textHelper="textHelpGeneral"
|
||||
:searchable="searchable"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-2 col-lg-2">
|
||||
턴 :
|
||||
<b-button-group>
|
||||
<b-button :pressed="isPull" @click="isPull = true"> 당기기 </b-button>
|
||||
<b-button :pressed="!isPull" @click="isPull = false"> 미루기 </b-button>
|
||||
</b-button-group>
|
||||
</div>
|
||||
<div class="col-7 col-lg-3">
|
||||
<SelectAmount v-model="amount" :amountGuide="amountGuide" :maxAmount="maxAmount" :minAmount="minAmount" />
|
||||
</div>
|
||||
<div class="col-3 col-lg-2 d-grid">
|
||||
<b-button variant="primary" @click="submit">
|
||||
{{ commandName }}
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<BottomBar :title="commandName" :type="procEntryMode" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
declare const procRes: {
|
||||
distanceList: Record<number, number[]>;
|
||||
cities: [number, string][];
|
||||
generals: procGeneralRawItemList;
|
||||
generalsKey: procGeneralKey[];
|
||||
minAmount: number;
|
||||
maxAmount: number;
|
||||
amountGuide: number[];
|
||||
};
|
||||
|
||||
declare const staticValues: {
|
||||
commandName: string;
|
||||
entryInfo: ["General" | "Nation", unknown];
|
||||
};
|
||||
</script>
|
||||
<script setup lang="ts">
|
||||
import SelectGeneral from "@/processing/SelectGeneral.vue";
|
||||
import SelectAmount from "@/processing/SelectAmount.vue";
|
||||
import { ref } from "vue";
|
||||
import { unwrap } from "@/util/unwrap";
|
||||
import type { Args } from "@/processing/args";
|
||||
import TopBackBar from "@/components/TopBackBar.vue";
|
||||
import BottomBar from "@/components/BottomBar.vue";
|
||||
import {
|
||||
convertGeneralList,
|
||||
getProcSearchable,
|
||||
type procGeneralItem,
|
||||
type procGeneralKey,
|
||||
type procGeneralRawItemList,
|
||||
} from "@/processing/processingRes";
|
||||
import { getNPCColor } from "@/utilGame";
|
||||
|
||||
const citiesMap = ref(
|
||||
new Map<
|
||||
number,
|
||||
{
|
||||
name: string;
|
||||
info?: string;
|
||||
}
|
||||
>()
|
||||
);
|
||||
for (const [id, name] of procRes.cities) {
|
||||
citiesMap.value.set(id, { name });
|
||||
}
|
||||
|
||||
const generalList = convertGeneralList(procRes.generalsKey, procRes.generals);
|
||||
const amount = ref(1);
|
||||
const isPull = ref(true);
|
||||
|
||||
const selectedGeneralID = ref(generalList[0].no);
|
||||
|
||||
type procGeneralItemWithTurn0Brief = procGeneralItem & {
|
||||
turn0Brief: string;
|
||||
};
|
||||
|
||||
function textHelpGeneral(_gen: procGeneralItem): string {
|
||||
const gen = _gen as procGeneralItemWithTurn0Brief;
|
||||
const nameColor = getNPCColor(gen.npc);
|
||||
const name = nameColor ? `<span style="color:${nameColor}">${gen.name}</span>` : gen.name;
|
||||
return `${name} [${citiesMap.value.get(unwrap(gen.cityID))?.name}] (${gen.leadership}/${gen.strength}/${
|
||||
gen.intel
|
||||
}) (${gen.turn0Brief})`;
|
||||
}
|
||||
|
||||
async function submit(e: Event) {
|
||||
const event = new CustomEvent<Args>("customSubmit", {
|
||||
detail: {
|
||||
amount: amount.value,
|
||||
isPull: isPull.value,
|
||||
destGeneralID: selectedGeneralID.value,
|
||||
},
|
||||
});
|
||||
unwrap(e.target).dispatchEvent(event);
|
||||
}
|
||||
|
||||
const { commandName, entryInfo } = staticValues;
|
||||
const searchable = getProcSearchable();
|
||||
|
||||
const procEntryMode: "chief" | "normal" = entryInfo[0] == "Nation" ? "chief" : "normal";
|
||||
|
||||
const { minAmount, maxAmount, amountGuide } = procRes;
|
||||
</script>
|
||||
@@ -3,6 +3,7 @@ import { default as che_국호변경 } from "./che_국호변경.vue";
|
||||
import { default as che_물자원조 } from "./che_물자원조.vue";
|
||||
import { default as che_불가침제의 } from "./che_불가침제의.vue";
|
||||
import { default as che_피장파장 } from "./che_피장파장.vue";
|
||||
import { default as che_행동지시 } from "./che_행동지시.vue";
|
||||
|
||||
import { default as cr_인구이동 } from "./cr_인구이동.vue";
|
||||
|
||||
@@ -33,6 +34,7 @@ export const commandMap: Record<string, typeof ProcessNation | typeof ProcessCit
|
||||
che_피장파장,
|
||||
che_허보: ProcessCity,
|
||||
cr_인구이동,
|
||||
che_행동지시,
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -13,7 +13,7 @@ const intArgs = [
|
||||
] as const;
|
||||
|
||||
const booleanArgs = [
|
||||
'isGold', 'buyRice',
|
||||
'isGold', 'buyRice', 'isPull',
|
||||
] as const;
|
||||
|
||||
const integerArrayArgs = [
|
||||
|
||||
Reference in New Issue
Block a user