Compare commits

...
88 Commits
Author SHA1 Message Date
Hide_D 42310fa170 랜임 개월 수 버그 수정 2018-10-24 01:17:03 +09:00
Hide_D bfff1d9e2f 랜임 모드 버그 수정 2018-10-24 00:54:18 +09:00
Hide_D 2c98777b9f 등용장 무효화 2018-10-23 23:33:12 +09:00
Hide_D 4a91260a31 오타 수정 설명 수정 2018-10-23 16:38:25 +09:00
Hide_D 076971bcae 오타 수정 2018-10-23 16:35:28 +09:00
Hide_D 01fcc9bcab 랜덤 임관 모드 추가 2018-10-23 15:05:19 +09:00
Hide_D 348877c7cd NPC 부대장 수치 버그 수정 2018-10-07 21:46:28 +09:00
sars 478f26e75a camelCase대신 underscore_case 사용 2018-10-04 00:16:08 +09:00
sars 57cc558b9b 장수 동향, 개인 기록, 중원 정세 id 등록 2018-10-04 00:07:46 +09:00
Hide_D 20b1f8eff8 전투 우선순위에 '유니크 아이템'의 효과가 과도하게 측정되는 버그 수정 2018-10-01 23:10:47 +09:00
Hide_D f0a7990404 계략 기본 성공률을 '보급'과 거꾸로 적용한 버그 수정 2018-09-27 17:00:56 +09:00
Hide_D 27f53ff4a6 임관 코드 최종 수정 2018-09-27 16:36:55 +09:00
Hide_D 9ec5dfc8b1 사실 모드 임관 수정 2018-09-27 16:29:49 +09:00
Hide_D e4c1e414c8 사실 모드 랜임 코드 버그 수정 2018-09-27 16:27:38 +09:00
Hide_D a391650472 인증 코드 자리 수 하나 감소 2018-09-25 10:45:21 +09:00
Hide_D 3cfde2b40d 주자사, 공, 황제일 때 장수 수가 내부적으로 1 차이나게 적용되는 버그 수정 2018-09-25 10:12:42 +09:00
Hide_D 8bf1ed33dc 전환 시 '빈칸' 보정, 설명 추가 2018-09-24 04:23:47 +09:00
Hide_D 422b3be0c5 flip image 추가 2018-09-24 04:17:54 +09:00
Hide_D c34e44c4ec data-flip을 허용하고, summernote에 img 태그에 data-flip을 추가하도록 2018-09-24 03:58:40 +09:00
Hide_D a2b20eca67 장수 생성시 초기 스탯으로 '임의 버튼을 클릭'하도록 지정 2018-09-24 02:16:42 +09:00
Hide_D d41c316bfb 설치 설명에서 MariaDB만 지원한다고 변경 2018-09-23 17:31:40 +09:00
Hide_D ca1d8aab84 WebUtil.php에서 drawMenu fallback 추가. 설치시 '활성화되지 않은' KakaoKey.php 파일 추가 2018-09-23 17:31:30 +09:00
Hide_D 32e3dcff7c 이미지 업로드 기능 추가 2018-09-22 03:05:58 +09:00
Hide_D 9a23470622 초반 제한 기간 텍스트 수정 2018-09-21 02:08:51 +09:00
Hide_D c37a186802 툴팁 class 수정. 지도의 년월에 올리면 초반 제한, 기술 제한 툴팁 2018-09-21 02:06:45 +09:00
Hide_D 84c17e3b22 왕조 일람 버그 수정 2018-09-20 02:26:20 +09:00
Hide_D 64e0fca124 전쟁 기한 공식을 스택형으로 변경 2018-09-20 01:15:50 +09:00
Hide_D 5c6537fd7a 멸망 시 접경 재설정 코드 버그 수정 2018-09-20 01:02:29 +09:00
Hide_D 764a82df00 버그 수정 2018-09-20 00:43:36 +09:00
Hide_D e904911fd9 후발 주자에게, 명성, 전특, 내특에 대해 일정 부분 보상 제공 2018-09-20 00:35:38 +09:00
Hide_D a7494f72f6 NPC 부대장에게 포상하지 않도록 수정 2018-09-19 23:56:33 +09:00
Hide_D b6b53b028d 부대탄 유저장도 발령하지 않도록 수정 2018-09-19 23:37:36 +09:00
Hide_D 1743ce714a 전투 코드를 모두 generator 기반으로 변경 2018-09-19 23:29:36 +09:00
Hide_D 656f0c5d11 부대장 주는 횟수 변경 2018-09-19 22:57:06 +09:00
Hide_D d80aebe1f4 집합장 때문에 총 기술치가 깎이는 버그 수정 2018-09-19 22:55:48 +09:00
Hide_D ad48bc1962 접경 내정 상승량 감소는 '수도가 아닐때' 적용 2018-09-19 03:01:38 +09:00
Hide_D d72fbb7098 부대장에게는 금쌀이 제공되지 않도록 수정 2018-09-19 02:21:38 +09:00
Hide_D 95d5eaa09b 주석 수정 2018-09-19 02:13:44 +09:00
Hide_D b997a6159e 치안에 따른 재난 확률 변경 2018-09-19 02:09:08 +09:00
Hide_D 1cd8b7a450 전쟁 중 접경에서는 농상성수 가 제대로 안 오르도록 2018-09-19 02:00:29 +09:00
Hide_D c5a8eb4261 접경지 처리시, 공백지 접경인지 적군 접경인지 구분 2018-09-19 01:49:46 +09:00
Hide_D 8891c29cbd 트래픽이 0인 경우 버그 수정 2018-09-19 01:46:15 +09:00
Hide_D 2facdfa1dd 루드라사움에서도 보병의 성벽 대미지 증가 2018-09-19 01:33:33 +09:00
Hide_D 65c9fa0c21 보병의 성벽 상대 전투력 20% 증가 2018-09-19 01:32:04 +09:00
Hide_D e53c85dbaf 돌격에 저지 불가 제거 2018-09-19 01:16:50 +09:00
Hide_D 3a231e8e61 저지 숙련 증가 2018-09-19 01:00:25 +09:00
Hide_D 4dc7776387 차병은 성벽 전투시 부상을 입지 않음 2018-09-19 00:39:15 +09:00
Hide_D 5ca043e0f1 견고 설명 수정 2018-09-19 00:29:24 +09:00
Hide_D 9ef052c814 견고 추가 상향 2018-09-19 00:28:09 +09:00
Hide_D 6d1690beaa 소울소드 리마스터 시나리오 업데이트 2018-09-18 23:19:30 +09:00
Hide_D 171656e5be 버그 수정 ㅜ 2018-09-18 03:30:40 +09:00
Hide_D 385e7f4871 천통했을 때에는 벌점이 늘어나지 않도록 수정 2018-09-18 03:26:12 +09:00
Hide_D 89c5485784 NPC 안생기는 버그 수정 2018-09-18 03:22:55 +09:00
Hide_D 02d191ec28 변수 대소문자 버그 수정 2018-09-18 03:17:20 +09:00
Hide_D 47c3090f3a NPC 생성 루프 수정 2018-09-18 03:15:40 +09:00
Hide_D 476dac1ac1 주목, 왕이되면 NPC 부대장 하나 더 추가 2018-09-18 02:56:35 +09:00
Hide_D 8ca0d0ced4 메시지 전송 시 장수명 순서대로 정렬 2018-09-18 02:31:41 +09:00
Hide_D ab197489d7 집합장 NPC 삭턴이 실행되지 않는 문제 수정 2018-09-18 02:25:03 +09:00
Hide_D 99736d187b 통합 제의 임시 삭제 2018-09-18 02:15:48 +09:00
Hide_D 197c09bd0d 집합장 턴을 그나마 확인할 수 있도록 삭턴 조정 2018-09-18 02:02:26 +09:00
Hide_D 6cc634ba1f 집합장은 턴이 항상 풀로 차도록.. 2018-09-18 02:01:55 +09:00
Hide_D 4c89ad91d2 부대장 시작 도시를 랜덤으로 2018-09-18 01:56:32 +09:00
Hide_D d66233bce0 NPC 부대장 버그 수정 2018-09-18 01:51:28 +09:00
Hide_D b485e6927e 부대장 번호 버그 수정 2018-09-18 01:47:48 +09:00
Hide_D 74b9e8bd7b 집합장 명칭을 부대장으로 변경 2018-09-18 01:46:37 +09:00
Hide_D 545742ecc0 부대 탄 사람은 발령 로직에서 최대한 배제 2018-09-18 01:27:30 +09:00
Hide_D d9f1f65352 NPC 부대 생성 버그 수정 2018-09-18 01:18:03 +09:00
Hide_D 0904d17a5f 집합장 등장 수식 수정 2018-09-18 00:36:05 +09:00
Hide_D 87171b4246 집합장 테스트 2018-09-18 00:29:44 +09:00
Hide_D 78f8b56203 reset_token에서 불필요한 명령 제거 2018-09-17 23:06:24 +09:00
Hide_D c160c5a555 천통시 모든 국가 등재 장수의 이름이 9글자 인 경우 발생하는 버그 수정 2018-09-12 01:46:16 +09:00
Hide_D 31c7bf5348 메뉴 아이템 길이 버그 2018-09-12 01:16:17 +09:00
Hide_D 6eadf718fc meta keyword 추가 2018-09-12 00:35:50 +09:00
Hide_D effced24d1 sitemap을 위하여 메뉴를 php에서 직접 출력하도록 변경 2018-09-12 00:12:32 +09:00
Hide_D 09f399db9a robots.txt 재등록 2018-09-11 23:50:29 +09:00
Hide_D 2b73f6faea 로봇에 대문자 들어가서 삭제 2018-09-11 23:50:16 +09:00
Hide_D 943662605e Robots.txt 설명 추가 2018-09-11 23:48:02 +09:00
Hide_D 9a04962bd6 대문에 meta 태그 추가 2018-09-11 23:03:10 +09:00
Hide_D c371f6bbb5 refresh_token 변수가 잘못된 것 수정 2018-09-11 11:13:37 +09:00
Hide_D 8324e2e454 access token 체크용 디버그 2018-09-11 11:08:37 +09:00
Hide_D 30307c1b56 로그인 인증 버그 체크 2018-09-11 10:55:53 +09:00
Hide_D f139d0d2a8 로그인 인증 디버깅용 코드 추가 2018-09-10 23:12:27 +09:00
Hide_D 33843764a7 로그인 토큰을 제대로 못 받은 경우 추가 2018-09-10 23:07:44 +09:00
Hide_D aca7d7c571 createOTP 반환형 버그 2018-09-10 01:49:11 +09:00
Hide_D bff72f609c 세션 로그인시 oauth token 값이 제대로 저장 안되는 버그 수정 2018-09-10 01:09:55 +09:00
Hide_D adb03b7420 인증시 로그아웃이 바로 풀리는 버그 수정 2018-09-10 00:38:06 +09:00
Hide_D 2094e18b60 IE에서 인증이 이상한 문제 해결 2018-09-10 00:35:59 +09:00
Hide_D 541d8ddd40 토큰 시간 초과시 즉시 로그아웃 되도록 변경 2018-09-10 00:22:57 +09:00
65 changed files with 1104 additions and 274 deletions
+1
View File
@@ -28,6 +28,7 @@ d_shared
d_pic/*.jpg
d_pic/*.gif
d_pic/*.png
d_pic/uploaded_image
d_setting/*.php
*/d_setting/*.php
+5 -3
View File
@@ -9,8 +9,10 @@
* <code>mpm_event</code> 권장
* PHP 7.2 이상
* <code>php-fpm</code> 권장
* php에서 curl을 실행가능해야 합니다.
* MySQL 5.6 이상, 또는 MariaDB 10.0 이상
* php에서 curl, pdo-sqlite을 실행가능해야 합니다. (기본값: 지원)
* mysqlnd가 지원되어야합니다. (기본값: 지원)
* MariaDB 10.2.1 이상
* MySQL 5.6 이상도 가능하도록 할 예정입니다.
* <code>git</code>
* <code>curl</code>
@@ -47,7 +49,7 @@ Database 수는 로그인 관리 서버 1개, 내부 서버 7개로, 총 8개의
현재 카카오로그인 API KEY를 입력하는 작업이 설치과정에 추가되어있지 않습니다.
<code>f_install/templates/KakaoKey.orig.php</code> 를 <code>d_setting/KakaoKey.php</code>로 복사한 후 API 키를 입력하여야 합니다.
설치 후 <code>d_setting/KakaoKey.php</code>에서 API키를 입력야 합니다.
## 라이선스
+2 -2
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3 -3
View File
File diff suppressed because one or more lines are too long
@@ -0,0 +1,153 @@
/* Forked from https://github.com/asiffermann/summernote-image-title */
(function (factory) {
/* Global define */
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(window.jQuery);
}
}(function ($) {
$.extend(true, $.summernote.lang, {
'en-US': {
imageFlip: {
edit: 'Flip image',
flipLabel: 'Alternative Image'
}
},
'ko-KR': {
imageFlip: {
edit: '이미지 전환',
flipLabel: '대체 이미지( , 로 구분)'
}
},
});
$.extend($.summernote.options, {
imageFlip: {
icon: '<i class="note-icon-pencil"/>',
tooltip: 'Image Flip'
}
});
$.extend($.summernote.plugins, {
'imageFlip': function (context) {
var self = this;
var ui = $.summernote.ui;
var $note = context.layoutInfo.note;
var $editor = context.layoutInfo.editor;
var $editable = context.layoutInfo.editable;
var $toolbar = context.layoutInfo.toolbar;
if (typeof context.options.imageFlip === 'undefined') {
context.options.imageFlip = {};
}
var options = context.options;
var lang = options.langInfo;
context.memo('button.imageFlip', function () {
var button = ui.button({
contents: ui.icon(options.icons.pencil),
container: false,
tooltip: lang.imageFlip.edit,
click: function (e) {
context.invoke('imageFlip.show');
}
});
return button.render();
});
this.initialize = function () {
var $container = options.dialogsInBody ? $(document.body) : $editor;
var body = '<div class="form-group">' +
'<label>' + lang.imageFlip.flipLabel + '</label>' +
'<input class="note-image-flip-text form-control" type="text" />' +
'</div>';
var footer = '<button href="#" class="btn btn-primary note-image-flip-btn">' + lang.imageFlip.edit + '</button>';
this.$dialog = ui.dialog({
title: lang.imageFlip.edit,
body: body,
footer: footer
}).render().appendTo($container);
};
this.destroy = function () {
ui.hideDialog(this.$dialog);
this.$dialog.remove();
};
this.bindEnterKey = function ($input, $btn) {
$input.on('keypress', function (event) {
if (event.keyCode === 13) {
$btn.trigger('click');
}
});
};
this.show = function () {
var $img = $($editable.data('target'));
var imgInfo = {
imgDom: $img,
flip: $img.data('flip'),
};
this.showLinkDialog(imgInfo).then(function (imgInfo) {
ui.hideDialog(self.$dialog);
var $img = imgInfo.imgDom;
if (imgInfo.flip) {
$img.attr('data-flip', imgInfo.flip);
}
else {
$img.removeData('flip');
}
$note.val(context.invoke('code'));
$note.change();
});
};
this.showLinkDialog = function (imgInfo) {
return $.Deferred(function (deferred) {
var $imageFlip = self.$dialog.find('.note-image-flip-text');
var $editBtn = self.$dialog.find('.note-image-flip-btn');
ui.onDialogShown(self.$dialog, function () {
context.triggerEvent('dialog.shown');
$editBtn.click(function (event) {
event.preventDefault();
deferred.resolve({
imgDom: imgInfo.imgDom,
flip: $imageFlip.val(),
});
});
$imageFlip.val(imgInfo.flip).trigger('focus');
self.bindEnterKey($imageFlip, $editBtn);
});
ui.onDialogHidden(self.$dialog, function () {
$editBtn.off('click');
if (deferred.state() === 'pending') {
deferred.reject();
}
});
ui.showDialog(self.$dialog);
});
};
}
});
}));
+1
View File
@@ -52,6 +52,7 @@ $rootDB->insert('member',[
'oauth_type' => 'NONE',
'id' => $username,
'email' => null,
'token_valid_until'=>'2999-01-01 00:00:00',
'pw' => $finalPassword,
'salt' => $userSalt,
'grade'=> 6,
+10 -2
View File
@@ -217,8 +217,8 @@ $result = Util::generateFileUsingSimpleTemplate(
);
$result = Util::generateFileUsingSimpleTemplate(
__dir__.'/templates/menu.orig.js',
ROOT.'/d_shared/menu.js',
__dir__.'/templates/menu.orig.json',
ROOT.'/d_shared/menu.json',
[],
true
);
@@ -263,6 +263,14 @@ $result = Util::generateFileUsingSimpleTemplate(
]
);
Util::generateFileUsingSimpleTemplate(
__dir__.'/templates/KakaoKey.orig.php',
ROOT.'/d_setting/KakaoKey.php',
[
],
true
);
if ($result !== true) {
Json::die([
'result'=>false,
-8
View File
@@ -1,8 +0,0 @@
window.sammo_menu = [
['/bbs/board', '삼모게시판', '_blank'],
['/bbs/tip', '팁/강좌', '_blank'],
['/bbs/news', '삼국 일보', '_blank'],
['/bbs/history2', '개인 열전', '_blank'],
['/bbs/history3', '국가 열전', '_blank'],
['/bbs/patch', '패치 내역', '_blank']
];
+8
View File
@@ -0,0 +1,8 @@
[
["/bbs/board", "삼모게시판", "_blank"],
["/bbs/tip", "팁/강좌", "_blank"],
["/bbs/news", "삼국 일보", "_blank"],
["/bbs/history2", "개인 열전", "_blank"],
["/bbs/history3", "국가 열전", "_blank"],
["/bbs/patch", "패치 내역", "_blank"]
]
+1 -1
View File
@@ -179,7 +179,7 @@ if($showServers){
if($nation['generals']){
$generals = $db->query('SELECT `general_no`, `name`, `last_yearmonth` FROM ng_old_generals WHERE server_id=%s AND general_no IN %li', $serverID, $nation['generals']);
if(count($generals) != $nation['generals'] && $serverID == UniqueConst::$serverID){
if(count($generals) != count($nation['generals']) && $serverID == UniqueConst::$serverID){
$liveGenerals = $nation['generals'];
foreach($generals as $general){
if(in_array($general['general_no'], $nation['generals'])){
+1 -1
View File
@@ -170,7 +170,7 @@ $max_refresh['name'] = '접속자 총합';
$refresh_result = array_merge([$max_refresh], $db->query('SELECT `name`,refresh,`connect` FROM general ORDER BY refresh DESC LIMIT 5'));
foreach ($refresh_result as $i=>$user) {
$w = round($user['refresh'] / $max_refresh['refresh'] * 100, 1);
$w = round($user['refresh'] / max(1, $max_refresh['refresh']) * 100, 1);
$w2 = round(100 - $w, 1);
$color = getTrafficColor($w);
?>
+1
View File
@@ -55,6 +55,7 @@ var editable = <?=($me['level']>=5?'true':'false')?>;
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../e_lib/summernote/summernote-bs4.min.js')?>
<?=WebUtil::printJS('../e_lib/summernote/lang/summernote-ko-KR.js')?>
<?=WebUtil::printJS('../e_lib/summernote/plugin/image-sammo/summernote-image-flip.js')?>
<?=WebUtil::printJS('../d_shared/common_path.js')?>
<?=WebUtil::printJS('js/common.js')?>
<?=WebUtil::printJS('js/dipcenter.js')?>
+1 -1
View File
@@ -177,7 +177,7 @@ for($i=0; $i < $nationcount; $i++) {
";
}
?>
<tr><td colspan=<?=$nationcount+1?> align=center>불가침 : <font color=limegreen>@</font>, 통합 : <font color=cyan>○</font>, 합병 : <font color=skyblue>◎</font>, 통상 : ㆍ, 선포 : <font color=magenta>▲</font>, 교전 : <font color=red>★</font></td></tr>
<tr><td colspan=<?=$nationcount+1?> align=center>불가침 : <font color=limegreen>@</font>, <!--통합 : <font color=cyan>○</font>, -->합병 : <font color=skyblue>◎</font>, 통상 : ㆍ, 선포 : <font color=magenta>▲</font>, 교전 : <font color=red>★</font></td></tr>
</table>
<?php if ($realConflict) : ?>
+4 -1
View File
@@ -150,12 +150,15 @@ if($meLevel >= 5 && $nation["l{$meLevel}set"] == 0) {
echo "
<select name=outlist size=1 style=color:white;background-color:black;>";
$query = "select no,name,level,leader,power,intel,killturn from general where nation='{$me['nation']}' and level!='12' and no!='{$me['no']}' order by npc,binary(name)";
$query = "select no,npc,name,level,leader,power,intel,killturn from general where nation='{$me['nation']}' and level!='12' and no!='{$me['no']}' order by npc,binary(name)";
$result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$gencount = MYDB_num_rows($result);
for($i=0; $i < $gencount; $i++) {
$general = MYDB_fetch_array($result);
if($general['npc'] == 5){
continue;
}
echo "
<option value={$general['no']}>{$general['name']} <small>({$general['leader']}/{$general['power']}/{$general['intel']}, {$general['killturn']}턴)</small></option>";
}
+6
View File
@@ -75,6 +75,12 @@ if($btn == "임명") {
header('location:b_myBossInfo.php');
exit();
}
//NPC 부대장 추방 불가
if($general['npc'] == 5){
header('location:b_myBossInfo.php');
exit();
}
}
//나와 대상 장수는 국가가 같아야 함
+6
View File
@@ -11,6 +11,12 @@
text-align:center;
}
.map_title_tooltiptext .tooltip-inner{
max-width:220px;
width:220px;
text-align: left;
}
.map_title_text{
margin:auto;
text-align:center;
+8 -4
View File
@@ -437,7 +437,7 @@ function commandTable() {
$connect=$db->get();
$userID = Session::getUserID();
$admin = $gameStor->getValues(['startyear', 'year', 'month', 'develcost', 'scenario']);
$admin = $gameStor->getValues(['startyear', 'year', 'month', 'develcost', 'scenario', 'join_mode']);
$query = "select no,npc,troop,city,nation,level,crew,makelimit,special from general where owner='{$userID}'";
$result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
@@ -554,7 +554,10 @@ function commandTable() {
addCommand("인재탐색(랜덤경험, 자금$develcost)", 29, 0);
}
if($me['level'] >= 1 && $city['supply'] != 0) {
if($admin['join_mode'] == 'onlyRandom'){
//do Nothing
}
else if($me['level'] >= 1 && $city['supply'] != 0) {
addCommand("등용(자금{$develcost5}+장수가치)", 22);
} else {
addCommand("등용(자금{$develcost5}+장수가치)", 22, 0);
@@ -709,7 +712,7 @@ function CoreCommandTable() {
addCommand("몰수", 24, $valid);
commandGroup("", 1);
commandGroup("====== 외 교 ======");
addCommand("통합 제의", 53, $valid);
//addCommand("통합 제의", 53, $valid);
addCommand("항복 권고", 51, $valid);
if($nation['level'] >= 2) {
@@ -1252,8 +1255,9 @@ function increaseRefresh($type="", $cnt=1) {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->refresh = $gameStor->refresh+$cnt; //TODO: +로 증가하는 값은 별도로 분리
$isunited = $gameStor->isunited;
if($generalID && $userGrade < 6) {
if($isunited != 2 && $generalID && $userGrade < 6) {
$db->update('general', [
'lastrefresh'=>$date,
'con'=>$db->sqleval('con + %i', $cnt),
+13 -6
View File
@@ -105,12 +105,19 @@ function getTurn(array $general, $type, $font=1) {
case 25: //임관
$double = $command[1];
$nation = getNationStaticInfo($double);
if($double == 98){
$nationName = '건국된 임의 국가';
}
else if($double == 99){
$nationName = '임의의 국가';
}
else{
$nationName = getNationStaticInfo($double)['name']??'?!?!';
}
if(!$nation['name']) { $nation['name'] = '????'; }
$josaRo = JosaUtil::pick($nation['name'], '로');
$str[$i] = "{$nation['name']}{$josaRo} 임관";
$josaRo = JosaUtil::pick($nationName, '로');
$str[$i] = "{$nationName}{$josaRo} 임관";
break;
case 26: //집합
$str[$i] = "집합";
@@ -511,7 +518,7 @@ function processCommand($no) {
case 27: process_27($general); break; //발령
case 51: process_51($general); break; //항복권고
case 52: process_52($general); break; //원조
case 53: process_53($general); break; //통합제의
//case 53: process_53($general); break; //통합제의
case 61: process_61($general); break; //불가침제의
case 62: process_62($general); break; //선전 포고
case 63: process_63($general); break; //종전 제의
+1 -1
View File
@@ -209,7 +209,7 @@ function getSpecialInfo(?int $type):?string{
60 => ['돌격', '[전투] 상대 회피 불가, 공격 시 전투 페이즈 +1, 공격 시 대미지 +10%'],
61 => ['무쌍', '[전투] 대미지 +10%, 공격 시 필살 확률 +10%p'],
62 => ['견고', '[전투] 상대 필살 불가, 상대 계략 시도시 성공 확률 -10%p'],
62 => ['견고', '[전투] 상대 필살, 격노, 위압, 저격 불가, 상대 계략 시도시 성공 확률 -10%p, 부상 없음, 아군 피해 -5%'],
63 => ['위압', '[전투] 훈련/사기≥90, 병력≥1,000 일 때 첫 페이즈 위압 발동(적 공격 불가)'],
70 => ['저격', '[전투] 전투 개시 시 1/3 확률로 저격 발동'],
+60 -14
View File
@@ -229,7 +229,7 @@ function SetNationFront($nationNo) {
if($adj){
$db->update('city', [
'front'=>1
'front'=>($enemyCities?1:2),
], 'nation=%i and city in %li', $nationNo, array_keys($adj));
}
}
@@ -562,11 +562,14 @@ function postUpdateMonthly() {
$genCount = $genNum[$dip['me']];
// 25% 참여율일때 두당 10턴에 4000명 소모한다고 계산
// 4000 / 10 * 0.25 = 100
$term = Util::round($dip['dead'] / 100 / $genCount) + 1;
if($dip['term'] > $term) { $term = $dip['term']; }
if($term > 13) { $term = 13; }
$query = "update diplomacy set term='{$term}' where (me='{$dip['me']}' and you='{$dip['you']}')";
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$term = floor($dip['dead'] / 100 / $genCount);
$dip['dead'] -= $term * 100 * $genCount;
$term = Util::valueFit($dip['term'] + $term, 0, 13);
$db->update('diplomacy', [
'term' => $term,
'dead'=> $dip['dead'],
], 'me = %i AND you = %i', $dip['me'], $dip['you']);
}
//개전국 로그
@@ -609,7 +612,7 @@ function postUpdateMonthly() {
}
pushWorldHistory($history, $admin['year'], $admin['month']);
//사상자 초기화
$query = "update diplomacy set dead=0";
$query = "update diplomacy set dead=0 WHERE state != 0";
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
//외교 기한-1
$query = "update diplomacy set term=term-1 where term!=0";
@@ -960,9 +963,9 @@ function updateNationState() {
$connect=$db->get();
$history = array();
$admin = $gameStor->getValues(['year', 'month']);
$admin = $gameStor->getValues(['year', 'month', 'fiction', 'startyear', 'show_img_level', 'turnterm']);
$query = "select nation,name,level from nation";
$query = "select nation,name,level,gennum,tech from nation";
$nationresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$nationcount = MYDB_num_rows($nationresult);
@@ -973,10 +976,6 @@ function updateNationState() {
$cityresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$citycount = MYDB_num_rows($cityresult);
$query = "select no from general where nation='{$nation['nation']}'";
$genresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$gencount = MYDB_num_rows($genresult);
if($citycount == 0) {
$nationlevel = 0; // 방랑군
} elseif($citycount == 1) {
@@ -996,6 +995,7 @@ function updateNationState() {
}
if($nationlevel > $nation['level']) {
$oldLevel = $nation['level'];
$nation['level'] = $nationlevel;
switch($nationlevel) {
@@ -1020,16 +1020,62 @@ function updateNationState() {
break;
}
$lastAssemblerID = $gameStor->assembler_id??0;
for($levelGen = max(1, $oldLevel) + 1; $levelGen <= $nationlevel; $levelGen+=1){
if(in_array($levelGen, [3, 5, 7])){
$genStep = 2;
}
else{
$genStep = 1;
}
while($genStep > 0){
$lastAssemblerID += 1;
$npcObj = new Scenario\NPC(
999, '부대장'.$lastAssemblerID, null, $nation['nation'], null,
10, 10, 10, 1, $admin['year'] - 15, $admin['year'] + 15, '은둔', '척사'
);
$npcObj->npc = 5;
$npcObj->build($admin);
$npcID = $npcObj->generalID;
$db->insert('troop', [
'name'=>$npcObj->realName,
'nation'=>$nation['nation'],
'no'=>$npcID
]);
$troopID = $db->insertId();
$command = EncodeCommand(0, 0, 0, 26); //집합
$db->update('general', [
'troop'=>$troopID,
'turn0'=>$command,
'turn1'=>$command,
'turn2'=>$command,
'turn3'=>$command,
'turn4'=>$command,
'turn5'=>$command,
'killturn'=>80
], 'no=%i', $npcID);
$genStep -= 1;
}
}
$gameStor->assembler_id = $lastAssemblerID;
//작위 상승
$query = "update nation set level='{$nation['level']}' where nation='{$nation['nation']}'";
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
refreshNationStaticInfo();
}
$gencount = $db->queryFirstField('SELECT count(*) FROM general WHERE nation=%i', $nation['nation']);
$gennum = $gencount;
if($gencount < GameConst::$initialNationGenLimit) $gencount = GameConst::$initialNationGenLimit;
//기술 및 변경횟수 업데이트
$query = "update nation set tech=totaltech/'$gencount',gennum='$gennum' where nation='{$nation['nation']}'";
$query = "update nation set totaltech=tech*'$gencount',gennum='$gennum' where nation='{$nation['nation']}'";
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
}
pushWorldHistory($history, $admin['year'], $admin['month']);
+54 -10
View File
@@ -192,10 +192,34 @@ function processAI($no) {
$isStart = 0;
}
$query = "select no,turn0,npcid,name,nation,nations,city,level,npcmsg,personal,leader,intel,power,gold,rice,crew,train,atmos,npc,affinity,mode,injury,picture,imgsvr,killturn,makelimit,dex0,dex10,dex20,dex30,dex40 from general where no='$no'";
$query = "select no,turn0,npcid,name,nation,nations,city,level,npcmsg,personal,leader,intel,power,gold,rice,crew,train,atmos,troop,npc,affinity,mode,injury,picture,imgsvr,killturn,makelimit,dex0,dex10,dex20,dex30,dex40 from general where no='$no'";
$result = MYDB_query($query, $connect) or Error("processAI01 ".MYDB_error($connect),"");
$general = MYDB_fetch_array($result);
if($general['npc'] == 5){
if($general['nation'] == 0 && $general['killturn'] > 1){
$command = EncodeCommand(0, 0, 0, 0); //휴식
$db->update('general', [
'turn0'=>$command,
'killturn'=>1
], 'no=%i', $general['no']);
}
else{
$command = EncodeCommand(0, 0, 0, 26); //집합
$db->update('general', [
'turn0'=>$command,
'turn1'=>$command,
'turn2'=>$command,
'turn3'=>$command,
'turn4'=>$command,
'turn5'=>$command,
'killturn'=>rand(70,75),
], 'no=%i', $general['no']);
}
return;
}
// 입력된 턴이 있으면 그것 실행
if(DecodeCommand($general['turn0'])[0] != 0) {
return;
@@ -224,7 +248,7 @@ function processAI($no) {
$coreCommand = MYDB_fetch_array($result);
}
$cityCount = $db->queryFirstField('SELECT count(city) FROM city WHERE nation=%i AND supply=1 AND front=1', $general['nation']);
$cityCount = $db->queryFirstField('SELECT count(city) FROM city WHERE nation=%i AND supply=1 AND front>0', $general['nation']);
// 공격가능도시 있으면 1
$attackable = $cityCount > 0;
@@ -467,7 +491,7 @@ function processAI($no) {
SetNationFront($nation['nation']);
$frontCount = $db->queryFirstField('SELECT count(city) FROM city WHERE nation=%i AND front=1', $general['nation']);
$frontCount = $db->queryFirstField('SELECT count(city) FROM city WHERE nation=%i AND front>0', $general['nation']);
if($frontCount > 0){
break;
}
@@ -721,7 +745,7 @@ function processAI($no) {
//전시일때
if($general['gold'] + $general['rice'] < $resrc*2) { $command = EncodeCommand(0, 0, 0, 9); } //금쌀없으면 조달
elseif($general['rice'] > $resrc && $city['rate'] < 95 && $city['front'] == 0) { $command = EncodeCommand(0, 0, 0, 4); } // 우선 선정
elseif($general['rice'] > $resrc && $city['rate'] < 50 && $city['front'] == 1) { $command = EncodeCommand(0, 0, 0, 4); } // 우선 선정
elseif($general['rice'] > $resrc && $city['rate'] < 50 && $city['front'] > 0) { $command = EncodeCommand(0, 0, 0, 4); } // 우선 선정
elseif($general['gold'] < $resrc || ($general['gold'] < $resrc *2 && $general['rice'] > $resrc * 6)) { // 금없으면 쌀팜
$amount = intdiv(($general['rice'] - $general['gold'])/2, 100); // 100단위
if($amount > 0) { $command = EncodeCommand(0, 1, $amount, 49); }// 팜
@@ -803,9 +827,9 @@ function processAI($no) {
if(count($target) == 0) {
//전방 도시 선택, 30% 확률로 태수 있는 전방으로 워프
if(rand()%100 < 30) {
$query = "select city from city where nation='{$general['nation']}' and supply='1' and front=1 order by gen1 desc,rand() limit 0,1";
$query = "select city from city where nation='{$general['nation']}' and supply='1' and front>0 order by gen1 desc,rand() limit 0,1";
} else {
$query = "select city from city where nation='{$general['nation']}' and supply='1' and front=1 order by rand() limit 0,1";
$query = "select city from city where nation='{$general['nation']}' and supply='1' and front>0 order by rand() limit 0,1";
}
$result = MYDB_query($query, $connect) or Error("processAI10 ".MYDB_error($connect),"");
$cityCount = MYDB_num_rows($result);
@@ -913,7 +937,7 @@ function NPCStaffWork($general, $nation, $dipState){
$commandList = [];
foreach($db->query('SELECT `no`, nation, city, npc, `gold`, `rice`, leader, `power`, intel, killturn, crew, train, atmos, `level` FROM general WHERE nation = %i', $general['nation']) as $nationGeneral) {
foreach($db->query('SELECT `no`, nation, city, npc, `gold`, `rice`, leader, `power`, intel, killturn, crew, train, atmos, `level`, troop FROM general WHERE nation = %i', $general['nation']) as $nationGeneral) {
$cityID = $nationGeneral['city'];
$generalID = $nationGeneral['no'];
@@ -1082,7 +1106,15 @@ function NPCStaffWork($general, $nation, $dipState){
}
} else{ // 포상
$compNpcWar = $npcWarGeneralsID?$nationGenerals[$npcWarGeneralsID[0]]:null;
$compNpcCivil = $npcCivilGeneralsID?$nationGenerals[$npcCivilGeneralsID[0]]:null;
$compNpcCivil = null;
foreach($npcCivilGeneralsID??[] as $npcCivilID){
$npcCivil = $nationGenerals[$npcCivilID];
if($npcCivil['npc'] == 5){
continue;
}
$compNpcCivil = $npcCivil;
break;
}
if($compNpcWar && $compNpcWar[$resName] < 21000){
$amount = min(100, intdiv(($nation[$resName]-($resName=='rice'?(GameConst::$baserice):(GameConst::$basegold))), 5000)*10 + 10);
@@ -1171,13 +1203,18 @@ function NPCStaffWork($general, $nation, $dipState){
if($maxDevCity['dev'] >= 95 && $targetCity['city'] != $maxDevCity['city'] && $targetCity['dev'] <= 70){
$targetGeneral = $nationGenerals[Util::choiceRandom($maxDevCity['generals'])];
$commandList[EncodeCommand(0, $targetGeneral['no'], $targetCity['city'], 27)] = 2;
if($targetGeneral['troop'] != 0){
$commandList[EncodeCommand(0, $targetGeneral['no'], $targetCity['city'], 27)] = 2;
}
}
if(count($targetCity['generals']) < count($maxCity['generals']) - 2){
//세명 이상 차이나야 함
$targetGeneral = $nationGenerals[Util::choiceRandom($maxCity['generals'])];
if($targetGeneral['npc']>=2 || $maxCity['dev'] >= 95){
if($targetGeneral['npc']==5){
}
else if($targetGeneral['npc']>=2 || $maxCity['dev'] >= 95 && $targetGeneral['troop'] == 0){
//유저장은 의도가 있을 것이므로 삽나지 않는 이상 발령 안함!
$commandList[EncodeCommand(0, $targetGeneral['no'], $targetCity['city'], 27)] = 5;
}
@@ -1205,6 +1242,10 @@ function NPCStaffWork($general, $nation, $dipState){
if($nationGeneral['train'] * $nationGeneral['atmos'] < 75 * 75){
continue;
}
if($nationGeneral['troop'] != 0){
continue;
}
$score = 5;
if($nationGeneral['npc']<2){
@@ -1255,6 +1296,9 @@ function NPCStaffWork($general, $nation, $dipState){
if($generalCity['pop'] - 33000 > $nationGeneral['leader']){
continue;
}
if($nationGeneral['troop'] != 0){
continue;
}
$score = 5;
if($nationGeneral['npc']<2){
+14
View File
@@ -273,6 +273,10 @@ function process_1(&$general, $type) {
$exp = CharExperience($exp, $general['personal']);
$ded = CharDedication($ded, $general['personal']);
if($city['front'] == 1 && $city['city'] != $nation['capital']){
$score *= 0.5;
}
$score += $city["$stype"];
if($score > $city["{$stype}2"]) { $score = $city["{$stype}2"]; }
// 내정 상승
@@ -558,6 +562,16 @@ function process_5(&$general, $type) {
$exp = $score * 0.7;
$ded = $score * 1.0;
if($city['front'] == 1 && $city['city'] != $nation['capital']){
if($stype == 'def'){
$score *= 0.5;
}
else{
$score *= 0.25;
}
}
// 성격 보정
$exp = CharExperience($exp, $general['personal']);
$ded = CharDedication($ded, $general['personal']);
+29 -5
View File
@@ -11,7 +11,7 @@ function process_22(&$general) {
$history = [];
$date = substr($general['turntime'],11,5);
$admin = $gameStor->getValues(['startyear','year','month','develcost']);
$admin = $gameStor->getValues(['startyear','year','month','develcost','join_mode']);
$query = "select nation,supply from city where city='{$general['city']}'";
$result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
@@ -26,7 +26,10 @@ function process_22(&$general) {
$cost = Util::round($admin['develcost'] + ($you['experience'] + $you['dedication'])/1000) * 10;
if(!$you) {
if($admin['join_mode'] == 'onlyRandom'){
$log[] = "<C>●</>{$admin['month']}월:랜덤 임관만 가능합니다. 등용 실패. <1>$date</>";
}
else if(!$you) {
$log[] = "<C>●</>{$admin['month']}월:없는 장수입니다. 등용 실패. <1>$date</>";
} elseif($admin['year'] < $admin['startyear']+3) {
$log[] = "<C>●</>{$admin['month']}월:초반 제한중입니다. 등용 실패. <1>$date</>";
@@ -70,7 +73,7 @@ function process_25(&$general) {
$history = [];
$date = substr($general['turntime'],11,5);
$admin = $gameStor->getValues(['startyear', 'year', 'month', 'scenario', 'fiction']);
$admin = $gameStor->getValues(['startyear', 'year', 'month', 'scenario', 'fiction', 'join_mode', 'init_year', 'init_month']);
$query = "select nation from city where city='{$general['city']}'";
$result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
@@ -79,12 +82,16 @@ function process_25(&$general) {
$command = DecodeCommand($general['turn0']);
$where = $command[1];
if($admin['join_mode'] == 'onlyRandom' && $where < 98){
$where = 99;
}
$nation = null;
$joinedNations = Json::decode($general['nations']);
// 랜덤임관인 경우
if($general['npc'] > 2 && $where >= 98 && ($admin['scenario'] < 100 || $admin['scenario'] >= 2000 || !$admin['fiction'])){
if($general['npc'] >= 2 && $where >= 98 && !$admin['fiction'] && 1000 <= $admin['scenario'] && $admin['scenario'] < 2000){
//'사실' 모드에서는 '성향'에 우선을 두되, 장수수, 랜덤에 비중을 둠
$nations = $db->query(
'SELECT nation.`name` as `name`,nation.nation as nation,scout,nation.`level` as `level`,gennum,`affinity` FROM nation join general on general.nation = nation.nation and general.level = 12 WHERE nation.nation not in %li and gennum < %i and scout = 0',
@@ -126,10 +133,18 @@ function process_25(&$general) {
$allGen = array_sum($generals);
$genLimit = GameConst::$defaultMaxGeneral;
if($admin['join_mode'] == 'onlyRandom' && TimeUtil::IsRangeMonth($admin['init_year'], $admin['init_month'], 1, $admin['year'], $admin['month'])){
$genLimit = GameConst::$initialNationGenLimitForRandInit;
}
else if($admin['year'] < $admin['startyear'] + 3){
$genLimit = GameConst::$initialNationGenLimit;
}
$nations = $db->query(
'SELECT nation.`name` as `name`,nation.nation as nation,scout,nation.`level` as `level`,gennum,`injury` FROM nation join general on general.nation = nation.nation and general.level = 12 WHERE nation.nation not in %li and gennum < %i and scout = 0',
$joinedNations,
($admin['year'] < $admin['startyear']+3)?GameConst::$initialNationGenLimit:GameConst::$defaultMaxGeneral
$genLimit
);
shuffle($nations);
@@ -152,6 +167,9 @@ function process_25(&$general) {
if($randVals){
$nation = $nations[Util::choiceRandomUsingWeight($randVals)];
}
else{
$nation = null;
}
} else {
$nation = $db->queryFirstRow('SELECT `name`,nation,scout,`level` FROM nation WHERE nation=%i', $where);
@@ -164,6 +182,12 @@ function process_25(&$general) {
if(!$nation) {
$log[] = "<C>●</>{$admin['month']}월:임관할 국가가 없습니다. 임관 실패. <1>$date</>";
if($where >= 98 && $genLimit == GameConst::$initialNationGenLimitForRandInit){
//랜덤 모드, 초기화시에는 랜덤 임관을 대신 한턴 더 넣어준다.
$db->update('general', [
'turn1'=>EncodeCommand(0, 0, $where, 25),
], '`no` = %i', $general['no']);
}
} elseif($general['nation'] != 0) {
$log[] = "<C>●</>{$admin['month']}월:재야가 아닙니다. 임관 실패. <1>$date</>";
} elseif($nation['nation'] == 0) {
+9 -9
View File
@@ -101,7 +101,7 @@ function processGoldIncome() {
$query = "update nation set gold='{$nation['gold']}' where nation='{$nation['nation']}'";
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$query = "select no,name,nation,dedication,gold from general where nation='{$nation['nation']}'";
$query = "select no,name,nation,dedication,gold from general where nation='{$nation['nation']}' AND npc != 5";
$genresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$gencount = MYDB_num_rows($genresult);
@@ -317,7 +317,7 @@ function getGoldOutcome($nation, $bill) {
$db = DB::db();
$connect=$db->get();
$query = "select dedication from general where nation='$nation'"; // 장수 목록
$query = "select dedication from general where nation='$nation' AND npc != 5"; // 장수 목록
$genresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$gencount = MYDB_num_rows($genresult);
@@ -424,7 +424,7 @@ function processRiceIncome() {
$query = "update nation set rice='{$nation['rice']}' where nation='{$nation['nation']}'";
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$query = "select no,name,nation,dedication,rice from general where nation='{$nation['nation']}'";
$query = "select no,name,nation,dedication,rice from general where nation='{$nation['nation']}' AND npc != 5";
$genresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$gencount = MYDB_num_rows($genresult);
@@ -517,7 +517,7 @@ function getRiceOutcome($nation, $bill) {
$db = DB::db();
$connect=$db->get();
$query = "select dedication from general where nation='$nation'"; // 장수 목록
$query = "select dedication from general where nation='$nation' AND npc != 5"; // 장수 목록
$genresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
$gencount = MYDB_num_rows($genresult);
@@ -594,14 +594,14 @@ function disaster() {
for($i=0; $i < $citycount; $i++) {
$city = MYDB_fetch_array($cityresult);
//호황 발생 도시 선택 ( 기본 3% 이므로 약 3개 도시 )
//재해 발생 도시 선택 ( 기본 6% 이므로 약 6개 도시 )
if($isgood == 1) { $ratio = 3 + Util::round(1.0*$city['secu']/$city['secu2']*3); } // 3 ~ 6%
else { $ratio = 6 - Util::round(1.0*$city['secu']/$city['secu2']*3); } // 3 ~ 6%
//호황 발생 도시 선택 ( 기본 2% )
//재해 발생 도시 선택 ( 기본 6% )
if($isgood == 1) { $ratio = 2 + Util::round($city['secu']/$city['secu2']*5); } // 2 ~ 7%
else { $ratio = 6 - Util::round($city['secu']/$city['secu2']*5); } // 1 ~ 6%
if(rand()%100+1 < $ratio) {
$disastercity[] = $city['city'];
$disasterratio[] = 1.0 * $city['secu'] / $city['secu2'];
$disasterratio[] = Util::valueFit($city['secu'] / 0.8 / $city['secu2'], 0, 1);
$disastername[] = $city['name'];
}
}
+3 -3
View File
@@ -282,11 +282,11 @@ else if($session->userGrade == 4){
<td width=498 class='bg1 center'><b>개인 기록</b></td>
</tr>
<tr>
<td width=498 style="text-align:left;"><?=getGeneralPublicRecordRecent(15)?></td>
<td width=498 style="text-align:left;"><?=getGenLogRecent($me['no'], 15)?></td>
<td width=498 id="general_public_record" style="text-align:left;"><?=getGeneralPublicRecordRecent(15)?></td>
<td width=498 id="general_log" style="text-align:left;"><?=getGenLogRecent($me['no'], 15)?></td>
</tr>
<tr><td width=998 colspan=2 class='bg1 center'><b>중원 정세</b></td></tr>
<tr><td width=998 colspan=2 style="text-align:left;"><?=getWorldHistoryRecent(15)?></td></tr>
<tr><td width=998 id="world_history" colspan=2 style="text-align:left;"><?=getWorldHistoryRecent(15)?></td></tr>
</table>
<div class="message_input_form bg0">
<select id="mailbox_list" size="1">
+14
View File
@@ -152,6 +152,20 @@ if($session->userGrade < 5 && !$allowReset){
</div>
</div>
<div class="form-group row">
<label for="join_mode" class="col-sm-3 col-form-label">임관 모드</label>
<div class="col-sm-9">
<div id="join_mode" class="btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-secondary active">
<input type="radio" name="join_mode" value="full" checked>일반
</label>
<label class="btn btn-secondary">
<input type="radio" name="join_mode" value="onlyRandom">랜덤 임관
</label>
</div>
</div>
</div>
<div class="form-group row">
<label for="show_img_level" class="col-sm-3 col-form-label">이미지 표기</label>
<div class="col-sm-9">
+109
View File
@@ -0,0 +1,109 @@
<?php
namespace sammo;
include 'lib.php';
include 'func.php';
$session = Session::requireGameLogin([])->setReadOnly();
$userID = $session::getUserID();
$serverID = UniqueConst::$serverID;
$image = $_FILES['img'];
switch ($image['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
Json::die([
'result'=>false,
'reason'=>'파일이 없습니다.'
]);
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
Json::die([
'result'=>false,
'reason'=>'업로드된 파일이 지나치게 큽니다.'
]);
default:
Json::die([
'result'=>false,
'reason'=>'업로드되지 않았습니다.'
]);
}
if(!is_uploaded_file($image['tmp_name'])) {
Json::die([
'result'=>false,
'reason'=>'제대로 파일이 업로드되지 않았습니다.'
]);
}
if($image['size'] > 1048576) {
//파일크기 검사
Json::die([
'result'=>false,
'reason'=>'1MB 이하로 올려주세요!'
]);
}
$size = getImageSize($image['tmp_name']);
$imageType = $size[2];
$availableImageType = array('.jpg'=>IMAGETYPE_JPEG, '.png'=>IMAGETYPE_PNG, '.gif'=>IMAGETYPE_GIF);
$newExt = array_search($imageType, $availableImageType, true);
if(!$newExt) {
Json::die([
'result'=>false,
'reason'=>'jpg, gif, png 파일이 아닙니다!'
]);
}
$db = RootDB::db();
$imgStor = KVStorage::getStorage($db, 'img_storage');
$picName = hash_file('md5', $image['tmp_name']);
$newPicName = "$picName$newExt";
$destDir = AppConf::getUserIconPathFS().'/uploaded_image';
$dest = $destDir.'/'.$newPicName;
if(!file_exists($dest)){
if (!file_exists($destDir)) {
mkdir($destDir);
}
if(!is_dir($destDir)) {
Json::die([
'result'=>false,
'reason'=>'버그! 업로드 경로 확인!'
]);
}
if(!is_writable($destDir)){
Json::die([
'result'=>false,
'reason'=>'버그! 업로드 권한 확인!'
]);
}
$dest = $destDir.'/'.$newPicName;
if(!move_uploaded_file($image['tmp_name'], $dest)) {
Json::die([
'result'=>false,
'reason'=>'업로드에 실패했습니다!'
]);
}
}
$storedStatus = $imgStor->$newPicName??[];
$imgKey = "$serverID:$userID";
if(!key_exists($imgKey, $storedStatus)){
$storedStatus[$imgKey] = TimeUtil::DatetimeNow();
}
$imgStor->$newPicName = $storedStatus;
Json::die([
'result'=>true,
'reason'=>'성공',
'path'=>AppConf::getUserIconPathWeb().'/uploaded_image/'.$newPicName
]);
+8 -4
View File
@@ -41,6 +41,7 @@ $v->rule('required', [
'scenario',
'fiction',
'extend',
'join_mode',
'npcmode',
'show_img_level'
])->rule('integer', [
@@ -51,8 +52,8 @@ $v->rule('required', [
'extend',
'npcmode',
'show_img_level',
'tournament_trig'
]);
'tournament_trig',
])->rule('in', 'join_mode', ['onlyRandom', 'full']);
if(!$v->validate()){
Json::die([
'result'=>false,
@@ -92,6 +93,7 @@ $extend = (int)$_POST['extend'];
$npcmode = (int)$_POST['npcmode'];
$show_img_level = (int)$_POST['show_img_level'];
$tournament_trig = (int)$_POST['tournament_trig'];
$join_mode = $_POST['join_mode'];
if($reserve_open){
$reserve_open = new \DateTime($reserve_open);
@@ -124,7 +126,8 @@ if($reserve_open){
'npcmode'=>$npcmode,
'show_img_level'=>$show_img_level,
'tournament_trig'=>$tournament_trig,
'gameConf'=>$scenarioObj->getGameConf()
'gameConf'=>$scenarioObj->getGameConf(),
'join_mode'=>$join_mode,
]),
'date'=>$reserve_open->format('Y-m-d H:i:s')
]);
@@ -143,5 +146,6 @@ Json::die(ResetHelper::buildScenario(
$extend,
$npcmode,
$show_img_level,
$tournament_trig
$tournament_trig,
$join_mode
));
+19 -5
View File
@@ -155,26 +155,40 @@ $leader = $leader + $pleader;
$power = $power + $ppower;
$intel = $intel + $pintel;
$admin = $gameStor->getValues(['scenario', 'turnterm', 'show_img_level', 'startyear', 'year']);
$relYear = Util::valueFit($admin['year'] - $admin['startyear'], 0);
$age = 20 + ($pleader + $ppower + $pintel) * 2 - (mt_rand(0, 1));
// 아직 남았고 천재등록상태이면 특기 부여
if ($genius) {
$specage2 = $age;
$special2 = getSpecial2($leader, $power, $intel);
} else {
$specage2 = Util::round((80 - $age)/3) + $age;
$specage2 = Util::valueFit(Util::round((80 - $age)/4 - $relYear / 2), 3) + $age;
$special2 = 0;
}
//내특
$specage = Util::round((80 - $age)/12) + $age;
$specage = Util::valueFit(Util::round((80 - $age)/12 - $relYear / 2), 3) + $age;
$special = 0;
$admin = $gameStor->getValues(['scenario', 'turnterm', 'show_img_level']);
if ($admin['scenario'] >= 1000) {
$specage2 = $age + 3;
$specage = $age + 3;
}
if($relYear < 3){
$experience = 0;
}
else{
$expGenCount = $db->queryFirstField('SELECT count(*) FROM general WHERE nation != 0 AND npc < 5');
$targetGenOrder = Util::round($expGenCount * 0.2);
$experience = $db->queryFirstField(
'SELECT experience FROM general WHERE nation != 0 AND npc < 5 ORDER BY experience ASC LIMIT %i, 1',
$targetGenOrder - 1
);
$experience *= 0.8;
}
$turntime = getRandTurn($admin['turnterm']);
$lastconnect = date('Y-m-d H:i:s');
@@ -211,7 +225,7 @@ $db->insert('general', [
'leader' => $leader,
'power' => $power,
'intel' => $intel,
'experience' => 0,
'experience' => $experience,
'dedication' => 0,
'gold' => 1000,
'rice' => 1000,
+64 -6
View File
@@ -143,18 +143,76 @@ function getIconPath(imgsvr, picture){
}
}
jQuery(function($){
$('.obj_tooltip').tooltip({
title:function(){
return $.trim($(this).find('.tooltiptext').html());
},
html:true
function activeFlip($obj){
var $result;
if($obj === undefined){
$result = $('img[data-flip]');
}
else{
$result = $obj.find('img[data-flip]');
}
$result.each(function(){
activeFlipItem($(this));
});
}
function activeFlipItem($img){
var imageList = [];
imageList.push($img.attr('src'));
$.each($img.data('flip').split(','), function(idx, value){
var value = $.trim(value);
if(!value){
return true;
}
imageList.push(value);
});
if(imageList.length <= 1){
return;
}
$img.data('computed_flip_array', imageList);
$img.data('computed_flip_idx', 0);
$img.click(function(){
var arr = $img.data('computed_flip_array');
var idx = $img.data('computed_flip_idx');
idx = (idx + 1)%(arr.length);
$img.attr('src', arr[idx]);
$img.data('computed_flip_idx', idx);
});
$img.css('cursor','pointer');
}
jQuery(function($){
$('.obj_tooltip').each(function(){
var $objTooltip = $(this);
var tooltipClassText = $objTooltip.data('tooltip-class');
if(!tooltipClassText){
tooltipClassText = '';
}
console.log($objTooltip.data('tooltip-class'));
var template = '<div class="tooltip {0}" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>'
.format(tooltipClassText);
$objTooltip.tooltip({
title:function(){
return $.trim($(this).find('.tooltiptext').html());
},
template:template,
html:true
});
});
activeFlip();
var customCSS = localStorage.getItem('sam_customCSS');
if(customCSS){
var $style = $('<style type="text/css"></style>');
$style.text(customCSS);
$style.appendTo($('head'));
}
});
+58 -1
View File
@@ -15,6 +15,12 @@ jQuery(function($){
function enableEditor(){
editMode = true;
$cancelEdit.show();
var inputText = $noticeInput.val();
if(!inputText || inputText == '<p></p>'){
inputText = '<p><br></p>';
}
$editForm.removeClass('viewer').summernote({
minHeight:200,
maxHeight:null,
@@ -31,10 +37,59 @@ jQuery(function($){
['para', ['ul', 'ol', 'paragraph']],
['height', ['height', 'codeview']]
],
popover: {
image: [
['imagesize', ['imageSize100', 'imageSize50', 'imageSize25']],
['float', ['floatLeft', 'floatRight', 'floatNone']],
['remove', ['removeMedia']],
['custom', ['imageFlip']],
],
},
fontNames: ['맑은 고딕', 'Nanum Gothic', 'Nanum Myeongjo', 'Nanum Pen Script', '굴림', '굴림체', '바탕', '바탕체', '궁서', '궁서체'],
fontSizes: ['8', '9', '10', '11', '12', '14', '16', '20', '24', '28', '32', '36', '40', '46', '52', '60'],
callbacks: {
onImageUpload: function(files) {
$editForm.summernote('saveRange');
if(files.length == 0){
alert('업로드된 파일이 없습니다.');
return false;
}
}).summernote('code', $noticeInput.val());
var formData = new FormData();
formData.append('img', files[0]);
$editForm.summernote("pasteHtml", '');
$.ajax({
type:'post',
url:'j_image_upload.php',
dataType:'json',
contentType: false,
processData:false,
data:formData
}).then(function(result){
if(!result.result){
alert(result.reason);
return;
}
console.log($editForm.summernote('code'));
if($editForm.summernote('isEmpty')){
console.log('haha?');
var $img = $('<img>');
$img.attr('src', result.path);
$editForm.summernote('code', $img);
return;
}
$editForm.summernote("insertImage", result.path, result.path);
},function(){
alert('알 수 없는 이유로 아이콘 업로드를 실패했습니다.');
});
}
}
}).summernote('code', inputText);
}
function disableEditor(){
@@ -42,10 +97,12 @@ jQuery(function($){
$editForm.summernote('destroy');
$cancelEdit.hide();
$editForm.html($noticeInput.val()).addClass('viewer');
activeFlip($editForm);
}
$cancelEdit.hide();
$editForm.html($noticeInput.val());
activeFlip($editForm);
if(editable){
$submitBtn.prop('disabled', false);
}
+4 -2
View File
@@ -114,7 +114,8 @@ function formSetup(){
extend:"required",
npcmode:"required",
show_img_level:"required",
tournament_trig:"required"
tournament_trig:"required",
join_mode:'required',
},
errorElement: "div",
errorPlacement: function ( error, element ) {
@@ -153,7 +154,8 @@ function formSetup(){
npcmode:$('#npcmode input:radio:checked').val(),
show_img_level:$('#show_img_level input:radio:checked').val(),
tournament_trig:$('#tournament_trig input:radio:checked').val(),
reserve_open:$('#reserve_open').val()
reserve_open:$('#reserve_open').val(),
join_mode:$('#join_mode input:radio:checked').val(),
}
}).then(function(result){
var deferred = $.Deferred();
+12
View File
@@ -173,4 +173,16 @@ jQuery(function($){
}
return true;
});
var randomGenType = Math.floor(Math.random()*7);
if(randomGenType < 3){
abilityLeadpow();
}
else if(randomGenType < 6){
abilityLeadint();
}
else{
abilityPowint();
}
});
+26
View File
@@ -90,6 +90,32 @@ function reloadWorldMap(option){
$map_title.css('color', 'yellow');
}
$map_title_tooltip = $('.map_title .tooltiptext');
$map_title_tooltip.empty();
var tooltipTexts = [];
if(year < startYear + 3){
var startYearText = [];
var remainYear = startYear + 3 - year;
var remainMonth = 12 - month + 1;
if(remainMonth > 0){
remainYear -= 1;
}
if(remainYear){
startYearText.push('{0}년'.format(remainYear));
}
if(remainMonth){
startYearText.push('{0}개월'.format(remainMonth));
}
tooltipTexts.push('초반제한 기간 : {0} ({1}년)'.format(startYearText.join(' '), startYear + 3));
}
var currentTechLimit = Math.floor(Math.max(0, year - startYear) / 5) + 1;
var nextTechLimitYear = currentTechLimit * 5 + startYear;
tooltipTexts.push('기술등급 제한 : {0}등급 ({1}년 해제)'.format(currentTechLimit, nextTechLimitYear, currentTechLimit+1));
$map_title_tooltip.html(tooltipTexts.join('<br>'));
$world_map.removeClass('map_string map_summer map_fall map_winter');
if(month <= 3){
+10
View File
@@ -257,6 +257,16 @@ function refreshMailboxList(obj){
$optgroup.css('color', 'white');
}
nation.general.sort(function(lhs, rhs){
if(lhs[1] < rhs[1]){
return -1;
}
if(lhs[1] > rhs[1]){
return 1;
}
return 0;
});
$.each(nation.general, function(){
var generalID = this[0];
var generalName = this[1];
+47 -27
View File
@@ -31,7 +31,7 @@ function processWar(array $rawAttacker, array $rawDefenderCity){
}
$gameStor = KVStorage::getStorage($db, 'game_env');
[$startYear, $year, $month, $cityRate] = $gameStor->getValuesAsArray(['startyear', 'year', 'month', 'city_rate']);
[$startYear, $year, $month, $cityRate, $joinMode] = $gameStor->getValuesAsArray(['startyear', 'year', 'month', 'city_rate', 'join_mode']);
$attacker = new WarUnitGeneral($rawAttacker, $rawAttackerCity, $rawAttackerNation, true, $year, $month);
@@ -154,7 +154,8 @@ function processWar(array $rawAttacker, array $rawDefenderCity){
'startyear'=>$startYear,
'year'=>$year,
'month'=>$month,
'city_rate'=>$cityRate
'city_rate'=>$cityRate,
'join_mode'=>$joinMode,
], $attacker->getRaw(), $city->getRaw(), $rawAttackerNation, $rawDefenderNation);
}
@@ -183,9 +184,9 @@ function extractBattleOrder($general){
$general['leader'] +
$general['power'] +
$general['intel'] +
$general['weap'] +
$general['horse'] +
$general['book'] +
getWeapEff($general['weap']) +
getHorseEff($general['horse']) +
getBookEff($general['book']) +
$general['crew'] / 100
);
}
@@ -270,8 +271,12 @@ function processWar_NG(
$attacker->setOppose($defender);
$defender->setOppose($attacker);
$attacker->checkBattleBeginSkill();
$defender->checkBattleBeginSkill();
foreach(Util::zip(
$attacker->checkBattleBeginSkill(),
$defender->checkBattleBeginSkill()
) as $b){
//doNothing
}
$attacker->checkBattleBeginItem();
$defender->checkBattleBeginItem();
@@ -283,21 +288,33 @@ function processWar_NG(
$attacker->beginPhase();
$defender->beginPhase();
$attacker->checkPreActiveSkill();
$defender->checkPreActiveSkill();
foreach(Util::zip(
$attacker->checkPreActiveSkill(),
$defender->checkPreActiveSkill()
) as $b){
//doNothing
}
$attacker->checkActiveSkill();
$defender->checkActiveSkill();
foreach(Util::zip(
$attacker->checkActiveSkill(),
$defender->checkActiveSkill()
) as $b){
//doNothing
}
//NOTE: 마법은 checkActiveSkill, checkPostActiveSkill 내에서 반영
$attacker->checkPostActiveSkill();
$defender->checkPostActiveSkill();
foreach(Util::zip(
$attacker->checkPostActiveSkill(),
$defender->checkPostActiveSkill()
) as $b){
//doNothing
}
//NOTE: 반계류 등의 스킬을 post에서 반영
$activeSkillIterator = new \AppendIterator();
$activeSkillIterator->append($attacker->applyActiveSkill());
$activeSkillIterator->append($defender->applyActiveSkill());
foreach($activeSkillIterator as $b){
foreach(Util::zip(
$attacker->applyActiveSkill(),
$defender->applyActiveSkill()
) as $b){
//doNothing
}
@@ -498,6 +515,7 @@ function ConquerCity($admin, $general, $city, $nation, $destnation) {
pushNationHistory($destnation, "<C>●</>{$year}{$month}월:<D><b>{$nation['name']}</b></>의 <Y>{$general['name']}</>에 의해 <G><b>{$city['name']}</b></>{$josaYiCity} <span class='ev_highlight'>함락</span>");
$citycount = $db->queryFirstField('SELECT count(city) FROM city WHERE nation = %i', $city['nation']);
$renewFront = false;
// 국가 멸망시
//TODO: 국가 멸망 코드를 별도로 작성
@@ -509,9 +527,6 @@ function ConquerCity($admin, $general, $city, $nation, $destnation) {
$history[] = "<C>●</>{$year}{$month}월:<R><b>【멸망】</b></><D><b>{$losenation['name']}</b></>{$josaYi} 멸망하였습니다.";
pushNationHistory($nation, "<C>●</>{$year}{$month}월:<D><b>{$losenation['name']}</b></>{$josaUl} 정복");
//다굴치는 나라들 전방설정을 위해 미리 얻어옴
$dipNations = $db->queryFirstColumn('SELECT you FROM diplomacy WHERE me = %i', $losenation['nation']);
$loseGeneralGold = 0;
$loseGeneralRice = 0;
//멸망국 장수들 역사 기록 및 로그 전달
@@ -546,7 +561,7 @@ function ConquerCity($admin, $general, $city, $nation, $destnation) {
$loseGeneralRice += $loseRice;
//모두 등용장 발부
if(Util::randBool(0.5)) {
if($admin['join_mode'] != 'onlyRandom' && Util::randBool(0.5)) {
$msg = ScoutMessage::buildScoutMessage($general['no'], $gen['no']);
if($msg){
$msg->send(true);
@@ -554,7 +569,7 @@ function ConquerCity($admin, $general, $city, $nation, $destnation) {
}
//NPC인 경우 10% 확률로 임관(엔장, 인재, 의병)
if($gen['npc'] >= 2 && $gen['npc'] <= 8 && rand() % 100 < 10) {
if($admin['join_mode'] != 'onlyRandom' && $gen['npc'] >= 2 && $gen['npc'] <= 8 && rand() % 100 < 10) {
$commissionCommand = EncodeCommand(0, 0, $nation['nation'], 25); //임관
$query = "update general set turn0='$commissionCommand' where no={$gen['no']}";
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
@@ -615,11 +630,7 @@ function ConquerCity($admin, $general, $city, $nation, $destnation) {
// 국가 삭제
$query = "delete from nation where nation='{$city['nation']}'";
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
// 아까 얻어온 다굴국들 전방설정
foreach($dipNations as $dip){
//전방설정
SetNationFront($dip);
}
$renewFront = true;
// 멸망이 아니면
} else {
// 태수,군사,시중은 일반으로...
@@ -717,6 +728,15 @@ function ConquerCity($admin, $general, $city, $nation, $destnation) {
SetNationFront($conquerNation);
}
if($renewFront){
foreach(getAllNationStaticInfo() as $nation){
if($nation['level'] <= 0){
continue;
}
SetNationFront($nation['nation']);
}
}
pushGenLog($general, $log);
pushGeneralPublicRecord($alllog, $year, $month);
pushWorldHistory($history);
+38 -29
View File
@@ -686,6 +686,9 @@ function command_25($turn, $command) {
$connect=$db->get();
$userID = Session::getUserID();
$gameStor->cacheValues(['year','startyear','month','join_mode']);
$onlyRandom = $gameStor->join_mode == 'onlyRandom';
starter("임관");
$query = "select no,nations from general where owner='{$userID}'";
@@ -700,11 +703,30 @@ function command_25($turn, $command) {
$nationList = $db->query('SELECT nation,`name`,color,scout,scoutmsg,gennum FROM nation ORDER BY rand()');
echo "
foreach($nationList as $nation){
if ($onlyRandom && TimeUtil::IsRangeMonth($gameStor->init_year, $gameStor->init_month, 1, $gameStor->year, $gameStor->month) && $nation['gennum'] >= GameConst::$initialNationGenLimitForRandInit) {
$nation['availableJoin'] = false;
}
else if($gameStor->year < $gameStor->startyear+3 && $nation['gennum'] >= GameConst::$initialNationGenLimit){
$nation['availableJoin'] = false;
}
else if($nation['scout'] == 1) {
$nation['availableJoin'] = false;
}
else{
$nation['availableJoin'] = true;
}
}
?>
국가에 임관합니다.<br>
이미 임관/등용되었던 국가는 다시 임관할 없습니다.<br>
바로 군주의 위치로 이동합니다.<br>
<?php if($onlyRandom): ?>
랜덤 임관 대상 국가는 아래에서 확인할 있습니다.<br>
<?php else: ?>
임관할 국가를 목록에서 선택하세요.<br>
<?php endif; ?>
!!! 방랑군을 포함한 랜덤임관입니다. 유니크를 기대하신다면!<br>
??? 방랑군을 제외한 랜덤임관입니다. 유니크 혜택은 없습니다.<br>
임관 금지이거나 초기 제한중인 국가는 붉은색 배경으로 표시됩니다.<br>
@@ -712,37 +734,24 @@ function command_25($turn, $command) {
<form name=form1 action=c_double.php method=post>
<select name=double size=1 style=color:white;background-color:black>
<option value=99 style=color:white;background-color:black;>!!!</option>
<option value=98 style=color:white;background-color:black;>???</option>";
<option value=98 style=color:white;background-color:black;>???</option>
$scoutStr = "";
foreach($nationList as $nation){
if($gameStor->year < $gameStor->startyear+3 && $nation['gennum'] >= GameConst::$initialNationGenLimit) {
echo "
<option value={$nation['nation']} style=color:{$nation['color']};background-color:red;> {$nation['name']} </option>";
} elseif($nation['scout'] == 1) {
echo "
<option value={$nation['nation']} style=color:{$nation['color']};background-color:red;> {$nation['name']} </option>";
} elseif(in_array($nation['nation'], $joinedNations)) {
/*
echo "
<option value={$nation['nation']} style=color:{$nation['color']};background-color:red; disabled> {$nation['name']} </option>";
*/
} else {
echo "
<option value={$nation['nation']} style=color:{$nation['color']};> {$nation['name']} </option>";
}
}
echo "
<?php foreach($nationList as $nation): ?>
<?php if($nation['availableJoin']): ?>
<option value='<?=$nation['nation']?>' style='color:<?=$nation['color']?>;background-color:red;' <?=$onlyRandom?'disabled':''?>>【 <?=$nation['name']?> 】</option>
<?php else: ?>
<option value='<?=$nation['nation']?>' style='color:<?=$nation['color']?>;' <?=$onlyRandom?'disabled':''?>>【 <?=$nation['name']?> 】</option>
<?php endif; ?>
<?php endforeach; ?>
</select>
<input type=submit value=임관>
<input type=hidden name=command value=$command>";
for($i=0; $i < count($turn); $i++) {
echo "
<input type=hidden name=turn[] value=$turn[$i]>";
}
echo "
</form>";
<input type=hidden name=command value=<?=$command?>>
<?php foreach(range(0, count(turn) - 1) as $i): ?>
<input type=hidden name=turn[] value=<?=$turn[$i]?>>
<?php endforeach; ?>
</form>
<?php
echo getInvitationList($nationList);
ender();
+4 -1
View File
@@ -40,7 +40,7 @@ class GameConstBase
/** @var float 훈련시 사기 감소율*/
public static $atmosSideEffectByTraining = 1;
/** @var float 계략 기본 성공률*/
public static $sabotageDefaultProb = 0.15;
public static $sabotageDefaultProb = 0.35;
/** @var int 계략시 확률 가중치(수치가 클수록 변화가 적음 : (지력차/$firing + $basefiring)*/
public static $sabotageProbCoefByStat = 300;
/** @var int 계략시 최소 수치 감소량*/
@@ -74,6 +74,9 @@ class GameConstBase
/** @var int 최대 기술 레벨 */
public static $maxTechLevel = 12;
/** @var int 초기 제한시 장수 제한 */
public static $initialNationGenLimitForRandInit = 3;
/** @var int 초기 제한시 장수 제한 */
public static $initialNationGenLimit = 10;
+1 -1
View File
@@ -38,7 +38,7 @@ class GameUnitConstBase{
100, 100, 7, 0, 0, 99, 9,
999999, null, null, 999999,
[],//성벽은 공격할 수 없다.
[],
[self::T_FOOTMAN=>1.2],
['성벽입니다.','생성할 수 없습니다.']
],
+5 -1
View File
@@ -107,7 +107,8 @@ class ResetHelper{
int $extend,
int $npcmode,
int $show_img_level,
int $tournament_trig
int $tournament_trig,
string $join_mode
):array{
//FIXME: 분리할 것
if(120 % $turnterm != 0){
@@ -193,6 +194,8 @@ class ResetHelper{
'startyear'=>$startyear,
'year'=> $year,
'month'=> $month,
'init_year'=> $year,
'init_month'=>$month,
'map_theme' => $scenarioObj->getMapTheme(),
'msg'=>'공지사항',//TODO:공지사항
'maxgeneral'=>GameConst::$defaultMaxGeneral,
@@ -207,6 +210,7 @@ class ResetHelper{
'killturn'=>$killturn,
'genius'=>GameConst::$defaultMaxGenius,
'show_img_level'=>$show_img_level,
'join_mode'=>$join_mode,
'npcmode'=>$npcmode,
'extended_general'=>$extend,
'fiction'=>$fiction,
+16 -1
View File
@@ -8,6 +8,9 @@ use \sammo\GameUnitConst;
class NPC{
public $generalID = null;
public $realName = null;
public $affinity;
public $name;
public $picturePath;
@@ -24,6 +27,16 @@ class NPC{
public $charWar = 0;
public $npc = 2;
public $text;
static $prefixList = [
1 => 'ⓝ', //빙의 NPC
2 => 'ⓝ', //NPC
3 => 'ⓜ', //인탐 장수
4 => 'ⓖ', //의병장(전략)
5 => '㉥', //부대장
6 => 'ⓤ', //unselectable npc, 빙의 불가 npc
9 => 'ⓞ', //오랑캐?
];
//[ 1, "헌제",1002, 1, null, 17, 13, 61, 0, 170, 250, "안전", null, "산 넘어 산이로구나..."],
public function __construct(
@@ -156,7 +169,8 @@ class NPC{
$charDomestic = 0;
}
$name = ''.$this->name;
$name = (static::$prefixList[$this->npc]?:'').$this->name;
$this->realName = $name;
$picturePath = $this->picturePath;
if($env['show_img_level'] < 3){
@@ -260,6 +274,7 @@ class NPC{
'bornyear'=>$this->birth,
'deadyear'=>$this->death
]);
$this->generalID = $db->insertId();
return true; //생성되었다.
}
+15 -8
View File
@@ -337,8 +337,8 @@ class WarUnit{
$this->computeWarPower();
}
function checkBattleBeginSkill():bool{
return false;
function checkBattleBeginSkill(){
yield true;
}
function checkBattleBeginItem():bool{
@@ -353,6 +353,13 @@ class WarUnit{
return $this->activatedSkill[$skillName] ?? false;
}
function hasActivatedSkillOnLog(string $skillName):bool{
if(key_exists($skillName, $this->logActivatedSkill)){
return true;
}
return $this->hasActivatedSkill($skillName);
}
function activateSkill(... $skillNames){
foreach($skillNames as $skillName){
$this->activatedSkill[$skillName] = true;
@@ -365,16 +372,16 @@ class WarUnit{
}
}
function checkPreActiveSkill():bool{
return false;
function checkPreActiveSkill(){
yield true;
}
function checkActiveSkill():bool{
return false;
function checkActiveSkill(){
yield true;
}
function checkPostActiveSkill():bool{
return false;
function checkPostActiveSkill(){
yield true;
}
function applyActiveSkill(){
+60 -33
View File
@@ -219,6 +219,9 @@ class WarUnitGeneral extends WarUnit{
else if($specialWar == 61){
$myWarPowerMultiply *= 1.10;
}
else if($specialWar == 62){
$opposeWarPowerMultiply *= 0.95;
}
else if($specialWar == 50){
if($this->isAttacker){
$opposeWarPowerMultiply *= 0.9;
@@ -346,22 +349,35 @@ class WarUnitGeneral extends WarUnit{
}
///전투 개시 시에 작동하여 매 장수마다 작동하는 스킬
function checkBattleBeginSkill():bool{
$skillResult = false;
function checkBattleBeginSkill(){
$oppose = $this->getOppose();
$specialWar = $this->getSpecialWar();
if(
$this->getCrewType()->armType == GameUnitConst::T_SIEGE &&
$oppose->getCrewType()->armType == GameUnitConst::T_CASTLE
){
$this->activateSkill('부상무효');
}
yield true;
if($specialWar == 62){
$oppose->activateSkill('저격불가');
$this->activateSkill('부상무효');
}
yield true;
if (
$specialWar == 70 &&
$this->oppose instanceof WarUnitGeneral &&
!$this->hasActivatedSkill('저격') &&
!$this->hasActivatedSkill('저격불가') &&
Util::randBool(1/3)
) {
$this->activateSkill('저격');
$skillResult = true;
}
return $skillResult;
yield true;
}
///전투 개시 시에 작동하여 매 장수마다 작동하는 아이템
@@ -380,6 +396,7 @@ class WarUnitGeneral extends WarUnit{
$item == 2 &&
$this->oppose instanceof WarUnitGeneral &&
!$this->hasActivatedSkill('저격') &&
!$this->hasActivatedSkill('저격불가') &&
Util::randBool(1/5)
){
//수극
@@ -491,7 +508,7 @@ class WarUnitGeneral extends WarUnit{
return $this->killed;
}
function checkPreActiveSkill():bool{
function checkPreActiveSkill(){
$activated = false;
$oppose = $this->getOppose();
@@ -499,34 +516,33 @@ class WarUnitGeneral extends WarUnit{
$item = $this->getItem();
$crewType = $this->getCrewType();
if($specialWar == 62){
$oppose->activateSkill('필살불가');
$oppose->activateSkill('위압불가');
$oppose->activateSkill('격노불가');
$oppose->activateSkill('계략약화');
}
yield true;
if(
$specialWar == 63 &&
$this->getPhase() == 0 &&
$this->getHP() >= 1000 &&
$this->getComputedAtmos() >= 90 &&
$this->getComputedTrain() >= 90
$this->getComputedTrain() >= 90 &&
!$this->hasActivatedSkill('위압불가')
){
$this->activateSkill('위압');
$activated = true;
}
if($specialWar == 62){
$oppose->activateSkill('필살불가');
$oppose->activateSkill('계략약화');
$activated = true;
}
yield true;
if($specialWar == 60){
$oppose->activateSkill('회피불가');
$oppose->activateSkill('저지불가');
}
return $activated;
yield true;
}
function checkActiveSkill():bool{
$activated = false;
function checkActiveSkill(){
$oppose = $this->getOppose();
$specialWar = $this->getSpecialWar();
$item = $this->getItem();
@@ -542,9 +558,9 @@ class WarUnitGeneral extends WarUnit{
$ratio = $this->getComputedAtmos() + $this->getComputedTrain();
if(Util::randBool($ratio / 400)){
$this->activateSkill('특수', '저지');
$activated = true;
}
}
yield true;
if(
!$this->hasActivatedSkill('특수') &&
@@ -552,8 +568,8 @@ class WarUnitGeneral extends WarUnit{
Util::randBool($this->getComputedCriticalRatio())
){
$this->activateSkill('특수', '필살시도', '필살');
$activated = true;
}
yield true;
if(
!$this->hasActivatedSkill('특수') &&
@@ -561,8 +577,8 @@ class WarUnitGeneral extends WarUnit{
Util::randBool($this->getComputedAvoidRatio())
){
$this->activateSkill('특수', '회피시도', '회피');
$activated = true;
}
yield true;
//계략
if($crewType->magicCoef){
@@ -607,17 +623,16 @@ class WarUnitGeneral extends WarUnit{
}
}
}
yield true;
//의술
if($specialWar == 73 && Util::randBool(0.2)){
$this->activateSkill('치료');
$activated = true;
}
return $activated;
yield true;
}
function checkPostActiveSkill():bool{
function checkPostActiveSkill(){
$activated = false;
$oppose = $this->getOppose();
@@ -625,7 +640,11 @@ class WarUnitGeneral extends WarUnit{
$item = $this->getItem();
$crewType = $this->getCrewType();
if($specialWar == 74 && $oppose->hasActivatedSkill('필살')){
if(
$specialWar == 74 &&
$oppose->hasActivatedSkill('필살') &&
!$this->hasActivatedSkill('격노불가')
){
if($this->isAttacker){
if(Util::randBool(1/3)){
$this->activateSkill('진노', '격노');
@@ -643,10 +662,12 @@ class WarUnitGeneral extends WarUnit{
}
}
}
yield true;
if(
$specialWar == 74 &&
$oppose->hasActivatedSkill('회피')
$oppose->hasActivatedSkill('회피') &&
!$this->hasActivatedSkill('격노불가')
){
if($this->isAttacker){
if(Util::randBool(1/3)){
@@ -668,6 +689,7 @@ class WarUnitGeneral extends WarUnit{
}
}
}
yield true;
if(
($item == 23 || $item == 24) &&
@@ -677,6 +699,7 @@ class WarUnitGeneral extends WarUnit{
$this->activateSkill('치료');
$activated = true;
}
yield true;
//계략
if(
@@ -688,6 +711,7 @@ class WarUnitGeneral extends WarUnit{
$oppose->deactivateSkill('계략');
$activated = true;
}
yield true;
if(
$specialWar == 42 &&
@@ -695,6 +719,7 @@ class WarUnitGeneral extends WarUnit{
){
$this->warPowerMultiply *= 1.3;
}
yield true;
if(
$specialWar == 43 &&
@@ -702,8 +727,7 @@ class WarUnitGeneral extends WarUnit{
){
$this->warPowerMultiply *= 1.5;
}
return $activated;
yield true;
}
function applyActiveSkill(){
@@ -717,8 +741,8 @@ class WarUnitGeneral extends WarUnit{
if($this->hasActivatedSkill('저지')){
$this->addDex($oppose->getCrewType(), $oppose->getWarPower() * 0.5 * 0.9);
$this->addDex($this->getCrewType(), $this->getWarPower() * 0.5 * 0.9);
$this->addDex($oppose->getCrewType(), $oppose->getWarPower() * 0.9);
$this->addDex($this->getCrewType(), $this->getWarPower() * 0.9);
$this->setWarPowerMultiply(0);
$oppose->setWarPowerMultiply(0);
@@ -894,6 +918,9 @@ class WarUnitGeneral extends WarUnit{
}
function tryWound():bool{
if($this->hasActivatedSkillOnLog('부상무효')){
return false;
}
if(!Util::randBool(0.05)){
return false;
}
+66 -24
View File
@@ -13,27 +13,30 @@
"npcMax":95
},
"general":[
[0, "흑뢰의라이제", null, 0, null, 91, 71, 93, 0, 160, 300, null, null],
[0, "성녀마리안", null, 0, null, 92, 71, 92, 0, 160, 300, null, null],
[0, "팔방미녀세정", null, 0, null, 88, 87, 80, 0, 160, 300, null, null],
[0, "빛나는아이오네", null, 0, null, 91, 93, 71, 0, 160, 300, null, null],
[0, "포근한라유", null, 0, null, 92, 92, 71, 0, 160, 300, null, null],
[0, "은랑의제로스", null, 0, null, 93, 91, 71, 0, 160, 300, null, null],
[0, "흑뢰의라이제", null, 0, null, 91, 71, 93, 0, 160, 300, "의협", "집중"],
[0, "성녀마리안", null, 0, null, 92, 71, 92, 0, 160, 300, null, "환술"],
[0, "팔방미녀세정", null, 0, null, 88, 87, 80, 0, 160, 300, "출세", "위압"],
[0, "빛나는아이오네", null, 0, null, 91, 93, 71, 0, 160, 300, "패권", "위압"],
[0, "포근한라유", null, 0, null, 92, 92, 71, 0, 160, 300, null, "돌격"],
[0, "은랑의제로스", null, 0, null, 93, 91, 71, 0, 160, 300, null, "무쌍"],
[0, "악몽술사테리온", null, 0, null, 91, 71, 92, 0, 160, 300, null, null],
[0, "마검의제시카", null, 0, null, 91, 92, 71, 0, 160, 300, null, null],
[0, "분노의슈란", null, 0, null, 91, 92, 71, 0, 160, 300, null, null],
[0, "영광의시아레스", null, 0, null, 92, 91, 71, 0, 160, 300, null, null],
[0, "마검의제시카", null, 0, null, 91, 92, 71, 0, 160, 300, null, "기병"],
[0, "분노의슈란", null, 0, null, 91, 92, 71, 0, 160, 300, null, "궁병"],
[0, "영광의시아레스", null, 0, null, 92, 91, 71, 0, 160, 300, null, "돌격"],
[0, "홍련의리오스", null, 0, null, 92, 91, 71, 0, 160, 300, null, null],
[0, "붉은눈의마모아", null, 0, null, 87, 80, 86, 0, 160, 300, null, null],
[0, "블리자드네로스", null, 0, null, 92, 90, 71, 0, 160, 300, null, null],
[0, "혈광의바이넨", null, 0, null, 91, 92, 70, 0, 160, 300, null, null],
[0, "붉은유성하네드", null, 0, null, 90, 93, 69, 0, 160, 300, null, null],
[0, "아랍왕자애버스", null, 0, null, 86, 81, 85, 0, 160, 300, null, null],
[0, "성검의알렌시아", null, 0, null, 91, 91, 70, 0, 160, 300, null, null],
[0, "뉴페이스마르첼라", null, 0, null, 90, 70, 91, 0, 160, 300, null, null],
[0, "환영의에루다", null, 0, null, 88, 73, 90, 0, 160, 300, null, null],
[0, "마도사나나리", null, 0, null, 91, 70, 90, 0, 160, 300, null, null],
[0, "유혹의유메리아", null, 0, null, 86, 79, 86, 0, 160, 300, null, null],
[0, "유혹의유메리아", null, 0, null, 86, 79, 86, 0, 160, 300, null, null],
[0, "풍요로운오리헨", null, 0, null, 92, 91, 68, 0, 160, 300, null, null],
[0, "리에하르", null, 0, null, 90, 68, 92, 0, 160, 300, null, null],
[0, "유혹의리에하르", null, 0, null, 90, 68, 92, 0, 160, 300, null, null],
[0, "용의기사카헬", null, 0, null, 87, 92, 71, 0, 160, 300, null, null],
[0, "파괴의바스타레", null, 0, null, 85, 82, 82, 0, 160, 300, null, null],
[0, "약속의글로리아", null, 0, null, 90, 92, 67, 0, 160, 300, null, null],
[0, "차가운세피럴", null, 0, null, 88, 69, 91, 0, 160, 300, null, null],
@@ -51,13 +54,15 @@
[0, "약속의카엘", null, 0, null, 85, 89, 70, 0, 160, 300, null, null],
[0, "신농가관지평", null, 0, null, 88, 66, 89, 0, 160, 300, null, null],
[0, "귀여운리모네", null, 0, null, 85, 79, 79, 0, 160, 300, null, null],
[0, "이데아", null, 0, null, 84, 89, 70, 0, 160, 300, null, null],
[0, "공포의이데아", null, 0, null, 84, 89, 70, 0, 160, 300, null, null],
[0, "현장복귀딘", null, 0, null, 86, 89, 68, 0, 160, 300, null, null],
[0, "리나젤", null, 0, null, 86, 90, 67, 0, 160, 300, null, null],
[0, "환수사세라자드", null, 0, null, 88, 89, 66, 0, 160, 300, null, null],
[0, "섬광의마틸다", null, 0, null, 88, 92, 63, 0, 160, 300, null, null],
[0, "건강한꼬마루피나", null, 0, null, 89, 92, 62, 0, 160, 300, null, null],
[0, "마법상인비르시아", null, 0, null, 88, 72, 83, 0, 160, 300, null, null],
[0, "신탁의하노아", null, 0, null, 89, 93, 60, 0, 160, 300, null, null],
[0, "마룡의제크", null, 0, null, 88, 64, 90, 0, 160, 300, null, null],
[0, "광역의블레악스", null, 0, null, 86, 67, 88, 0, 160, 300, null, null],
[0, "유혹의나룬", null, 0, null, 80, 83, 78, 0, 160, 300, null, null],
[0, "정령궁수모니카", null, 0, null, 86, 88, 67, 0, 160, 300, null, null],
@@ -65,11 +70,11 @@
[0, "저주의네로메루", null, 0, null, 86, 64, 90, 0, 160, 300, null, null],
[0, "백련의마르센", null, 0, null, 86, 86, 68, 0, 160, 300, null, null],
[0, "풍광의아이리", null, 0, null, 86, 88, 66, 0, 160, 300, null, null],
[0, "세르펜스", null, 0, null, 89, 60, 90, 0, 160, 300, null, null],
[0, "따뜻한세르펜스", null, 0, null, 89, 60, 90, 0, 160, 300, null, null],
[0, "블랙어스카이로스", null, 0, null, 84, 85, 70, 0, 160, 300, null, null],
[0, "분란의새논", null, 0, null, 87, 86, 65, 0, 160, 300, null, null],
[0, "미소의아스트리아", null, 0, null, 82, 65, 90, 0, 160, 300, null, null],
[0, "어맨더", null, 0, null, 83, 87, 67, 0, 160, 300, null, null],
[0, "섬광의어맨더", null, 0, null, 83, 87, 67, 0, 160, 300, null, null],
[0, "염사의라루아", null, 0, null, 84, 86, 66, 0, 160, 300, null, null],
[0, "뿅망치에멜", null, 0, null, 86, 85, 65, 0, 160, 300, null, null],
[0, "정보상인미세리아", null, 0, null, 86, 60, 89, 0, 160, 300, null, null],
@@ -78,7 +83,7 @@
[0, "찰나의아리스", null, 0, null, 82, 84, 69, 0, 160, 300, null, null],
[0, "흑랑의리코스", null, 0, null, 83, 87, 65, 0, 160, 300, null, null],
[0, "혈광의클라우드", null, 0, null, 84, 88, 63, 0, 160, 300, null, null],
[0, "크리디", null, 0, null, 80, 64, 90, 0, 160, 300, null, null],
[0, "미룡의크리디", null, 0, null, 80, 64, 90, 0, 160, 300, null, null],
[0, "백작부인블론디", null, 0, null, 83, 86, 65, 0, 160, 300, null, null],
[0, "기사렌티온", null, 0, null, 87, 88, 59, 0, 160, 300, null, null],
[0, "셀루아", null, 0, null, 85, 83, 65, 0, 160, 300, null, null],
@@ -86,13 +91,16 @@
[0, "순백의티라", null, 0, null, 71, 72, 89, 0, 160, 300, null, null],
[0, "교황의기사미라이", null, 0, null, 86, 90, 56, 0, 160, 300, null, null],
[0, "맹독의멀독", null, 0, null, 85, 83, 63, 0, 160, 300, null, null],
[0, "트롤왕레우기", null, 0, null, 84, 87, 60, 0, 160, 300, null, null],
[0, "데이나", null, 0, null, 77, 63, 90, 0, 160, 300, null, null],
[0, "바람의무희네바", null, 0, null, 83, 59, 88, 0, 160, 300, null, null],
[0, "웨스트윈드아모스", null, 0, null, 73, 70, 87, 0, 160, 300, null, null],
[0, "루치아", null, 0, null, 83, 80, 67, 0, 160, 300, null, null],
[0, "하이나", null, 0, null, 81, 57, 91, 0, 160, 300, null, null],
[0, "환상의사히누스", null, 0, null, 86, 66, 78, 0, 160, 300, null, null],
[0, "애정의하이나", null, 0, null, 81, 57, 91, 0, 160, 300, null, null],
[0, "스니퍼", null, 0, null, 78, 81, 70, 0, 160, 300, null, null],
[0, "오마주", null, 0, null, 82, 87, 60, 0, 160, 300, null, null],
[0, "분노의오마주", null, 0, null, 82, 87, 60, 0, 160, 300, null, null],
[0, "초록늑대데빌레덤", null, 0, null, 78, 79, 72, 0, 160, 300, null, null],
[0, "이로아스", null, 0, null, 82, 76, 70, 0, 160, 300, null, null],
[0, "광살의에반", null, 0, null, 80, 88, 60, 0, 160, 300, null, null],
[0, "카밀라", null, 0, null, 86, 49, 92, 0, 160, 300, null, null],
@@ -100,19 +108,25 @@
[0, "바람의레지나", null, 0, null, 77, 64, 86, 0, 160, 300, null, null],
[0, "부정의퓨니엄", null, 0, null, 76, 74, 75, 0, 160, 300, null, null],
[0, "흑묘샬롯", null, 0, null, 81, 88, 56, 0, 160, 300, null, null],
[0, "현자제노에오스", null, 0, null, 78, 58, 89, 0, 160, 300, null, null],
[0, "돌풍의루파로", null, 0, null, 78, 66, 81, 0, 160, 300, null, null],
[0, "쥬곤을찾는만텔", null, 0, null, 76, 80, 67, 0, 160, 300, null, null],
[0, "날는알트", null, 0, null, 73, 62, 87, 0, 160, 300, null, null],
[0, "날는알트", null, 0, null, 73, 62, 87, 0, 160, 300, null, null],
[0, "달아오른슈롯셔", null, 0, null, 80, 64, 78, 0, 160, 300, null, null],
[0, "로즈", null, 0, null, 72, 63, 86, 0, 160, 300, null, null],
[0, "막내카라", null, 0, null, 75, 67, 79, 0, 160, 300, null, null],
[0, "리치네", null, 0, null, 78, 65, 78, 0, 160, 300, null, null],
[0, "블랙하운드암푸스", null, 0, null, 74, 80, 66, 0, 160, 300, null, null],
[0, "화염늑대데빌리덤", null, 0, null, 77, 81, 62, 0, 160, 300, null, null],
[0, "검은늑대데빌사울", null, 0, null, 70, 84, 66, 0, 160, 300, null, null],
[0, "흑월의리베스", null, 0, null, 73, 55, 91, 0, 160, 300, null, null],
[0, "혁명의브렉", null, 0, null, 76, 77, 66, 0, 160, 300, null, null],
[0, "에클레", null, 0, null, 73, 83, 63, 0, 160, 300, null, null],
[0, "만텔을쫒는에클레", null, 0, null, 73, 83, 63, 0, 160, 300, null, null],
[0, "타베나", null, 0, null, 77, 80, 62, 0, 160, 300, null, null],
[0, "복수의이벤", null, 0, null, 72, 58, 88, 0, 160, 300, null, null],
[0, "심연의베르", null, 0, null, 72, 79, 67, 0, 160, 300, null, null],
[0, "탐험가로이", null, 0, null, 73, 78, 67, 0, 160, 300, null, null],
[0, "독장미야나가", null, 0, null, 67, 86, 65, 0, 160, 300, null, null],
[0, "미녀기사쥬니아", null, 0, null, 71, 66, 80, 0, 160, 300, null, null],
[0, "스토마", null, 0, null, 69, 69, 79, 0, 160, 300, null, null],
[0, "리사", null, 0, null, 70, 71, 76, 0, 160, 300, null, null],
@@ -124,18 +138,24 @@
[0, "귀환의류나드", null, 0, null, 80, 84, 52, 0, 160, 300, null, null],
[0, "라타", null, 0, null, 73, 69, 73, 0, 160, 300, null, null],
[0, "정령기사한나", null, 0, null, 70, 73, 72, 0, 160, 300, null, null],
[0, "원스", null, 0, null, 77, 82, 56, 0, 160, 300, null, null],
[0, "빙결체이서원스", null, 0, null, 77, 82, 56, 0, 160, 300, null, null],
[0, "초고속승진리체", null, 0, null, 81, 47, 87, 0, 160, 300, null, null],
[0, "푸른늑대데빌덤", null, 0, null, 82, 78, 55, 0, 160, 300, null, null],
[0, "악동듀요라", null, 0, null, 76, 69, 69, 0, 160, 300, null, null],
[0, "에렌디라", null, 0, null, 82, 80, 52, 0, 160, 300, null, null],
[0, "아이스트롤레쿠", null, 0, null, 66, 70, 78, 0, 160, 300, null, null],
[0, "파이어트롤레키", null, 0, null, 59, 73, 82, 0, 160, 300, null, null],
[0, "은발의야마르", null, 0, null, 73, 73, 67, 0, 160, 300, null, null],
[0, "하늘의콜리나", null, 0, null, 74, 77, 62, 0, 160, 300, null, null],
[0, "그림자라이넌", null, 0, null, 70, 59, 84, 0, 160, 300, null, null],
[0, "어스트롤레크", null, 0, null, 61, 72, 80, 0, 160, 300, null, null],
[0, "루이칸", null, 0, null, 73, 66, 73, 0, 160, 300, null, null],
[0, "레이첼", null, 0, null, 70, 68, 73, 0, 160, 300, null, null],
[0, "테이머존덜링", null, 0, null, 67, 72, 72, 0, 160, 300, null, null],
[0, "엘린", null, 0, null, 74, 48, 88, 0, 160, 300, null, null],
[0, "에포스", null, 0, null, 76, 48, 86, 0, 160, 300, null, null],
[0, "아미르", null, 0, null, 69, 64, 77, 0, 160, 300, null, null],
[0, "에타", null, 0, null, 72, 62, 76, 0, 160, 300, null, null],
[0, "혹한의에타", null, 0, null, 72, 62, 76, 0, 160, 300, null, null],
[0, "정령술사도루숨", null, 0, null, 72, 64, 74, 0, 160, 300, null, null],
[0, "차녀카미안", null, 0, null, 72, 76, 62, 0, 160, 300, null, null],
[0, "질니아", null, 0, null, 74, 80, 56, 0, 160, 300, null, null],
@@ -146,9 +166,11 @@
[0, "폭주의란도루", null, 0, null, 70, 51, 87, 0, 160, 300, null, null],
[0, "웬디", null, 0, null, 72, 77, 59, 0, 160, 300, null, null],
[0, "찰스", null, 0, null, 72, 83, 53, 0, 160, 300, null, null],
[0, "윈드트롤레칸", null, 0, null, 57, 75, 76, 0, 160, 300, null, null],
[0, "산들바람젤레", null, 0, null, 68, 52, 87, 0, 160, 300, null, null],
[0, "요하스", null, 0, null, 69, 65, 73, 0, 160, 300, null, null],
[0, "아이노", null, 0, null, 72, 70, 65, 0, 160, 300, null, null],
[0, "욕망의타실리", null, 0, null, 67, 54, 86, 0, 160, 300, null, null],
[0, "홍염의케이시", null, 0, null, 76, 42, 88, 0, 160, 300, null, null],
[0, "소태우스", null, 0, null, 72, 70, 64, 0, 160, 300, null, null],
[0, "빙혼마도사카이", null, 0, null, 74, 43, 88, 0, 160, 300, null, null],
@@ -169,6 +191,7 @@
[0, "레이븐", null, 0, null, 69, 43, 86, 0, 160, 300, null, null],
[0, "투말린", null, 0, null, 72, 69, 57, 0, 160, 300, null, null],
[0, "게르고", null, 0, null, 72, 69, 57, 0, 160, 300, null, null],
[0, "욕망의로이즈", null, 0, null, 73, 37, 88, 0, 160, 300, null, null],
[0, "로렌시아", null, 0, null, 70, 42, 85, 0, 160, 300, null, null],
[0, "달라니카", null, 0, null, 65, 59, 73, 0, 160, 300, null, null],
[0, "레이나", null, 0, null, 66, 56, 74, 0, 160, 300, null, null],
@@ -176,10 +199,12 @@
[0, "안테리나", null, 0, null, 67, 68, 61, 0, 160, 300, null, null],
[0, "쿠벤", null, 0, null, 67, 69, 60, 0, 160, 300, null, null],
[0, "이고트리", null, 0, null, 70, 73, 53, 0, 160, 300, null, null],
[0, "데브라", null, 0, null, 74, 73, 49, 0, 160, 300, null, null],
[0, "데비오스", null, 0, null, 74, 73, 49, 0, 160, 300, null, null],
[0, "리로븐", null, 0, null, 67, 48, 81, 0, 160, 300, null, null],
[0, "칼리오스", null, 0, null, 58, 53, 84, 0, 160, 300, null, null],
[0, "시몬느", null, 0, null, 67, 56, 72, 0, 160, 300, null, null],
[0, "추적자주혜", null, 0, null, 67, 73, 55, 0, 160, 300, null, null],
[0, "크리슈아", null, 0, null, 78, 85, 32, 0, 160, 300, null, null],
[0, "감시자록시", null, 0, null, 58, 56, 80, 0, 160, 300, null, null],
[0, "모멘트", null, 0, null, 61, 70, 63, 0, 160, 300, null, null],
[0, "올거", null, 0, null, 58, 76, 60, 0, 160, 300, null, null],
@@ -187,6 +212,7 @@
[0, "비랑카", null, 0, null, 65, 70, 59, 0, 160, 300, null, null],
[0, "야쿠", null, 0, null, 66, 69, 59, 0, 160, 300, null, null],
[0, "휘크리스", null, 0, null, 70, 74, 50, 0, 160, 300, null, null],
[0, "엔사그니", null, 0, null, 67, 72, 55, 0, 160, 300, null, null],
[0, "사랑찾는메리아", null, 0, null, 68, 39, 86, 0, 160, 300, null, null],
[0, "에벨라", null, 0, null, 62, 46, 85, 0, 160, 300, null, null],
[0, "아리엔", null, 0, null, 72, 44, 77, 0, 160, 300, null, null],
@@ -213,6 +239,7 @@
[0, "모리웬", null, 0, null, 69, 64, 54, 0, 160, 300, null, null],
[0, "메니아드", null, 0, null, 67, 67, 53, 0, 160, 300, null, null],
[0, "담금질중인칸나", null, 0, null, 75, 84, 28, 0, 160, 300, null, null],
[0, "약제사미리움", null, 0, null, 65, 47, 75, 0, 160, 300, null, null],
[0, "장녀카나안", null, 0, null, 70, 32, 84, 0, 160, 300, null, null],
[0, "하나리", null, 0, null, 59, 62, 65, 0, 160, 300, null, null],
[0, "하로데스", null, 0, null, 70, 72, 44, 0, 160, 300, null, null],
@@ -268,6 +295,7 @@
[0, "토리스", null, 0, null, 58, 43, 73, 0, 160, 300, null, null],
[0, "하카세", null, 0, null, 60, 62, 52, 0, 160, 300, null, null],
[0, "모코", null, 0, null, 65, 70, 39, 0, 160, 300, null, null],
[0, "고트리시", null, 0, null, 53, 47, 74, 0, 160, 300, null, null],
[0, "크루피사냐", null, 0, null, 53, 46, 74, 0, 160, 300, null, null],
[0, "에리키오먼", null, 0, null, 63, 38, 72, 0, 160, 300, null, null],
[0, "로윈터", null, 0, null, 53, 64, 56, 0, 160, 300, null, null],
@@ -292,6 +320,7 @@
[0, "에스텔", null, 0, null, 59, 64, 47, 0, 160, 300, null, null],
[0, "가리먼", null, 0, null, 65, 66, 39, 0, 160, 300, null, null],
[0, "타나소스", null, 0, null, 69, 62, 39, 0, 160, 300, null, null],
[0, "안티오그나", null, 0, null, 28, 65, 77, 0, 160, 300, null, null],
[0, "에리사", null, 0, null, 53, 43, 73, 0, 160, 300, null, null],
[0, "미라시아", null, 0, null, 58, 39, 72, 0, 160, 300, null, null],
[0, "루카", null, 0, null, 58, 63, 48, 0, 160, 300, null, null],
@@ -327,7 +356,20 @@
[0, "알리오나", null, 0, null, 53, 34, 72, 0, 160, 300, null, null],
[0, "케시아", null, 0, null, 53, 71, 32, 0, 160, 300, null, null],
[0, "듀라스", null, 0, null, 48, 26, 78, 0, 160, 300, null, null],
[0, "아카시", null, 0, null, 48, 29, 74, 0, 160, 300, null, null]
[0, "아카시", null, 0, null, 48, 29, 74, 0, 160, 300, null, null],
[0, "코르코슘", null, 0, null, 32, 35, 80, 0, 160, 300, null, null],
[0, "휴식의카소아샤", null, 0, null, 33, 77, 33, 0, 160, 300, null, null],
[0, "요청의가스우세", null, 0, null, 33, 33, 77, 0, 160, 300, null, null],
[0, "칼로아눈", null, 0, null, 39, 19, 82, 0, 160, 300, null, null],
[0, "나시루", null, 0, null, 28, 21, 78, 0, 160, 300, null, null],
[0, "비로", null, 0, null, 54, 43, 74, 0, 160, 300, null, null],
[0, "어둠의질레르", null, 0, null, 68, 65, 87, 0, 160, 300, null, null],
[0, "암흑도둑에베넌", null, 0, null, 67, 65, 78, 0, 160, 300, null, null],
[0, "뛰노는차이치", null, 0, null, 64, 52, 69, 0, 160, 300, null, null],
[0, "운명의페인트", null, 0, null, 82, 63, 84, 0, 160, 300, null, null],
[0, "케로베로스바이라", null, 0, null, 79, 73, 72, 0, 160, 300, null, null],
[0, "대장장이시이로", null, 0, null, 78, 67, 54, 0, 160, 300, null, null],
[0, "병기참모프레인", null, 0, null, 88, 60, 77, 0, 160, 300, null, null]
],
"general_ex":[
@@ -336,7 +378,7 @@
],
"history":[
"<C>●</>180년 1월:<L><b>【이벤트】</b></>제작자: 촉구.",
"<C>●</>180년 1월:<L><b>【이벤트】</b></>제작자: 촉구, 관지평",
"<C>●</>180년 1월:<L><b>【가상모드13】</b>소울소드</>",
"<C>●</>180년 1월:<L><b>【이벤트】</b></>혼란스러운 세상을 영웅들과 함께 바로잡아라!"
],
+1 -1
View File
@@ -19,7 +19,7 @@ class GameUnitConst extends GameUnitConstBase
100, 100, 7, 0, 0, 99, 9,
999999, null, null, 999999,
[],//성벽은 공격할 수 없다.
[],
[self::T_FOOTMAN=>1.2],
['성벽입니다.','생성할 수 없습니다.']
],
+2 -2
View File
@@ -627,8 +627,8 @@ CREATE TABLE IF NOT EXISTS `emperior` (
`l6pic` CHAR(32) NULL DEFAULT '',
`l5name` CHAR(64) NULL DEFAULT '',
`l5pic` CHAR(32) NULL DEFAULT '',
`tiger` CHAR(64) NULL DEFAULT '',
`eagle` CHAR(64) NULL DEFAULT '',
`tiger` VARCHAR(128) NULL DEFAULT '',
`eagle` VARCHAR(128) NULL DEFAULT '',
`gen` TEXT NULL DEFAULT '',
`history` MEDIUMTEXT NULL DEFAULT '',
`aux` MEDIUMTEXT NULL DEFAULT '' COMMENT 'json',
+3 -2
View File
@@ -1,7 +1,8 @@
<div class="world_map map_theme_<?=$mapTheme?> draw_required">
<div class="map_title">
<span class="map_title_text">
<div class="map_title obj_tooltip" data-toggle="tooltip" data-placement="top" data-tooltip-class="map_title_tooltiptext">
<span class="map_title_text ">
</span>
<span class="tooltiptext"></span>
</div>
<div class="map_body">
<div class="map_bglayer1"></div>
+2 -2
View File
@@ -12,6 +12,7 @@ $db = RootDB::db();
$notice = $db->queryFirstField('SELECT `NOTICE` FROM `system` WHERE `NO`=1');
$userGrade = $session->userGrade;
$acl = $session->acl;
?>
<!DOCTYPE html>
<html>
@@ -34,8 +35,6 @@ $acl = $session->acl;
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../js/func.js')?>
<?=WebUtil::printJS('../js/entrance.js')?>
<?=WebUtil::printJS('../d_shared/menu.js')?>
<?=WebUtil::printJS('../js/title.js')?>
<?php if ($userGrade >= 5 || $acl): ?>
<!-- 운영자 -->
@@ -53,6 +52,7 @@ $acl = $session->acl;
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<?=WebUtil::drawMenu(ROOT.'/d_shared/menu.json')?>
</ul>
</div>
</nav>
+1 -2
View File
@@ -26,8 +26,6 @@ require(__dir__.'/../vendor/autoload.php');
<?=WebUtil::printJS('../e_lib/moment.min.js')?>
<?=WebUtil::printJS('../js/func.js')?>
<?=WebUtil::printJS('../js/user_info.js')?>
<?=WebUtil::printJS('../d_shared/menu.js')?>
<?=WebUtil::printJS('../js/title.js')?>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
@@ -37,6 +35,7 @@ require(__dir__.'/../vendor/autoload.php');
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<?=WebUtil::drawMenu(ROOT.'/d_shared/menu.json')?>
</ul>
</div>
</nav>
+7 -10
View File
@@ -30,12 +30,16 @@ if ($session->isLoggedIn()) {
<?=WebUtil::printJS('e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('e_lib/jquery.validate.min.js')?>
<?=WebUtil::printJS('e_lib/sha512.min.js')?>
<?=WebUtil::printJS('d_shared/menu.js')?>
<?=WebUtil::printJS('js/common.js')?>
<?=WebUtil::printJS('js/login.js')?>
<?=WebUtil::printJS('js/title.js')?>
<?=WebUtil::printCSS('e_lib/bootstrap.min.css')?>
<?=WebUtil::printCSS('css/login.css')?>
<meta name="description" content="실시간으로 진행되는 삼국지 웹게임(삼모전)입니다">
<meta name="keywords" content="삼국지,삼모전,웹게임,힏체,힏체섭,히데체,히데체섭,HiDCHe,체섭">
<meta property="og:type" content="website">
<meta property="og:title" content="삼국지 모의전투 HiDCHe">
<meta property="og:description" content="실시간으로 진행되는 삼국지 웹게임(삼모전)입니다">
<meta property="og:url" content="https://sam.hided.net">
<script>
var oauthMode = null;
@@ -135,6 +139,7 @@ function postOAuthResult(result){
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<?=WebUtil::drawMenu(ROOT.'/d_shared/menu.json')?>
</ul>
</div>
</nav>
@@ -184,14 +189,6 @@ function postOAuthResult(result){
</div>
</div>
</form>
<!--
<div class="form-group row">
<div class="col-sm-4"><a href="javascript:getOAuthToken('change_pw', 'talk_message');">비밀번호 찾기<img src="oauth_kakao/kakao_to_me.png"></a></div>
<div class="col-sm-8">
</div>
</div>
-->
</div>
</div>
</div>
+11 -5
View File
@@ -41,7 +41,7 @@ function kakaoOAuthCheck(array $userInfo) : ?array {
$refreshTokenValidUntil = $oauthInfo['refreshTokenValidUntil']??null;
$OTPValue = $oauthInfo['OTPValue']??null;
$OTPTrialUntil = $oauthInfo['OTPTrialUntil']??null;
$tokenValidUntil = $member['token_valid_until'];
$tokenValidUntil = $userInfo['token_valid_until'];
if(!$accessToken || !$refreshToken || !$accessTokenValidUntil || !$refreshTokenValidUntil){
return [false, 'OAuth 정보가 보관되어 있지 않습니다. 카카오 로그인을 수행해 주세요.'];
@@ -60,7 +60,12 @@ function kakaoOAuthCheck(array $userInfo) : ?array {
return [false, '로그인 토큰 자동 갱신을 실패했습니다. 카카오 로그인을 수행해 주세요.'];
}
$accessToken = $refreshResult['access_token'];
$accessToken = $refreshResult['access_token']??null;
if(!$accessToken){
trigger_error("refreshToken 에러 ".Json::encode($refreshResult).",".$refreshToken.",".substr(\kakao\KakaoKey::REST_KEY, 0, 6), E_USER_NOTICE);
return [false, '로그인 토큰 자동 갱신을 실패했습니다. 카카오 로그인을 수행해 주세요.'];
}
$accessTokenValidUntil = TimeUtil::DatetimeFromNowSecond($refreshResult['expires_in']);
$oauthInfo['accessToken'] = $accessToken;
@@ -84,6 +89,7 @@ function kakaoOAuthCheck(array $userInfo) : ?array {
}
//인증 시스템 가동
$session = Session::getInstance();
$session->access_token = $accessToken;
$session->expires = $accessTokenValidUntil;
$session->refresh_token = $refreshToken;
@@ -97,7 +103,7 @@ function kakaoOAuthCheck(array $userInfo) : ?array {
}
$userInfo = $RootDB->queryFirstRow(
'SELECT `no`, `id`, `name`, `grade`, `delete_after`, `acl`, oauth_id, oauth_type, oauth_info '.
'SELECT `no`, `id`, `name`, `grade`, `delete_after`, `acl`, oauth_id, oauth_type, oauth_info, token_valid_until '.
'from member where id=%s_username AND '.
'pw=sha2(concat(salt, %s_password, salt), 512)',[
'username'=>$username,
@@ -152,7 +158,7 @@ $RootDB->insert('member_log',[
if($userInfo['oauth_type'] == 'KAKAO'){
$oauthFailResult = kakaoOAuthCheck($userInfo);
if($oauthFailResult !== null){
$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], true, Json::decode($userInfo['acl']??'{}'));
$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], true, $userInfo['token_valid_until'], Json::decode($userInfo['acl']??'{}'));
[$oauthReqOTP, $oauthFailReason] = $oauthFailResult;
Json::die([
'result'=>false,
@@ -163,7 +169,7 @@ if($userInfo['oauth_type'] == 'KAKAO'){
}
$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], false, Json::decode($userInfo['acl']??'{}'));
$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], false, $userInfo['token_valid_until'], Json::decode($userInfo['acl']??'{}'));
Json::die([
'result'=>true,
'reqOTP'=>false,
+3 -1
View File
@@ -56,7 +56,9 @@ $(document).ready( function () {
alert(obj.reason);
return;
}
$('#modalOTP').modal().on('shown.bs.modal', function(){
var $modal = $('#modalOTP').modal();
$modal.on('shown.bs.modal', function(){
$('#otp_code').focus();
});
-15
View File
@@ -1,15 +0,0 @@
jQuery(function($){
$.each(window.sammo_menu, function(idx){
var href = this[0];
var name = this[1];
var target = (this.length > 2)?this[2]:null;
var $a = $('<a class="nav-link" href="{0}">{1}</a>'.format(href, name));
if(target){
$a.attr('target', target);
}
var $li = $('<li class="nav-item"></li>').append($a);
$('#navbarNav .navbar-nav').append($li);
console.log(this);
});
});
+1 -1
View File
@@ -79,7 +79,7 @@ if($OTPValue != $otp){
}
$tokenValidUntil = TimeUtil::DatetimeFromNowDay(10);
$session->setReqOTP(false);
$session->setReqOTP(false, $tokenValidUntil);
RootDB::db()->update('member', [
'oauth_info'=>Json::encode($oauthInfo),
'token_valid_until'=>$tokenValidUntil,
+6 -4
View File
@@ -155,9 +155,11 @@ if($userInfo['delete_after']){
$oauthInfo = Json::decode($userInfo['oauth_info'])??[];
$oauthInfo['accessToken'] = $access_token;
$oauthInfo['refreshToken'] = $refresh_token;
$oauthInfo['accessTokenValidUntil'] = $expires;
$oauthInfo['refreshTokenValidUntil'] = $refresh_token_expires;
if($refresh_token){
$oauthInfo['refreshToken'] = $refresh_token;
$oauthInfo['refreshTokenValidUntil'] = $refresh_token_expires;
}
RootDB::db()->update('member', [
'oauth_info'=>Json::encode($oauthInfo)
@@ -174,7 +176,7 @@ if(!$tokenValidUntil || $tokenValidUntil < $now){
'reason'=>'인증 코드를 보내는데 실패했습니다.'
]);
}
$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], true, Json::decode($userInfo['acl']??'{}'));
$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], true, $userInfo['token_valid_until'], Json::decode($userInfo['acl']??'{}'));
Json::die([
'result'=>false,
'reqOTP'=>true,
@@ -192,7 +194,7 @@ $RootDB->insert('member_log',[
])
]);
$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], false, Json::decode($userInfo['acl']??'{}'));
$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], false, $userInfo['token_valid_until'], Json::decode($userInfo['acl']??'{}'));
Json::die([
'result'=>true,
'reqOTP'=>false,
-1
View File
@@ -31,7 +31,6 @@ if($expectedDate <= $tokenValidUntil){
]);
}
unset($oauthInfo['tokenValidUntil']);
RootDB::db()->update('member', [
'token_valid_until'=> null
], 'no=%i', $userID);
+2 -2
View File
@@ -104,10 +104,10 @@ function createOTPbyUserNO(int $userNo):bool{
return true;
}
function createOTP(string $accessToken):array{
function createOTP(string $accessToken):?array{
$restAPI = new Kakao_REST_API_Helper($accessToken);
$OTPValue = Util::randRangeInt(10000, 99999);
$OTPValue = Util::randRangeInt(1000, 9999);
$OTPTrialUntil = TimeUtil::DatetimeFromNowSecond(180);
$sendResult = $restAPI->talk_to_me_default([
+2
View File
@@ -0,0 +1,2 @@
User-agent: *
Allow: /
+1 -2
View File
@@ -182,8 +182,7 @@ class Kakao_REST_API_Helper
$params = [
'grant_type'=>'refresh_token',
'client_id'=>$this->REST_KEY,
'redirect_uri'=>$this->REDIRECT_URI,
'code'=>$refresh_token
'refresh_token'=>$refresh_token
];
$result = $this->_create_or_refresh_access_token($params);
+19 -5
View File
@@ -10,6 +10,7 @@ namespace sammo;
* @property string $ip IP
* @property bool $reqOTP 인증 코드 필요
* @property array $acl 권한
* @property string $tokenValidUntil 로그인 토큰 길이
*/
class Session
{
@@ -23,6 +24,7 @@ class Session
'writeClosed'=>true,
'generalID'=>true,
'generalName'=>true,
'tokenValidUntil'=>true,
'acl'=>true
];
@@ -165,7 +167,7 @@ class Session
return Util::array_get($_SESSION[$name]);
}
public function login(int $userID, string $userName, int $grade, bool $reqOTP, array $acl): Session
public function login(int $userID, string $userName, int $grade, bool $reqOTP, ?string $tokenValidUntil, array $acl): Session
{
$this->set('userID', $userID);
$this->set('userName', $userName);
@@ -174,11 +176,13 @@ class Session
$this->set('userGrade', $grade);
$this->set('acl', $acl);
$this->set('reqOTP', $reqOTP);
$this->set('tokenValidUntil', $tokenValidUntil);
return $this;
}
public function setReqOTP(bool $reqOTP=false){
public function setReqOTP(bool $reqOTP=false, string $tokenValidUntil){
$this->set('reqOTP', $reqOTP);
$this->set('tokenValidUntil', $tokenValidUntil);
}
@@ -333,10 +337,20 @@ class Session
public function isLoggedIn(bool $ignoreOTP = false): bool
{
if (!$ignoreOTP && $this->reqOTP){
return false;
if(!$ignoreOTP){
if($this->reqOTP){
return false;
}
if(!$this->tokenValidUntil){
return false;
}
$now = TimeUtil::DatetimeNow();
if($this->tokenValidUntil < $now){
return false;
}
}
else if ($this->userID) {
if ($this->userID) {
return true;
} else {
return false;
+1 -1
View File
@@ -177,7 +177,7 @@ class StringUtil
public static function removeSpecialCharacter($str)
{
return str_replace([
'"', '\'', 'ⓝ', 'ⓜ', 'ⓖ', '\\', '/', '`', '#',
'"', '\'', 'ⓝ', 'ⓜ', 'ⓖ', 'ⓞ', 'ⓧ', '㉥', '\\', '/', '`', '#',
'-', '#', '|'
], '', $str);
}
+26
View File
@@ -63,4 +63,30 @@ class TimeUtil
{
return date('H:i:s', strtotime('00:00:00') + $second);
}
/**
* $baseYear, $baseMonth 부터 $afterMonth 개월 이내인지. $afterMonth 포함.
*
*/
public static function IsRangeMonth(int $baseYear, int $baseMonth, int $afterMonth, int $askYear, int $askMonth):bool{
if($baseMonth < 1 || $baseMonth > 12){
throw new \InvalidArgumentException('개월이 올바르지 않음');
}
if($askMonth < 1 || $askMonth > 12){
throw new \InvalidArgumentException('개월이 올바르지 않음');
}
$minMonth = $baseYear * 12 + $baseMonth;
if($afterMonth < 0){
$maxMonth = $minMonth;
$minMonth = $maxMonth - $afterMonth;
}
$maxMonth = $minMonth + $afterMonth;
$askMonth = $askYear * 12 + $askMonth;
if($askMonth < $minMonth || $maxMonth < $askMonth){
return false;
}
return true;
}
}
+18
View File
@@ -60,6 +60,24 @@ class Util extends \utilphp\util
throw new \InvalidArgumentException('올바르지 않은 type 지정');
}
public static function zip(iterable ...$iterators){
while(true){
$hasValue = false;
$values = [];
foreach($iterators as $iter){
if($iter->valid()){
$values[] = $iter->send(NULL);
$hasValue = true;
}
}
yield $values;
if(!$hasValue){
break;
}
}
}
/**
* $_POST, $_GET에서 값을 가져오는 함수. Util::array_get($_POST[$name]) 축약 가능.
* 타입이 복잡해질 경우 함수를 통하지 않고 json으로 요청할 것을 권장.
+27
View File
@@ -132,7 +132,34 @@ class WebUtil
}
$config = \HTMLPurifier_HTML5Config::createDefault();
$def = $config->getHTMLDefinition();
$def->info_global_attr['data-flip'] = new \HTMLPurifier_AttrDef_Text;
$purifier = new \HTMLPurifier($config);
return $purifier->purify($text);
}
public static function drawMenu(string $path): string{
if(!file_exists($path)){
return '';
}
$json = Json::decode(file_get_contents($path));
$result = [];
foreach($json as $menuItem){
if (count($menuItem) == 2) {
[$url, $title] = $menuItem;
$targetAttr = '';
}
else{
[$url, $title, $target] = $menuItem;
$target = htmlspecialchars($target);
$targetAttr = "target='$target' ";
}
$title = htmlspecialchars($title);
$url = htmlspecialchars($url);
$result[] = "<a class='nav-link' href='$url' $targetAttr>$title</a>";
}
return join("\n", $result);
}
}