Compare commits

...
20 Commits
Author SHA1 Message Date
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
20 changed files with 465 additions and 32 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키를 입력야 합니다.
## 라이선스
@@ -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);
});
};
}
});
}));
+8
View File
@@ -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,
+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
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')?>
+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;
+4 -10
View File
@@ -976,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) {
@@ -1051,11 +1047,6 @@ function updateNationState() {
]);
$troopID = $db->insertId();
$db->update('nation', [
'gennum'=>$nation['gennum']+1,
'totaltech'=>Util::valueFit($nation['gennum']+1, GameConst::$initialNationGenLimit) * $nation['tech'],
], 'nation=%i', $nation['nation']);
$command = EncodeCommand(0, 0, 0, 26); //집합
$db->update('general', [
'troop'=>$troopID,
@@ -1078,10 +1069,13 @@ function updateNationState() {
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']);
+1 -1
View File
@@ -84,7 +84,7 @@ function process_25(&$general) {
$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',
+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">
+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
]);
+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);
}
+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){
+3 -3
View File
@@ -183,9 +183,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
);
}
+1 -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 계략시 최소 수치 감소량*/
+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>
+1 -1
View File
@@ -107,7 +107,7 @@ function createOTPbyUserNO(int $userNo):bool{
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([
+5
View File
@@ -132,11 +132,16 @@ 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 = [];