vue: join
This commit is contained in:
+1
-1
@@ -2345,7 +2345,7 @@ function getRandTurn($term, ?\DateTimeInterface $baseDateTime = null)
|
|||||||
$randSecond = Util::randRangeInt(0, 60 * $term - 1);
|
$randSecond = Util::randRangeInt(0, 60 * $term - 1);
|
||||||
$randFraction = Util::randRangeInt(0, 999999) / 1000000; //6자리 소수
|
$randFraction = Util::randRangeInt(0, 999999) / 1000000; //6자리 소수
|
||||||
|
|
||||||
return $baseDateTime->add(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s.u');
|
return TimeUtil::format($baseDateTime->add(TimeUtil::secondsToDateInterval($randSecond + $randFraction)), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandTurn2($term, ?\DateTimeInterface $baseDateTime = null)
|
function getRandTurn2($term, ?\DateTimeInterface $baseDateTime = null)
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ function getAPIExecutorClass($path){
|
|||||||
throw new \InvalidArgumentException("{$path}는 올바른 API 지시자가 아님");
|
throw new \InvalidArgumentException("{$path}는 올바른 API 지시자가 아님");
|
||||||
}
|
}
|
||||||
|
|
||||||
$classPath = ($basePath.$path);
|
$classPath = str_replace('/', '\\', $basePath.$path);
|
||||||
|
|
||||||
if(class_exists($classPath)){
|
if(class_exists($classPath)){
|
||||||
return $classPath;
|
return $classPath;
|
||||||
@@ -377,7 +377,7 @@ function getAPIExecutorClass($path){
|
|||||||
throw new \InvalidArgumentException("{$path}는 올바른 API 경로가 아님");
|
throw new \InvalidArgumentException("{$path}는 올바른 API 경로가 아님");
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildAPIExecutorClass(string $type, string $rootPath, array $args):\sammo\BaseAPI{
|
function buildAPIExecutorClass($type, string $rootPath, array $args):\sammo\BaseAPI{
|
||||||
$class = getAPIExecutorClass($type);
|
$class = getAPIExecutorClass($type);
|
||||||
return new $class($rootPath, $args);
|
return new $class($rootPath, $args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1158,13 +1158,13 @@ function resetInheritanceUser(int $userID, bool $isRebirth=false):float{
|
|||||||
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
|
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
|
||||||
$totalPoint = 0;
|
$totalPoint = 0;
|
||||||
$allPoints = $inheritStor->getAll();
|
$allPoints = $inheritStor->getAll();
|
||||||
if(count($allPoints) == 0){
|
if(!$allPoints || count($allPoints) == 0){
|
||||||
//비었으므로 리셋 안함
|
//비었으므로 리셋 안함
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(count($allPoints) == 1 && key_exists('previous', $allPoints)){
|
if(count($allPoints) == 1 && key_exists('previous', $allPoints)){
|
||||||
//이미 리셋되었으므로 리셋 안함
|
//이미 리셋되었으므로 리셋 안함
|
||||||
return $allPoints['previous'];
|
return $allPoints['previous'][0];
|
||||||
}
|
}
|
||||||
foreach($allPoints as $key=>[$value,]){
|
foreach($allPoints as $key=>[$value,]){
|
||||||
if($isRebirth && key_exists($key, $rebirthDegraded)){
|
if($isRebirth && key_exists($key, $rebirthDegraded)){
|
||||||
|
|||||||
+2
-2
@@ -111,7 +111,7 @@ if ($inheritBonusStat) {
|
|||||||
dieMsg("보너스 능력치가 잘못 지정되었습니다. 다시 가입해주세요!");
|
dieMsg("보너스 능력치가 잘못 지정되었습니다. 다시 가입해주세요!");
|
||||||
}
|
}
|
||||||
$sum = array_sum($inheritBonusStat);
|
$sum = array_sum($inheritBonusStat);
|
||||||
if ($sum < 3 || $sum > 5) {
|
if ($sum < GameConst::$bornMinStatBonus || GameConst::$bornMaxStatBonus > 5) {
|
||||||
dieMsg("보너스 능력치 합이 잘못 지정되었습니다. 다시 가입해주세요!");
|
dieMsg("보너스 능력치 합이 잘못 지정되었습니다. 다시 가입해주세요!");
|
||||||
}
|
}
|
||||||
foreach ($inheritBonusStat as $stat) {
|
foreach ($inheritBonusStat as $stat) {
|
||||||
@@ -180,7 +180,7 @@ if ($inheritBonusStat) {
|
|||||||
$pleadership = 0;
|
$pleadership = 0;
|
||||||
$pstrength = 0;
|
$pstrength = 0;
|
||||||
$pintel = 0;
|
$pintel = 0;
|
||||||
foreach (Util::range(Util::randRangeInt(3, 5)) as $statIdx) {
|
foreach (Util::range(Util::randRangeInt(GameConst::$bornMinStatBonus, GameConst::$bornMaxStatBonus)) as $statIdx) {
|
||||||
switch (Util::choiceRandomUsingWeight([$leadership, $strength, $intel])) {
|
switch (Util::choiceRandomUsingWeight([$leadership, $strength, $intel])) {
|
||||||
case 0:
|
case 0:
|
||||||
$pleadership++;
|
$pleadership++;
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class Join extends \sammo\BaseAPI
|
|||||||
|
|
||||||
public function launch(?Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
|
public function launch(?Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
{
|
{
|
||||||
if($session === null){
|
if ($session === null) {
|
||||||
throw "invalid session";
|
throw "invalid session";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,10 +98,10 @@ class Join extends \sammo\BaseAPI
|
|||||||
$strength = $this->args['strength'];
|
$strength = $this->args['strength'];
|
||||||
$intel = $this->args['intel'];
|
$intel = $this->args['intel'];
|
||||||
|
|
||||||
$inheritSpecial = $this->args['inheritSpecial']??null;
|
$inheritSpecial = $this->args['inheritSpecial'] ?? null;
|
||||||
$inheritTurntime =$this->args['inheritTurntime']??null;
|
$inheritTurntime = $this->args['inheritTurntime'] ?? null;
|
||||||
$inheritCity = $this->args['inheritCity']??null;
|
$inheritCity = $this->args['inheritCity'] ?? null;
|
||||||
$inheritBonusStat = $this->args['inheritBonusStat']??null;
|
$inheritBonusStat = $this->args['inheritBonusStat'] ?? null;
|
||||||
|
|
||||||
$rootDB = RootDB::db();
|
$rootDB = RootDB::db();
|
||||||
//회원 테이블에서 정보확인
|
//회원 테이블에서 정보확인
|
||||||
@@ -277,11 +277,11 @@ class Join extends \sammo\BaseAPI
|
|||||||
$experience *= 0.8;
|
$experience *= 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($inheritTurntime === null) {
|
if ($inheritTurntime !== null) {
|
||||||
$inheritTurntime = $inheritTurntime % ($gameStor->turnterm * 60);
|
$inheritTurntime = $inheritTurntime % ($gameStor->turnterm * 60);
|
||||||
$inheritTurntime += Util::randRangeInt(0, 999999) / 1000000;
|
$inheritTurntime += Util::randRangeInt(0, 999999) / 1000000;
|
||||||
$turntime = cutTurn($admin['turntime'], $admin['turnterm']);
|
$turntime = new \DateTimeImmutable(cutTurn($admin['turntime'], $admin['turnterm']));
|
||||||
$turntime = TimeUtil::nowAddSeconds($inheritTurntime, true);
|
$turntime = TimeUtil::format($turntime->add(TimeUtil::secondsToDateInterval($inheritTurntime)), true);
|
||||||
} else {
|
} else {
|
||||||
$turntime = getRandTurn($admin['turnterm'], new \DateTimeImmutable($admin['turntime']));
|
$turntime = getRandTurn($admin['turnterm'], new \DateTimeImmutable($admin['turntime']));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,11 @@ class GameConstBase
|
|||||||
/** @var int 거병,임관 제한 기간 */
|
/** @var int 거병,임관 제한 기간 */
|
||||||
public static $joinActionLimit = 12;
|
public static $joinActionLimit = 12;
|
||||||
|
|
||||||
|
/** @var int 장수 생성시 능력치 최소 보너스 */
|
||||||
|
public static $bornMinStatBonus = 3;
|
||||||
|
/** @var int 장수 생성시 능력치 최대 보너스 */
|
||||||
|
public static $bornMaxStatBonus = 5;
|
||||||
|
|
||||||
/** @var array 선택 가능한 국가 성향 */
|
/** @var array 선택 가능한 국가 성향 */
|
||||||
public static $availableNationType = [
|
public static $availableNationType = [
|
||||||
'che_도적', 'che_명가', 'che_음양가', 'che_종횡가', 'che_불가', 'che_오두미도', 'che_태평도', 'che_도가',
|
'che_도적', 'che_명가', 'che_음양가', 'che_종횡가', 'che_불가', 'che_오두미도', 'che_태평도', 'che_도가',
|
||||||
|
|||||||
+20
-5
@@ -10,6 +10,7 @@ html {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: 삭제!!
|
||||||
table.tb_layout {
|
table.tb_layout {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
@@ -17,7 +18,8 @@ table.tb_layout {
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body{
|
html,
|
||||||
|
body {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,10 +32,23 @@ html, body{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.float-left{
|
.float-left {
|
||||||
float:left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.float-right{
|
.float-right {
|
||||||
float:right;
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.a-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.a-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.a-center {
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
+348
@@ -0,0 +1,348 @@
|
|||||||
|
<template>
|
||||||
|
<top-back-bar title="장수 생성" />
|
||||||
|
|
||||||
|
<div id="container" class="bg0">
|
||||||
|
<div class="row bg1">
|
||||||
|
<div class="col col-md-11 col-9 center align-self-center">
|
||||||
|
임관 권유 메시지
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-1 col-3">
|
||||||
|
<label
|
||||||
|
><input type="checkbox" v-model="displayTable" />{{
|
||||||
|
displayTable ? "숨기기" : "보이기"
|
||||||
|
}}</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CTable responsive v-if="displayTable">
|
||||||
|
<CTableBody>
|
||||||
|
<CTableRow
|
||||||
|
class="nation-row"
|
||||||
|
v-for="nation in nationList"
|
||||||
|
:key="nation.nation"
|
||||||
|
>
|
||||||
|
<CTableHeaderCell
|
||||||
|
scope="row"
|
||||||
|
class="a-center p-0"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: nation.color,
|
||||||
|
color: isBrightColor(nation.color) ? 'black' : 'white',
|
||||||
|
}"
|
||||||
|
><div class="nation-name">
|
||||||
|
{{ nation.name }}
|
||||||
|
</div>
|
||||||
|
</CTableHeaderCell>
|
||||||
|
<CTableDataCell class="p-0">
|
||||||
|
<div
|
||||||
|
class="nation-info"
|
||||||
|
v-html="nation.scoutmsg ?? '-'"
|
||||||
|
></div></CTableDataCell></CTableRow
|
||||||
|
></CTableBody>
|
||||||
|
</CTable>
|
||||||
|
<!-- 국가 설명 -->
|
||||||
|
<div class="row bg1"><div class="col center">장수 생성</div></div>
|
||||||
|
<div class="forms">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-4 col-3 a-right align-self-center">장수명</div>
|
||||||
|
<div class="col col-md-3 col-9 align-self-center">
|
||||||
|
<input v-model="args.name" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-1 col-3 a-right align-self-center">
|
||||||
|
전콘 사용
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-4 col-9 align-self-center">
|
||||||
|
<img style="height: 64px; width: 64px" :src="iconPath" /><label
|
||||||
|
><input type="checkbox" v-model="args.pic" /> 사용</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-4 col-3 align-self-center a-right">성격</div>
|
||||||
|
|
||||||
|
<div class="col col-md-8 col-9 align-self-center">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-3 col-4 align-self-center">
|
||||||
|
<select
|
||||||
|
class="form-select form-inline"
|
||||||
|
style="max-width: 20ch"
|
||||||
|
v-model="args.character"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="(personalityObj, key) in availablePersonality"
|
||||||
|
:key="key"
|
||||||
|
:value="key"
|
||||||
|
>
|
||||||
|
{{ personalityObj.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-9 col-8 align-self-center">
|
||||||
|
<small class="text-muted">{{
|
||||||
|
availablePersonality[args.character].info
|
||||||
|
}}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
계정관리에서 자신만을 표현할 수 있는 아이콘을 업로드 해보세요!
|
||||||
|
</div>
|
||||||
|
</div>-->
|
||||||
|
<div class="row" style="margin-top: 1em">
|
||||||
|
<div class="col col-md-4 col-3 a-right align-self-center">
|
||||||
|
능력치<br /><small class="text-muted">통/무/지</small>
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-2 col-3 align-self-center">
|
||||||
|
<input type="number" class="form-control" v-model="args.leadership" />
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-2 col-3 align-self-center">
|
||||||
|
<input type="number" class="form-control" v-model="args.strength" />
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-2 col-3 align-self-center">
|
||||||
|
<input type="number" class="form-control" v-model="args.intel" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" style="margin-top: 1em">
|
||||||
|
<div class="col col-md-4 col-3 a-right align-self-center">
|
||||||
|
능력치 조절
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-8 col-9">
|
||||||
|
<CButton color="secondary" class="stat-btn" @click="randStatRandom"
|
||||||
|
>랜덤형</CButton
|
||||||
|
>
|
||||||
|
<CButton color="secondary" class="stat-btn" @click="randStatLeadPow"
|
||||||
|
>통솔무력형</CButton
|
||||||
|
>
|
||||||
|
<CButton color="secondary" class="stat-btn" @click="randStatLeadInt"
|
||||||
|
>통솔지력형</CButton
|
||||||
|
>
|
||||||
|
<CButton color="secondary" class="stat-btn" @click="randStatPowInt"
|
||||||
|
>무력지력형</CButton
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" style="border-top: solid 1px #aaa; margin-top: 0.5em">
|
||||||
|
<div class="col a-center" style="color: orange">
|
||||||
|
모든 능력치는 ( {{ stats.min }} <= 능력치 <= {{ stats.max }} )
|
||||||
|
사이로 잡으셔야 합니다.<br />
|
||||||
|
그 외의 능력치는 가입되지 않습니다.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col a-center">
|
||||||
|
능력치의 총합은 {{ stats.total }} 입니다. 가입후 {{ stats.bonusMin }} ~
|
||||||
|
{{ stats.bonusMax }} 의 능력치 보너스를 받게 됩니다.<br />
|
||||||
|
임의의 도시에서 재야로 시작하며 건국과 임관은 게임 내에서 실행합니다.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" style="border-top: solid 1px #aaa">
|
||||||
|
<div class="col a-center" style="margin: 0.5em">
|
||||||
|
<CButton color="primary" @click="submitForm">장수 생성</CButton
|
||||||
|
> <CButton color="secondary" @click="resetArgs">다시 입력</CButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import "../scss/bootstrap5.scss";
|
||||||
|
import "../scss/game_bg.scss";
|
||||||
|
|
||||||
|
import { defineComponent, unref } from "vue";
|
||||||
|
import TopBackBar from "./components/TopBackBar.vue";
|
||||||
|
import {
|
||||||
|
CButton,
|
||||||
|
CTable,
|
||||||
|
CTableBody,
|
||||||
|
CTableRow,
|
||||||
|
CTableHeaderCell,
|
||||||
|
CTableDataCell,
|
||||||
|
} from "@coreui/vue/src";
|
||||||
|
import { getIconPath } from "./util/getIconPath";
|
||||||
|
import { isBrightColor } from "./util/isBrightColor";
|
||||||
|
import {
|
||||||
|
abilityLeadint,
|
||||||
|
abilityLeadpow,
|
||||||
|
abilityPowint,
|
||||||
|
abilityRand,
|
||||||
|
} from "./util/generalStats";
|
||||||
|
import { clone, shuffle } from "lodash";
|
||||||
|
import axios from "axios";
|
||||||
|
import { InvalidResponse } from "./defs";
|
||||||
|
|
||||||
|
declare const nationList: {
|
||||||
|
nation: number;
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
scout: number;
|
||||||
|
scoutmsg?: string;
|
||||||
|
}[];
|
||||||
|
declare const availablePersonality: {
|
||||||
|
[key: string]: {
|
||||||
|
name: string;
|
||||||
|
info: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
declare const member: {
|
||||||
|
name: string;
|
||||||
|
grade: number;
|
||||||
|
picture: string;
|
||||||
|
imgsvr: 0 | 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare const stats: {
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
total: number;
|
||||||
|
bonusMin: number;
|
||||||
|
bonusMax: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare const serverID: string;
|
||||||
|
|
||||||
|
declare module "@vue/runtime-core" {
|
||||||
|
interface ComponentCustomProperties {
|
||||||
|
member: typeof member;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type APIArgs = {
|
||||||
|
name: string;
|
||||||
|
leadership: number;
|
||||||
|
strength: number;
|
||||||
|
intel: number;
|
||||||
|
pic: boolean;
|
||||||
|
character: string;
|
||||||
|
inheritSpecial?: string;
|
||||||
|
inheritTurntime?: number;
|
||||||
|
inheritCity?: number;
|
||||||
|
inheritBonusStat?: [number, number, number];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "Join",
|
||||||
|
components: {
|
||||||
|
TopBackBar,
|
||||||
|
CButton,
|
||||||
|
CTable,
|
||||||
|
CTableBody,
|
||||||
|
CTableRow,
|
||||||
|
CTableHeaderCell,
|
||||||
|
CTableDataCell,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
const displayTable = JSON.parse(
|
||||||
|
localStorage.getItem(`conf.${serverID}.join.displayTable`) ?? "true"
|
||||||
|
);
|
||||||
|
const nationListShuffled = shuffle(nationList);
|
||||||
|
const args: APIArgs = {
|
||||||
|
name: member.name,
|
||||||
|
leadership: stats.total - 2 * Math.floor(stats.total / 3),
|
||||||
|
strength: Math.floor(stats.total / 3),
|
||||||
|
intel: Math.floor(stats.total / 3),
|
||||||
|
pic: true,
|
||||||
|
character: "Random",
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
displayTable: displayTable,
|
||||||
|
availablePersonality,
|
||||||
|
member: member,
|
||||||
|
stats,
|
||||||
|
args,
|
||||||
|
nationList: nationListShuffled,
|
||||||
|
isBrightColor,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
displayTable(newValue: boolean) {
|
||||||
|
localStorage.setItem(
|
||||||
|
`conf.${serverID}.join.displayTable`,
|
||||||
|
JSON.stringify(newValue)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iconPath() {
|
||||||
|
if (this.args.pic) {
|
||||||
|
return getIconPath(this.member.imgsvr, this.member.picture);
|
||||||
|
}
|
||||||
|
return getIconPath(0, "default.jpg");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
randStatRandom() {
|
||||||
|
[this.args.leadership, this.args.strength, this.args.intel] =
|
||||||
|
abilityRand();
|
||||||
|
},
|
||||||
|
randStatLeadPow() {
|
||||||
|
[this.args.leadership, this.args.strength, this.args.intel] =
|
||||||
|
abilityLeadpow();
|
||||||
|
},
|
||||||
|
randStatLeadInt() {
|
||||||
|
[this.args.leadership, this.args.strength, this.args.intel] =
|
||||||
|
abilityLeadint();
|
||||||
|
},
|
||||||
|
randStatPowInt() {
|
||||||
|
[this.args.leadership, this.args.strength, this.args.intel] =
|
||||||
|
abilityPowint();
|
||||||
|
},
|
||||||
|
resetArgs() {
|
||||||
|
this.args.name = member.name;
|
||||||
|
this.args.pic = true;
|
||||||
|
this.args.character = "Random";
|
||||||
|
this.args.leadership = stats.total - 2 * Math.floor(stats.total / 3);
|
||||||
|
this.args.strength = Math.floor(stats.total / 3);
|
||||||
|
this.args.intel = Math.floor(stats.total / 3);
|
||||||
|
},
|
||||||
|
async submitForm() {
|
||||||
|
const args = clone(this.args);
|
||||||
|
console.log(args);
|
||||||
|
const response = await axios({
|
||||||
|
url: "api.php",
|
||||||
|
method: 'post',
|
||||||
|
responseType: 'json',
|
||||||
|
data: {
|
||||||
|
path: ["General", "Join"],
|
||||||
|
args,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log(response);
|
||||||
|
const result:InvalidResponse = response.data;
|
||||||
|
console.log(result);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
#container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: auto;
|
||||||
|
border: solid 1px #888888;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forms {
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-btn {
|
||||||
|
width: 8em;
|
||||||
|
margin-right: 1px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nation-row {
|
||||||
|
max-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nation-name {
|
||||||
|
width: 128px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nation-info {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: hidden;
|
||||||
|
width: 870px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,7 +6,8 @@ import 'bootstrap';
|
|||||||
import download from 'downloadjs';
|
import download from 'downloadjs';
|
||||||
import { unwrap } from "./util/unwrap";
|
import { unwrap } from "./util/unwrap";
|
||||||
import { isInteger } from 'lodash';
|
import { isInteger } from 'lodash';
|
||||||
import { combineArray, errUnknown, getNpcColor, isBrightColor } from './common_legacy';
|
import { combineArray, errUnknown, getNpcColor } from './common_legacy';
|
||||||
|
import { isBrightColor } from "./util/isBrightColor";
|
||||||
import { numberWithCommas } from "./util/numberWithCommas";
|
import { numberWithCommas } from "./util/numberWithCommas";
|
||||||
import { unwrap_any } from './util/unwrap_any';
|
import { unwrap_any } from './util/unwrap_any';
|
||||||
import { BasicGeneralListResponse, InvalidResponse } from './defs';
|
import { BasicGeneralListResponse, InvalidResponse } from './defs';
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { exportWindow } from "./util/exportWindow";
|
import { exportWindow } from "./util/exportWindow";
|
||||||
import { activateFlip, isBrightColor, getIconPath, errUnknown, errUnknownToast, quickReject, initTooltip } from "./common_legacy";
|
import { activateFlip, errUnknown, errUnknownToast, quickReject, initTooltip } from "./common_legacy";
|
||||||
|
import { isBrightColor } from "./util/isBrightColor";
|
||||||
|
import { getIconPath } from "./util/getIconPath";
|
||||||
import { mb_strwidth } from "./util/mb_strwidth";
|
import { mb_strwidth } from "./util/mb_strwidth";
|
||||||
import { TemplateEngine } from "./util/TemplateEngine";
|
import { TemplateEngine } from "./util/TemplateEngine";
|
||||||
import { escapeHtml } from "./legacy/escapeHtml";
|
import { escapeHtml } from "./legacy/escapeHtml";
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { unwrap } from "./util/unwrap";
|
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
@@ -31,24 +30,6 @@ export function stringFormat(text: string, ...args: (string | number)[]): string
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hexToRgb(hex: string): { r: number, g: number, b: number } | null {
|
|
||||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
||||||
return result ? {
|
|
||||||
r: parseInt(result[1], 16),
|
|
||||||
g: parseInt(result[2], 16),
|
|
||||||
b: parseInt(result[3], 16)
|
|
||||||
} : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isBrightColor(color: string): boolean {
|
|
||||||
const cv = unwrap(hexToRgb(color));
|
|
||||||
if ((cv.r * 0.299 + cv.g * 0.587 + cv.b * 0.114) > 140) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 게임내에서 지원하는 color type만 선택할 수 있도록 해주는 함수
|
* 게임내에서 지원하는 color type만 선택할 수 있도록 해주는 함수
|
||||||
* @param {string} color #AAAAAA 또는 AAAAAA 형태로 작성된 RGB hex color string
|
* @param {string} color #AAAAAA 또는 AAAAAA 형태로 작성된 RGB hex color string
|
||||||
@@ -82,15 +63,6 @@ declare global {
|
|||||||
linkifyStr: (v: string, k?: Record<string, string | number>) => string;
|
linkifyStr: (v: string, k?: Record<string, string | number>) => string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function getIconPath(imgsvr: boolean | 1 | 0, picture: string): string {
|
|
||||||
// ../d_shared/common_path.js 필요
|
|
||||||
if (!imgsvr) {
|
|
||||||
return window.pathConfig.sharedIcon + '/' + picture;
|
|
||||||
} else {
|
|
||||||
return window.pathConfig.root + '/d_pic/' + picture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function activateFlip($obj?: JQuery<HTMLElement>): void {
|
export function activateFlip($obj?: JQuery<HTMLElement>): void {
|
||||||
let $result: JQuery<HTMLElement>;
|
let $result: JQuery<HTMLElement>;
|
||||||
if ($obj === undefined) {
|
if ($obj === undefined) {
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { unwrap_any } from './util/unwrap_any';
|
import { unwrap_any } from './util/unwrap_any';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { isBrightColor } from './common_legacy';
|
import { isBrightColor } from "./util/isBrightColor";
|
||||||
import { setAxiosXMLHttpRequest } from './util/setAxiosXMLHttpRequest';
|
import { setAxiosXMLHttpRequest } from './util/setAxiosXMLHttpRequest';
|
||||||
import { isString } from 'lodash';
|
import { isString } from 'lodash';
|
||||||
import { convertFormData } from './util/convertFormData';
|
import { convertFormData } from './util/convertFormData';
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ const serverLoginBtn = "<a href='<%serverPath%>/' class='item'\
|
|||||||
></a>";
|
></a>";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const serverCreateBtn = "<a href='<%serverPath%>/join.php' class='item'\
|
const serverCreateBtn = "<a href='<%serverPath%>/v_join.php' class='item'\
|
||||||
><button type='button' class='fill_box with_skin'>장수생성</button\
|
><button type='button' class='fill_box with_skin'>장수생성</button\
|
||||||
></a>";
|
></a>";
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ const serverCreateTemplate = "\
|
|||||||
<td colspan='2' class='not_registered'>- 미 등 록 -</div>\
|
<td colspan='2' class='not_registered'>- 미 등 록 -</div>\
|
||||||
<td class='ignore_border vertical_flex BtnPlate'>\
|
<td class='ignore_border vertical_flex BtnPlate'>\
|
||||||
<%if(canCreate) {%>\
|
<%if(canCreate) {%>\
|
||||||
<a href='<%serverPath%>/join.php' class='item'><button type='button' class='fill_box with_skin'>장수생성</button></a>\
|
<a href='<%serverPath%>/v_join.php' class='item'><button type='button' class='fill_box with_skin'>장수생성</button></a>\
|
||||||
<%}%>\
|
<%}%>\
|
||||||
<%if(canSelectNPC) {%>\
|
<%if(canSelectNPC) {%>\
|
||||||
<a href='<%serverPath%>/select_npc.php' class='item'><button type='button' class='fill_box with_skin'>장수빙의</button></a>\
|
<a href='<%serverPath%>/select_npc.php' class='item'><button type='button' class='fill_box with_skin'>장수빙의</button></a>\
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ import { InvalidResponse } from './defs';
|
|||||||
import { getDateTimeNow } from './util/getDateTimeNow';
|
import { getDateTimeNow } from './util/getDateTimeNow';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { convertFormData } from './util/convertFormData';
|
import { convertFormData } from './util/convertFormData';
|
||||||
import { isBrightColor } from './common_legacy';
|
import { isBrightColor } from "./util/isBrightColor";
|
||||||
import { unwrap } from './util/unwrap';
|
import { unwrap } from './util/unwrap';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { addMinutes } from 'date-fns';
|
import { addMinutes } from 'date-fns';
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import $ from 'jquery';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { setAxiosXMLHttpRequest } from './util/setAxiosXMLHttpRequest';
|
import { setAxiosXMLHttpRequest } from './util/setAxiosXMLHttpRequest';
|
||||||
import { InvalidResponse } from './defs';
|
import { InvalidResponse } from './defs';
|
||||||
import { getIconPath, initTooltip } from './common_legacy';
|
import { initTooltip } from './common_legacy';
|
||||||
|
import { getIconPath } from "./util/getIconPath";
|
||||||
import { convertFormData } from './util/convertFormData';
|
import { convertFormData } from './util/convertFormData';
|
||||||
import { unwrap_any } from './util/unwrap_any';
|
import { unwrap_any } from './util/unwrap_any';
|
||||||
import { unwrap } from './util/unwrap';
|
import { unwrap } from './util/unwrap';
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { errUnknown, getIconPath } from './common_legacy';
|
import { errUnknown } from './common_legacy';
|
||||||
|
import { getIconPath } from "./util/getIconPath";
|
||||||
import { TemplateEngine } from "./util/TemplateEngine";
|
import { TemplateEngine } from "./util/TemplateEngine";
|
||||||
import { GeneralListResponse, InvalidResponse } from './defs';
|
import { GeneralListResponse, InvalidResponse } from './defs';
|
||||||
import { convertFormData } from './util/convertFormData';
|
import { convertFormData } from './util/convertFormData';
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
declare const stats: {
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
total: number;
|
||||||
|
bonusMin: number;
|
||||||
|
bonusMax: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function abilityRand(): [number, number, number] {
|
||||||
|
let leadership = Math.random() * 65 + 10;
|
||||||
|
let strength = Math.random() * 65 + 10;
|
||||||
|
let intel = Math.random() * 65 + 10;
|
||||||
|
const rate = leadership + strength + intel;
|
||||||
|
|
||||||
|
leadership = Math.floor((leadership / rate) * stats.total);
|
||||||
|
strength = Math.floor((strength / rate) * stats.total);
|
||||||
|
intel = Math.floor((intel / rate) * stats.total);
|
||||||
|
|
||||||
|
while (leadership + strength + intel < stats.total) {
|
||||||
|
leadership += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
leadership > stats.max ||
|
||||||
|
strength > stats.max ||
|
||||||
|
intel > stats.max ||
|
||||||
|
leadership < stats.min ||
|
||||||
|
strength < stats.min ||
|
||||||
|
intel < stats.min
|
||||||
|
) {
|
||||||
|
return abilityRand();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [leadership, strength, intel];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function abilityLeadpow(): [number, number, number] {
|
||||||
|
let leadership = Math.random() * 6;
|
||||||
|
let strength = Math.random() * 6;
|
||||||
|
let intel = Math.random() * 1;
|
||||||
|
const rate = leadership + strength + intel;
|
||||||
|
|
||||||
|
leadership = Math.floor((leadership / rate) * stats.total);
|
||||||
|
strength = Math.floor((strength / rate) * stats.total);
|
||||||
|
intel = Math.floor((intel / rate) * stats.total);
|
||||||
|
|
||||||
|
while (leadership + strength + intel < stats.total) {
|
||||||
|
strength += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intel < stats.min) {
|
||||||
|
leadership -= stats.min - intel;
|
||||||
|
intel = stats.min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leadership > stats.max) {
|
||||||
|
strength += leadership - stats.max;
|
||||||
|
leadership = stats.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strength > stats.max) {
|
||||||
|
leadership += strength - stats.max;
|
||||||
|
strength = stats.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leadership > stats.max) {
|
||||||
|
intel += leadership - stats.max;
|
||||||
|
leadership = stats.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [leadership, strength, intel];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function abilityLeadint(): [number, number, number] {
|
||||||
|
let leadership = Math.random() * 6;
|
||||||
|
let strength = Math.random() * 1;
|
||||||
|
let intel = Math.random() * 6;
|
||||||
|
const rate = leadership + strength + intel;
|
||||||
|
|
||||||
|
leadership = Math.floor((leadership / rate) * stats.total);
|
||||||
|
strength = Math.floor((strength / rate) * stats.total);
|
||||||
|
intel = Math.floor((intel / rate) * stats.total);
|
||||||
|
|
||||||
|
while (leadership + strength + intel < stats.total) {
|
||||||
|
intel += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strength < stats.min) {
|
||||||
|
leadership -= stats.min - strength;
|
||||||
|
strength = stats.min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leadership > stats.max) {
|
||||||
|
intel += leadership - stats.max;
|
||||||
|
leadership = stats.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intel > stats.max) {
|
||||||
|
leadership += intel - stats.max;
|
||||||
|
intel = stats.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leadership > stats.max) {
|
||||||
|
strength += leadership - stats.max;
|
||||||
|
leadership = stats.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [leadership, strength, intel];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function abilityPowint(): [number, number, number] {
|
||||||
|
let leadership = Math.random() * 1;
|
||||||
|
let strength = Math.random() * 6;
|
||||||
|
let intel = Math.random() * 6;
|
||||||
|
const rate = leadership + strength + intel;
|
||||||
|
|
||||||
|
leadership = Math.floor((leadership / rate) * stats.total);
|
||||||
|
strength = Math.floor((strength / rate) * stats.total);
|
||||||
|
intel = Math.floor((intel / rate) * stats.total);
|
||||||
|
|
||||||
|
while (leadership + strength + intel < stats.total) {
|
||||||
|
intel += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leadership < stats.min) {
|
||||||
|
strength -= stats.min - leadership;
|
||||||
|
leadership = stats.min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strength > stats.max) {
|
||||||
|
intel += strength - stats.max;
|
||||||
|
strength = stats.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intel > stats.max) {
|
||||||
|
strength += intel - stats.max;
|
||||||
|
intel = stats.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strength > stats.max) {
|
||||||
|
leadership += strength - stats.max;
|
||||||
|
strength = stats.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [leadership, strength, intel];
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export function getIconPath(imgsvr: boolean | 1 | 0, picture: string): string {
|
||||||
|
// ../d_shared/common_path.js 필요
|
||||||
|
if (!imgsvr) {
|
||||||
|
return `${window.pathConfig.sharedIcon}/${picture}`;
|
||||||
|
} else {
|
||||||
|
return `${window.pathConfig.root}/d_pic/${picture}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export function hexToRgb(hex: string): { r: number; g: number; b: number; } | null {
|
||||||
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||||
|
return result ? {
|
||||||
|
r: parseInt(result[1], 16),
|
||||||
|
g: parseInt(result[2], 16),
|
||||||
|
b: parseInt(result[3], 16)
|
||||||
|
} : null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { unwrap } from "./unwrap";
|
||||||
|
import { hexToRgb } from "./hexToRgb";
|
||||||
|
|
||||||
|
export function isBrightColor(color: string): boolean {
|
||||||
|
const cv = unwrap(hexToRgb(color));
|
||||||
|
if ((cv.r * 0.299 + cv.g * 0.587 + cv.b * 0.114) > 140) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-1
@@ -1 +1,4 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
|
import Join from './Join.vue';
|
||||||
|
|
||||||
|
createApp(Join).mount('#app')
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo;
|
||||||
|
|
||||||
|
include "lib.php";
|
||||||
|
include "func.php";
|
||||||
|
//로그인 검사
|
||||||
|
|
||||||
|
$session = Session::requireLogin()->setReadOnly();
|
||||||
|
$userID = Session::getUserID();
|
||||||
|
|
||||||
|
if (!$userID) {
|
||||||
|
die(WebUtil::errorBackMsg("잘못된 접근입니다!!!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//회원 테이블에서 정보확인
|
||||||
|
$member = RootDB::db()->queryFirstRow("SELECT no,name,picture,imgsvr,grade from member where no= %i", $userID);
|
||||||
|
if (!$member) {
|
||||||
|
die(WebUtil::errorBackMsg("잘못된 접근입니다!!!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$admin = $gameStor->getValues(['block_general_create', 'show_img_level', 'maxgeneral']);
|
||||||
|
if ($admin['block_general_create']) {
|
||||||
|
die(WebUtil::errorBackMsg("잘못된 접근입니다!!!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$alreadyJoined = $db->queryFirstField('SELECT name FROM general WHERE owner = %i', $userID);
|
||||||
|
if ($alreadyJoined) {
|
||||||
|
die(WebUtil::errorBackMsg("이미 장수를 생성했습니다: {$alreadyJoined}", './'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$gencount = $db->queryFirstField('SELECT count(no) FROM general WHERE npc<2');
|
||||||
|
if ($gencount >= $admin['maxgeneral']) {
|
||||||
|
die(WebUtil::errorBackMsg("더 이상 등록할 수 없습니다."));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$nationList = $db->query('SELECT nation,`name`,color,scout FROM nation');
|
||||||
|
$nationList = Util::convertArrayToDict($nationList, 'nation');
|
||||||
|
//NOTE: join 안할것임
|
||||||
|
$scoutMsgs = KVStorage::getValuesFromInterNamespace($db, 'nation_env', 'scout_msg');
|
||||||
|
foreach ($scoutMsgs as $nationID => $scoutMsg) {
|
||||||
|
$nationList[$nationID]['scoutmsg'] = $scoutMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$availablePersonality = [];
|
||||||
|
foreach (GameConst::$availablePersonality as $personalityID) {
|
||||||
|
$personalityObj = buildPersonalityClass($personalityID);
|
||||||
|
$availablePersonality[$personalityID] = [
|
||||||
|
'name' => $personalityObj->getName(),
|
||||||
|
'info' => $personalityObj->getInfo(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title><?= UniqueConst::$serverName ?>: 장수 생성</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<?= WebUtil::printCSS('dist_css/common_vue.css') ?>
|
||||||
|
<?= WebUtil::printCSS('dist_css/v_join.css') ?>
|
||||||
|
<?= WebUtil::printJS('../d_shared/common_path.js', true) ?>
|
||||||
|
<?= WebUtil::printJS('dist_js/vendors_vue.js', true) ?>
|
||||||
|
<?= WebUtil::printJS('dist_js/common_vue.js', true) ?>
|
||||||
|
<?= WebUtil::printJS('dist_js/v_join.js', true) ?>
|
||||||
|
<?= WebUtil::printStaticValues([
|
||||||
|
'serverID' => UniqueConst::$serverID,
|
||||||
|
'nationList' => array_values($nationList),
|
||||||
|
'config' => [
|
||||||
|
'show_img_level' => $admin['show_img_level']
|
||||||
|
],
|
||||||
|
'member' => [
|
||||||
|
'name' => $member['name'],
|
||||||
|
'grade' => $member['grade'],
|
||||||
|
'picture' => $member['picture'],
|
||||||
|
'imgsvr' => $member['imgsvr'],
|
||||||
|
],
|
||||||
|
'availablePersonality' => array_merge([
|
||||||
|
'Random' => ['name' => '???', 'info' => '무작위 성격을 선택합니다.']
|
||||||
|
], $availablePersonality),
|
||||||
|
'stats' => [
|
||||||
|
'min' => GameConst::$defaultStatMin,
|
||||||
|
'max' => GameConst::$defaultStatMax,
|
||||||
|
'total' => GameConst::$defaultStatTotal,
|
||||||
|
'bonusMin' => GameConst::$bornMinStatBonus,
|
||||||
|
'bonusMax' => GameConst::$bornMaxStatBonus,
|
||||||
|
]
|
||||||
|
]) ?>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -12,11 +12,16 @@ class APIHelper
|
|||||||
public static function launch(string $rootPath)
|
public static function launch(string $rootPath)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$input = json_decode(file_get_contents('php://input'));
|
$rawInput = file_get_contents('php://input');
|
||||||
|
$input = Json::decode($rawInput);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Json::dieWithReason($e->getMessage());
|
Json::dieWithReason($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!$input){
|
||||||
|
Json::dieWithReason("input이 비어있습니다. {$rawInput}");
|
||||||
|
}
|
||||||
|
|
||||||
if (!key_exists('path', $input)) {
|
if (!key_exists('path', $input)) {
|
||||||
Json::dieWithReason('path가 지정되지 않았습니다.');
|
Json::dieWithReason('path가 지정되지 않았습니다.');
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-20
@@ -88,50 +88,35 @@ class TimeUtil
|
|||||||
public static function now(bool $withFraction = false): string
|
public static function now(bool $withFraction = false): string
|
||||||
{
|
{
|
||||||
$obj = new \DateTime();
|
$obj = new \DateTime();
|
||||||
if (!$withFraction) {
|
return static::format($obj, $withFraction);
|
||||||
return $obj->format('Y-m-d H:i:s');
|
|
||||||
}
|
|
||||||
return $obj->format('Y-m-d H:i:s.u');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function nowAddDays($day, bool $withFraction = false): string
|
public static function nowAddDays($day, bool $withFraction = false): string
|
||||||
{
|
{
|
||||||
$obj = new \DateTime();
|
$obj = new \DateTime();
|
||||||
$obj->add(static::secondsToDateInterval($day * 3600 * 24));
|
$obj->add(static::secondsToDateInterval($day * 3600 * 24));
|
||||||
if (!$withFraction) {
|
return static::format($obj, $withFraction);
|
||||||
return $obj->format('Y-m-d H:i:s');
|
|
||||||
}
|
|
||||||
return $obj->format('Y-m-d H:i:s.u');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function nowAddHours($hour, bool $withFraction = false): string
|
public static function nowAddHours($hour, bool $withFraction = false): string
|
||||||
{
|
{
|
||||||
$obj = new \DateTime();
|
$obj = new \DateTime();
|
||||||
$obj->add(static::secondsToDateInterval($hour * 3600));
|
$obj->add(static::secondsToDateInterval($hour * 3600));
|
||||||
if (!$withFraction) {
|
return static::format($obj, $withFraction);
|
||||||
return $obj->format('Y-m-d H:i:s');
|
|
||||||
}
|
|
||||||
return $obj->format('Y-m-d H:i:s.u');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function nowAddMinutes($minute, bool $withFraction = false): string
|
public static function nowAddMinutes($minute, bool $withFraction = false): string
|
||||||
{
|
{
|
||||||
$obj = new \DateTime();
|
$obj = new \DateTime();
|
||||||
$obj->add(static::secondsToDateInterval($minute * 60));
|
$obj->add(static::secondsToDateInterval($minute * 60));
|
||||||
if (!$withFraction) {
|
return static::format($obj, $withFraction);
|
||||||
return $obj->format('Y-m-d H:i:s');
|
|
||||||
}
|
|
||||||
return $obj->format('Y-m-d H:i:s.u');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function nowAddSeconds($second, bool $withFraction = false): string
|
public static function nowAddSeconds($second, bool $withFraction = false): string
|
||||||
{
|
{
|
||||||
$obj = new \DateTime();
|
$obj = new \DateTime();
|
||||||
$obj->add(static::secondsToDateInterval($second));
|
$obj->add(static::secondsToDateInterval($second));
|
||||||
if (!$withFraction) {
|
return static::format($obj, $withFraction);
|
||||||
return $obj->format('Y-m-d H:i:s');
|
|
||||||
}
|
|
||||||
return $obj->format('Y-m-d H:i:s.u');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function secondsToDateTime(float $fullSeconds, bool $isDateTimeImmutable = false, bool $isUTC = false): \DateTimeInterface
|
public static function secondsToDateTime(float $fullSeconds, bool $isDateTimeImmutable = false, bool $isUTC = false): \DateTimeInterface
|
||||||
@@ -188,6 +173,13 @@ class TimeUtil
|
|||||||
return $seconds;
|
return $seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function format(\DateTimeInterface $dateTime, bool $withFraction): string{
|
||||||
|
if (!$withFraction) {
|
||||||
|
return $dateTime->format('Y-m-d H:i:s');
|
||||||
|
}
|
||||||
|
return $dateTime->format('Y-m-d H:i:s.u');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $baseYear, $baseMonth 부터 $afterMonth 개월 이내인지. $afterMonth 포함.
|
* $baseYear, $baseMonth 부터 $afterMonth 개월 이내인지. $afterMonth 포함.
|
||||||
*
|
*
|
||||||
|
|||||||
+81
-64
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace sammo;
|
namespace sammo;
|
||||||
|
|
||||||
use phpDocumentor\Reflection\Types\Boolean;
|
use phpDocumentor\Reflection\Types\Boolean;
|
||||||
@@ -14,7 +15,7 @@ class WebUtil
|
|||||||
return str_replace('.', '\\.', $ip);
|
return str_replace('.', '\\.', $ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function resolveRelativePath(string $path, string $basepath) : string
|
public static function resolveRelativePath(string $path, string $basepath): string
|
||||||
{
|
{
|
||||||
return \phpUri::parse($basepath)->join($path);
|
return \phpUri::parse($basepath)->join($path);
|
||||||
}
|
}
|
||||||
@@ -30,15 +31,17 @@ class WebUtil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isAJAX(){
|
public static function isAJAX()
|
||||||
return strtolower($_SERVER['HTTP_X_REQUESTED_WITH']??null) === 'xmlhttprequest';
|
{
|
||||||
|
return strtolower($_SERVER['HTTP_X_REQUESTED_WITH'] ?? null) === 'xmlhttprequest';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function requireAJAX():void{
|
public static function requireAJAX(): void
|
||||||
if(!static::isAJAX()){
|
{
|
||||||
|
if (!static::isAJAX()) {
|
||||||
Json::die([
|
Json::die([
|
||||||
'result'=>false,
|
'result' => false,
|
||||||
'reason'=>'no ajax'
|
'reason' => 'no ajax'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,23 +84,23 @@ class WebUtil
|
|||||||
//Use a switch statement to figure out the exact error.
|
//Use a switch statement to figure out the exact error.
|
||||||
switch ($jsonError) {
|
switch ($jsonError) {
|
||||||
case JSON_ERROR_DEPTH:
|
case JSON_ERROR_DEPTH:
|
||||||
$error .= 'Maximum depth exceeded! : '.$content;
|
$error .= 'Maximum depth exceeded! : ' . $content;
|
||||||
break;
|
break;
|
||||||
case JSON_ERROR_STATE_MISMATCH:
|
case JSON_ERROR_STATE_MISMATCH:
|
||||||
$error .= 'Underflow or the modes mismatch! : '.$content;
|
$error .= 'Underflow or the modes mismatch! : ' . $content;
|
||||||
break;
|
break;
|
||||||
case JSON_ERROR_CTRL_CHAR:
|
case JSON_ERROR_CTRL_CHAR:
|
||||||
$error .= 'Unexpected control character found : '.$content;
|
$error .= 'Unexpected control character found : ' . $content;
|
||||||
break;
|
break;
|
||||||
case JSON_ERROR_SYNTAX:
|
case JSON_ERROR_SYNTAX:
|
||||||
$error .= 'Malformed JSON : '.$content;
|
$error .= 'Malformed JSON : ' . $content;
|
||||||
break;
|
break;
|
||||||
case JSON_ERROR_UTF8:
|
case JSON_ERROR_UTF8:
|
||||||
$error .= 'Malformed UTF-8 characters found! : '.$content;
|
$error .= 'Malformed UTF-8 characters found! : ' . $content;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$error .= 'Unknown error! : '.$content;
|
$error .= 'Unknown error! : ' . $content;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
throw new \Exception($error);
|
throw new \Exception($error);
|
||||||
}
|
}
|
||||||
@@ -105,89 +108,89 @@ class WebUtil
|
|||||||
return $decoded;
|
return $decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function preloadAsset(string $path, string $type){
|
public static function preloadAsset(string $path, string $type)
|
||||||
|
{
|
||||||
$upath = \phpUri::parse($path);
|
$upath = \phpUri::parse($path);
|
||||||
$path = $upath->join('');
|
$path = $upath->join('');
|
||||||
if(!$upath->scheme){
|
if (!$upath->scheme) {
|
||||||
if(!file_exists($upath->path)){
|
if (!file_exists($upath->path)) {
|
||||||
return "<!-- preload:{$type} '{$path}' -->\n";
|
return "<!-- preload:{$type} '{$path}' -->\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$mtime = filemtime($upath->path);
|
$mtime = filemtime($upath->path);
|
||||||
if($upath->query){
|
if ($upath->query) {
|
||||||
$tail = '&'.$mtime;
|
$tail = '&' . $mtime;
|
||||||
|
} else {
|
||||||
|
$tail = '?' . $mtime;
|
||||||
}
|
}
|
||||||
else{
|
} else {
|
||||||
$tail = '?'.$mtime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$tail = '';
|
$tail = '';
|
||||||
}
|
}
|
||||||
return "<link href='{$path}{$tail}' rel='preload' as='$type'>\n";
|
return "<link href='{$path}{$tail}' rel='preload' as='$type'>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function preloadCSS(string $path){
|
public static function preloadCSS(string $path)
|
||||||
|
{
|
||||||
return static::preloadAsset($path, 'style');
|
return static::preloadAsset($path, 'style');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function preloadJS(string $path){
|
public static function preloadJS(string $path)
|
||||||
|
{
|
||||||
return static::preloadAsset($path, 'script');
|
return static::preloadAsset($path, 'script');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function printJS(string $path, bool $isDefer=false){
|
public static function printJS(string $path, bool $isDefer = false)
|
||||||
|
{
|
||||||
//async 옵션 고려?
|
//async 옵션 고려?
|
||||||
$upath = \phpUri::parse($path);
|
$upath = \phpUri::parse($path);
|
||||||
$path = $upath->join('');
|
$path = $upath->join('');
|
||||||
if(!$upath->scheme){
|
if (!$upath->scheme) {
|
||||||
if(!file_exists($upath->path)){
|
if (!file_exists($upath->path)) {
|
||||||
return "<!-- JS '{$path}' -->\n";
|
return "<!-- JS '{$path}' -->\n";
|
||||||
}
|
}
|
||||||
$mtime = filemtime($upath->path);
|
$mtime = filemtime($upath->path);
|
||||||
if($upath->query){
|
if ($upath->query) {
|
||||||
$tail = '&'.$mtime;
|
$tail = '&' . $mtime;
|
||||||
|
} else {
|
||||||
|
$tail = '?' . $mtime;
|
||||||
}
|
}
|
||||||
else{
|
} else {
|
||||||
$tail = '?'.$mtime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$tail = '';
|
$tail = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$typeText = $isDefer?'defer':'';
|
$typeText = $isDefer ? 'defer' : '';
|
||||||
return "<script {$typeText} src='{$path}{$tail}'></script>\n";
|
return "<script {$typeText} src='{$path}{$tail}'></script>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function printCSS(string $path){
|
public static function printCSS(string $path)
|
||||||
|
{
|
||||||
$upath = \phpUri::parse($path);
|
$upath = \phpUri::parse($path);
|
||||||
$path = $upath->join('');
|
$path = $upath->join('');
|
||||||
if(!$upath->scheme){
|
if (!$upath->scheme) {
|
||||||
if(!file_exists($upath->path)){
|
if (!file_exists($upath->path)) {
|
||||||
return "<!-- CSS '{$path}' -->\n";
|
return "<!-- CSS '{$path}' -->\n";
|
||||||
}
|
}
|
||||||
$mtime = filemtime($upath->path);
|
$mtime = filemtime($upath->path);
|
||||||
if($upath->query){
|
if ($upath->query) {
|
||||||
$tail = '&'.$mtime;
|
$tail = '&' . $mtime;
|
||||||
|
} else {
|
||||||
|
$tail = '?' . $mtime;
|
||||||
}
|
}
|
||||||
else{
|
} else {
|
||||||
$tail = '?'.$mtime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$tail = '';
|
$tail = '';
|
||||||
}
|
}
|
||||||
return "<link rel='stylesheet' type='text/css' href='{$path}{$tail}' />\n";
|
return "<link rel='stylesheet' type='text/css' href='{$path}{$tail}' />\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function printStaticValues(array $values, bool $pretty=true){
|
public static function printStaticValues(array $values, bool $pretty = true)
|
||||||
if(!count($values)){
|
{
|
||||||
|
if (!count($values)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$lines = ["<script>"];
|
$lines = ["<script>"];
|
||||||
|
|
||||||
foreach($values as $key => $value){
|
foreach ($values as $key => $value) {
|
||||||
$lines[] = "var {$key} = ".Json::encode($value, Json::EMPTY_ARRAY_IS_DICT | ($pretty?Json::PRETTY:0));
|
$lines[] = "var {$key} = " . Json::encode($value, Json::EMPTY_ARRAY_IS_DICT | ($pretty ? Json::PRETTY : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
$lines[] = "</script>\n";
|
$lines[] = "</script>\n";
|
||||||
@@ -195,13 +198,14 @@ class WebUtil
|
|||||||
return join("\n", $lines);
|
return join("\n", $lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function htmlPurify(?string $text): string{
|
public static function htmlPurify(?string $text): string
|
||||||
if(!$text){
|
{
|
||||||
|
if (!$text) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = \HTMLPurifier_HTML5Config::createDefault();
|
$config = \HTMLPurifier_HTML5Config::createDefault();
|
||||||
$config->set('Filter.Custom', array (new \HTMLPurifier_Filter_YouTube()));
|
$config->set('Filter.Custom', array(new \HTMLPurifier_Filter_YouTube()));
|
||||||
$config->set('HTML.SafeIframe', true);
|
$config->set('HTML.SafeIframe', true);
|
||||||
$config->set('URI.SafeIframeRegexp', '%^(https?:)?//(www\.youtube(?:-nocookie)?\.com/embed/|player\.vimeo\.com/video/)%'); //allow YouTube and Vimeo
|
$config->set('URI.SafeIframeRegexp', '%^(https?:)?//(www\.youtube(?:-nocookie)?\.com/embed/|player\.vimeo\.com/video/)%'); //allow YouTube and Vimeo
|
||||||
$def = $config->getHTMLDefinition();
|
$def = $config->getHTMLDefinition();
|
||||||
@@ -210,19 +214,32 @@ class WebUtil
|
|||||||
return $purifier->purify($text);
|
return $purifier->purify($text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function drawMenu(string $path): string{
|
public static function errorBackMsg(string $msg, ?string $target=null): string
|
||||||
if(!file_exists($path)){
|
{
|
||||||
|
$jmsg = Json::encode($msg);
|
||||||
|
if(!$target){
|
||||||
|
$moveNext = 'history.go(-1);';
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$moveNext = "location.replace('{$target}');";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<html><head><style>html,body{background:black;}</style><script>alert({$jmsg});$moveNext</script></head><body></body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function drawMenu(string $path): string
|
||||||
|
{
|
||||||
|
if (!file_exists($path)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
$json = Json::decode(file_get_contents($path));
|
$json = Json::decode(file_get_contents($path));
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach($json as $menuItem){
|
foreach ($json as $menuItem) {
|
||||||
if (count($menuItem) == 2) {
|
if (count($menuItem) == 2) {
|
||||||
[$url, $title] = $menuItem;
|
[$url, $title] = $menuItem;
|
||||||
$targetAttr = '';
|
$targetAttr = '';
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
[$url, $title, $target] = $menuItem;
|
[$url, $title, $target] = $menuItem;
|
||||||
$target = htmlspecialchars($target);
|
$target = htmlspecialchars($target);
|
||||||
$targetAttr = "target='$target' ";
|
$targetAttr = "target='$target' ";
|
||||||
|
|||||||
Reference in New Issue
Block a user