diff --git a/css/login.css b/css/login.css index 66fdacf3..cf1ef0ae 100644 --- a/css/login.css +++ b/css/login.css @@ -1,131 +1,132 @@ -body, html{ - height: 100%; - background-repeat: no-repeat; -} - -.main{ - margin-top: 70px; -} - -h1.title { - font-size: 50px; - font-family: 'Passion One', cursive; - font-weight: 400; -} - -hr{ - width: 10%; - /*color: #fff;*/ -} - -.form-group{ - margin-bottom: 15px; -} - -label{ - margin-bottom: 15px; -} - -input, -input::-webkit-input-placeholder { - font-size: 11px; - padding-top: 3px; -} - -.main-login{ - /*background-color: #fff;*/ - /* shadows and rounded borders */ - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - border-radius: 2px; - -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); - box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); - -} - -.main-center{ - margin-top: 30px; - margin: 0 auto; - max-width: 330px; - padding: 40px 40px; - -} - -.login_btn_group{ - margin-top: 5px; -} - -.login-register{ - font-size: 11px; - text-align: center; -} - - -.col-form-label{ - text-align:center; -} - -.terms{ - max-height: 200px; overflow-y: auto; -} - -.terms pre{ - width:100%; - white-space: pre-wrap; /* Since CSS 2.1 */ - white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ - white-space: -pre-wrap; /* Opera 4-6 */ - white-space: -o-pre-wrap; /* Opera 7 */ - word-wrap: break-word; /* Internet Explorer 5.5+ */ -} - -.vertical-center { - min-height: 100%; /* Fallback for browsers do NOT support vh unit */ - min-height: 100vh; /* These two lines are counted as one :-) */ - - display: flex; - align-items: center; -} - -.full-content { - position:fixed; - left:0; - top:0; - width:100%; - height:100%; - margin:0; - padding:0; - z-index:800; -} - -#login_card{ - z-index:801; -} - -#btn_kakao_login{ - cursor: pointer; - height:46px; - width:116px; - background-color: transparent; - color:transparent; - border:0; - background-size: 100%; /* To fill the dimensions of container (button), or */ - background-repeat: no-repeat; - background-position: bottom center; - margin-top:5px; - background-image:url('../oauth_kakao/kakao_login_join.png'); -} - -#btn_kakao_login:hover { - background-image:url('../oauth_kakao/kakao_login_join_ov.png'); -} - -#bottom_box{ - position:fixed; - bottom:0; - width:100%; - left:0; -} -#bottom_box .container{ - text-align:center; +body, +html { + height: 100%; + background-repeat: no-repeat; +} + +.main { + margin-top: 70px; +} + +h1.title { + font-size: 50px; + font-family: 'Passion One', cursive; + font-weight: 400; +} + +hr { + width: 10%; + /*color: #fff;*/ +} + +.form-group { + margin-bottom: 15px; +} + +label { + margin-bottom: 15px; +} + +input, +input::-webkit-input-placeholder { + font-size: 11px; + padding-top: 3px; +} + +.main-login { + /*background-color: #fff;*/ + /* shadows and rounded borders */ + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); +} + +.main-center { + margin-top: 30px; + margin: 0 auto; + max-width: 330px; + padding: 40px 40px; +} + +.login_btn_group { + margin-top: 5px; +} + +.login-register { + font-size: 11px; + text-align: center; +} + +.col-form-label { + text-align: center; +} + +.terms { + max-height: 200px; + overflow-y: auto; +} + +.terms pre { + width: 100%; + white-space: pre-wrap; + /* Since CSS 2.1 */ + white-space: -moz-pre-wrap; + /* Mozilla, since 1999 */ + white-space: -pre-wrap; + /* Opera 4-6 */ + white-space: -o-pre-wrap; + /* Opera 7 */ + word-wrap: break-word; + /* Internet Explorer 5.5+ */ +} + +.vertical-center { + min-height: 100%; + /* Fallback for browsers do NOT support vh unit */ + min-height: 100vh; + /* These two lines are counted as one :-) */ + display: flex; + align-items: center; +} + +#login_card { + z-index: 801; +} + +#btn_kakao_login { + cursor: pointer; + height: 46px; + width: 116px; + background-color: transparent; + color: transparent; + border: 0; + background-size: 100%; + /* To fill the dimensions of container (button), or */ + background-repeat: no-repeat; + background-position: bottom center; + margin-top: 5px; + background-image: url('../oauth_kakao/kakao_login_join.png'); +} + +#btn_kakao_login:hover { + background-image: url('../oauth_kakao/kakao_login_join_ov.png'); +} + +#bottom_box .container { + text-align: center; +} + +.btn-group-xs>.btn, +.btn-xs { + padding: .25rem .4rem; + font-size: .875rem; + line-height: .5; + border-radius: .2rem; +} + +#running_map { + margin-top: 20px; } \ No newline at end of file diff --git a/hwe/j_map_recent.php b/hwe/j_map_recent.php index e6cecd03..f557f856 100644 --- a/hwe/j_map_recent.php +++ b/hwe/j_map_recent.php @@ -54,7 +54,7 @@ $defaultPost = [ 'showMe' => false, ]; -$history = getGlobalHistoryLogRecent(15); +$history = formatHistoryToHTML(getGlobalHistoryLogRecent(10)); $rawMap = getWorldMap([ 'year' => null, 'month' => null, @@ -63,7 +63,12 @@ $rawMap = getWorldMap([ 'showMe' => false, ]); +$db = DB::db(); +$gameStor = KVStorage::getStorage($db, 'game_env'); +$mapTheme = $gameStor->map_theme ?? 'che'; + $rawMap['history'] = $history; +$rawMap['theme'] = $mapTheme; $etag = hash('sha256', $serverID.$now); $map = [ diff --git a/hwe/js/map.js b/hwe/js/map.js index 9ddbbda0..871ad48f 100644 --- a/hwe/js/map.js +++ b/hwe/js/map.js @@ -1,654 +1,686 @@ - -function is_touch_device() { - var prefixes = ' -webkit- -moz- -o- -ms- '.split(' '); - var mq = function(query) { - return window.matchMedia(query).matches; - } - - if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) { - return true; - } - - - // include the 'heartz' as a way to have a non matching MQ to help terminate the join - // https://git.io/vznFH - var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''); - return mq(query); - } - -function reloadWorldMap(option){ - var $world_map = $('.world_map'); - - if($world_map.length == 0){ - return; - } - - var defaultOption = { - isDetailMap:true, //복잡 지도, 단순 지도 - clickableAll:false, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도. - selectCallback:null, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행. - hrefTemplate:'#', //도시가 클릭가능할 경우 지정할 href값. {0}은 도시 id로 변환됨 - useCachedMap:false, //맵 캐시를 사용 - - //아래부터는 post query에 들어갈 녀석 - year:null, //year값, 연감등에 사용 - month:null, //month값, 연감등에 사용 - aux:null, //기타 넣고 싶은 값을 입력 - neutralView:false, //clickable, 소속 국가, 첩보 여부 등을 반환여부를 설정 - showMe:true, //반환 값에 본인이 위치한 도시 값을 반환하도록 설정. neutralView와 별개 - targetJson:'j_map.php', - - //기타 보조 값 - startYear:null, - }; - - option = $.extend(defaultOption, option); - - var useCachedMap = option.useCachedMap; - var isDetailMap = option.isDetailMap; - var clickableAll = option.clickableAll; - var selectCallback = option.selectCallback; - var hrefTemplate = option.hrefTemplate; - - var cityPosition = getCityPosition(); - - var storedOldMapKey = 'sam.{0}.map'.format(serverNick); - var storedStartYear = 'sam.{0}.startYear'.format(serverNick); - //OBJ : startYear, year, month, cityList, nationList, spyList, shownByGeneralList, myCity - - function checkReturnObject(obj){ - if(!obj.result){ - var obj = $.Deferred(); - obj.reject('fail'); - return obj.promise(); - } - - if(!$.isNumeric(obj.startYear) - ||!$.isNumeric(obj.year) - ||!$.isNumeric(obj.month) - ){ - var obj = $.Deferred(); - obj.reject('fail'); - return obj.promise(); - } - - if(useCachedMap){ - localStorage.setItem(storedOldMapKey, JSON.stringify([serverID, obj])); - localStorage.setItem(storedStartYear, JSON.stringify(obj.startYear)); - } - - $world_map.removeClass('draw_required'); - - return obj; - } - - function setMapBackground(obj){ - var startYear = obj.startYear; - var year = obj.year; - var month = obj.month; - - if(isDetailMap){ - $world_map.addClass('map_detail').removeClass('map_basic'); - } - else{ - $world_map.addClass('map_basic').removeClass('map_detail'); - } - - var $map_title = $('.map_title_text'); - if(year < startYear + 1){ - $map_title.css('color', 'magenta'); - } - else if(year < startYear + 2){ - $map_title.css('color', 'orange'); - } - else if(year < startYear + 3){ - $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('
')); - - $world_map.removeClass('map_string map_summer map_fall map_winter'); - if(month <= 3){ - $world_map.addClass('map_spring'); - } - else if(month <= 6){ - $world_map.addClass('map_summer'); - } - else if(month <= 9){ - $world_map.addClass('map_fall'); - } - else{ - $world_map.addClass('map_winter'); - } - - $map_title.html('{0}年 {1}月'.format(year, month)); - - return obj; - } - - function convertCityObjs(obj){ - //원본 Obj는 굉장히 간소하게 온다, Object 형태로 변환해서 사용한다. - - function toCityObj(arr){ - return { - id:arr[0], - level:arr[1], - state:arr[2], - nationId:(arr[3]>0)?arr[3]:null, - region:arr[4], - supply:(arr[5]!=0) - }; - } - - function toNationObj(arr){ - return { - id:arr[0], - name:arr[1], - color:arr[2], - capital:arr[3] - }; - } - - var cityList = obj.cityList.map(toCityObj); - var nationList = obj.nationList.map(toNationObj); - nationList = convertDictById(nationList); //array of object -> dict - - var spyList = obj.spyList; - var shownByGeneralList = convertSet(obj.shownByGeneralList);//Array -> Set - - var myCity = obj.myCity; - var myNation = obj.myNation; - - - function mergePositionInfo(city){ - var id = city.id; - if(!(id in cityPosition)){ - return city; - } - var xy_val = cityPosition[id]; - city.name = xy_val[0]; - city.x = xy_val[1]; - city.y = xy_val[2]; - return city; - } - - function mergeNationInfo(city){ - //nationId 값으로 isCapital, color, nation을 통합 - - var nationId = city.nationId; - if(nationId === null || !(nationId in nationList)){ - city.nationId = null; - city.nation = null; - city.color = null; - city.isCapital = false; - return city; - } - - var nationObj = nationList[nationId]; - city.nation = nationObj.name; - city.color = nationObj.color; - city.isCapital = (nationObj.capital == city.id); - - return city; - } - - function mergeClickable(city){ - //clickable = (remainSpy << 3) | (ourCity << 2) | (shownByGeneral << 1) | clickableAll - var id = city.id; - var nationId = city.nationId; - var clickable = 0; - if(id in spyList){ - clickable |= spyList[id] << 3; - } - if(myNation !== null && nationId == myNation){ - clickable |= 4; - } - if(shownByGeneralList.hasOwnProperty(id)){ - clickable |= 2; - } - if(myCity !== null && id == myCity){ - clickable |= 2; - } - if(clickableAll){ - clickable |= 1; - } - - - city.clickable = clickable; - return city; - } - - cityList = cityList - .map(mergePositionInfo) - .map(mergeNationInfo) - .map(mergeClickable) - .map(formatCityInfo); - - return { - 'cityList' : cityList, - 'myCity' : myCity - }; - } - - function drawDetailWorldMap(obj){ - - var $map_body = $('.world_map .map_body'); - - var cityList = obj.cityList; - var myCity = obj.myCity; - - cityList.forEach(function(city){ - var id = city.id; - $('.city_base_{0}'.format(id)).detach(); - //이전 도시는 지운다. - - var $cityObj = $('
'.format(id)); - $cityObj.addClass('city_level_{0}'.format(city.level)); - $cityObj.data('obj', city).css({'left':city.x-20,'top':city.y-15}); - - if('color' in city && city.color !== null){ - var $bgObj = $('
'); - $cityObj.append($bgObj); - $bgObj.css({'background-image':'url({0}/b{1}.png)'.format(pathConfig.gameImage, convColorValue(city.color))}); - } - - var $linkObj = $(''); - $linkObj.data({'text':city.text,'nation':city.nation,'id':city.id}); - $cityObj.append($linkObj); - - var $imgObj = $('
'.format(pathConfig.gameImage, city.level)); - $linkObj.append($imgObj); - - - - if(city.state > 0){ - var $stateObj = $('
'.format(pathConfig.gameImage, city.state)); - $linkObj.append($stateObj); - } - - if(city.nationId && city.nationId > 0){ - var flagType = city.supply?'f':'d'; - var $flagObj = $('
'.format(pathConfig.gameImage, flagType, convColorValue(city.color))); - if(city.isCapital){ - var $capitalObj = $('
'.format(pathConfig.gameImage)); - $flagObj.append($capitalObj); - } - $imgObj.append($flagObj); - } - - var $nameObj = $('{0}'.format(city.name)); - $imgObj.append($nameObj); - - - $map_body.append($cityObj); - - - }); - - $world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city'); - - return obj; - } - - function drawBasicWorldMap(obj){ - - var $map_body = $('.world_map .map_body'); - - var cityList = obj.cityList; - var myCity = obj.myCity; - - cityList.forEach(function(city){ - var id = city.id; - $('.city_base_{0}'.format(id)).detach(); - //이전 도시는 지운다. - - var $cityObj = $('
'.format(id)); - $cityObj.addClass('city_level_{0}'.format(city.level)); - $cityObj.data('obj', city).css({'left':city.x-20,'top':city.y-15}); - - var $linkObj = $(''); - $linkObj.data({'text':city.text,'nation':city.nation,'id':city.id}); - $cityObj.append($linkObj); - - var $imgObj = $('
'); - if('color' in city && city.color !== null){ - $imgObj.css({'background-color':city.color}); - } - $linkObj.append($imgObj); - - if(city.state > 0){ - var state_text = 'wrong'; - if(city.state < 10){ - state_text = 'good'; - } - else if(city.state < 40){ - state_text = 'bad'; - } - else if(city.state < 50){ - state_text = 'war'; - } - - var $stateObj = $('
'.format(state_text)); - $imgObj.append($stateObj); - } - - //단순 표기에서는 깃발 여부가 없음 - if(city.isCapital){ - var $capitalObj = $('
'); - $imgObj.append($capitalObj); - } - - var $nameObj = $('{0}'.format(city.name)); - $imgObj.append($nameObj); - - $map_body.append($cityObj); - }); - - $world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city'); - - return obj; - } - - function setMouseWork(obj){ - var $tooltip = $('.world_map .city_tooltip'); - var $tooltip_city = $tooltip.find('.city_name'); - var $tooltip_nation = $tooltip.find('.nation_name'); - - var $objs = $('.world_map .city_link'); - - var $map_body = $('.world_map .map_body'); - - //터치스크린 탭 - - if(!option.neutralView && is_touch_device()){ - $objs.on('touchstart', function(e){ - if(window.sam_toggleSingleTap){ - return true; - } - var $this = $(this); - - var touchMode = $this.data('touchMode'); - if($tooltip_city.data('target') != $this.data('id')){ - $this.data('touchMode', 1); - } - else if(touchMode === undefined){ - $this.data('touchMode', 1); - } - else{ - $this.data('touchMode', touchMode + 1); - } - $map_body.data('touchMode', 1); - - $tooltip_city.data('target', $this.data('id')); - - - }); - - $objs.on('touchend', function(e){ - if(window.sam_toggleSingleTap){ - return true; - } - var $this = $(this); - var position = $this.parent().position(); - $tooltip_city.html($this.data('text')); - - var nation_text = $this.data('nation'); - if(nation_text){ - $tooltip_nation.html(nation_text).show(); - } - else{ - $tooltip_nation.html('').hide(); - } - - $tooltip.css({'top': position.top + 25, 'left': position.left + 35}).show(); - - var touchMode = $this.data('touchMode'); - if(touchMode <= 1){ - return false; - } - - //xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다. - $this.data('touchMode', 0); - }); - - $map_body.on('touchend',function(e){ - if(window.sam_toggleSingleTap){ - return true; - } - //위의 touchend bind에 해당하지 않는 경우 -> 빈 지도 터치 - $tooltip.hide(); - }); - - } - - //Mouse over 모드 작동 - - $map_body.on('mousemove', function(e){ - if($(this).data('touchMode')){ - return true; - } - - var parentOffset = $map_body.offset(); - var relX = e.pageX - parentOffset.left; - var relY = e.pageY - parentOffset.top; - - $tooltip.css({'top': relY + 10, 'left': relX + 10}); - }); - - $objs.on('mouseenter', function(e){ - if($map_body.data('touchMode')){ - return true; - } - - var $this = $(this); - - $tooltip_city.data('target', $this.data('id')); - $tooltip_city.html($this.data('text')); - var nation_text = $this.data('nation'); - if(nation_text){ - $tooltip_nation.html(nation_text).show(); - } - else{ - $tooltip_nation.html('').hide(); - } - - $tooltip.show(); - }); - - $objs.on('mouseleave', function(event){ - $tooltip.hide(); - }); - - $objs.on('click', function(e){ - //xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다. - var touchMode = $(this).data('touchMode'); - if(touchMode === undefined){ - return; - } - - if(touchMode === 1){ - return false; - } - }); - - - return obj; - } - - function setCityClickable(obj){ - - obj.cityList.forEach(function(city){ - var $cityLink = $world_map.find('.city_base_{0} .city_link'.format(city.id)); - - if('clickable' in city && city.clickable > 0){ - $cityLink.attr('href',hrefTemplate.format(city.id)); - } - - if(selectCallback){ - $cityLink.click(function(){ - return selectCallback(city); - }); - } - }); - - return obj; - } - - function saveCityInfo(obj){ - $world_map.data('cityInfo', obj); - return obj; - } - - var $hideCityNameBtn = $world_map.find('.map_toggle_cityname'); - if(localStorage.getItem('sam.hideMapCityName') == 'yes'){ - $world_map.addClass('hide_cityname'); - $hideCityNameBtn.addClass('active').attr('aria-pressed', 'true'); - } - - $hideCityNameBtn.click(function(){ - //이전 상태 확인 - var state = !$hideCityNameBtn.hasClass('active'); - if(state){ - $world_map.addClass('hide_cityname'); - localStorage.setItem('sam.hideMapCityName', 'yes'); - } - else{ - $world_map.removeClass('hide_cityname'); - localStorage.setItem('sam.hideMapCityName', 'no'); - } - }); - - var $toggleSingleTapBtn = $world_map.find('.map_toggle_single_tap'); - if(localStorage.getItem('sam.toggleSingleTap') == 'yes'){ - window.sam_toggleSingleTap = true; - $toggleSingleTapBtn.addClass('active').attr('aria-pressed', 'true'); - } - else{ - window.sam_toggleSingleTap = false; - } - - var $map_body = $('.world_map .map_body'); - - $toggleSingleTapBtn.click(function(){ - //이전 상태 확인 - var state = !$toggleSingleTapBtn.hasClass('active'); - if(state){ - $map_body.removeData('touchMode'); - localStorage.setItem('sam.toggleSingleTap', 'yes'); - window.sam_toggleSingleTap = true; - } - else{ - localStorage.setItem('sam.toggleSingleTap', 'no'); - window.sam_toggleSingleTap = false; - } - }); - - if(isDetailMap){ - $world_map.addClass('map_detail'); - } - else{ - $world_map.removeClass('map_datail'); - } - - //deferred mode of jQuery. != promise-then. - var deferred = $.ajax({ - url: option.targetJson, - type: 'post', - dataType:'json', - data: { - data: JSON.stringify({ - neutralView:option.neutralView, - year:option.year, - month:option.month, - showMe:option.showMe, - aux:option.aux - }) - } - }); - - deferred - .then(checkReturnObject) - .then(setMapBackground) - .then(convertCityObjs) - .then(isDetailMap?drawDetailWorldMap:drawBasicWorldMap) - .then(setMouseWork) - .then(setCityClickable) - .then(saveCityInfo); - - if($world_map.hasClass('draw_required')){ - if(useCachedMap){ - //일단 불러옴 - do{ - var storedMap = localStorage.getItem(storedOldMapKey); - if(!storedMap){ - break; - } - storedMap = JSON.parse(storedMap); - var storedServerID = storedMap[0]; - if(storedServerID != serverID){ - break; - } - - storedMap = storedMap[1]; - storedMap = setMapBackground(storedMap); - storedMap = convertCityObjs(storedMap); - if(isDetailMap){ - storedMap = drawDetailWorldMap(storedMap); - } - else{ - storedMap = drawBasicWorldMap(storedMap); - } - storedMap = setMouseWork(storedMap); - storedMap = setCityClickable(storedMap); - storedMap = saveCityInfo(storedMap); - }while(false); - } - else if(option.year && option.month){ - var startYear = localStorage.getItem(storedStartYear); - if(startYear){ - startYear = JSON.parse(startYear); - } - else{ - startYear = option.year; - } - var tmp = { - year : option.year, - month : option.month, - startYear : startYear - }; - setMapBackground(tmp); - } - - - } -} -$(function(){ - if(is_touch_device()){ - $('.map_body .map_toggle_single_tap').show(); - } +function is_touch_device() { + var prefixes = ' -webkit- -moz- -o- -ms- '.split(' '); + var mq = function(query) { + return window.matchMedia(query).matches; + } + + if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) { + return true; + } + + + // include the 'heartz' as a way to have a non matching MQ to help terminate the join + // https://git.io/vznFH + var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''); + return mq(query); +} + +function reloadWorldMap(option, drawTarget) { + if (drawTarget === undefined || drawTarget === null) { + drawTarget = '.world_map' + } + var $world_map = $(drawTarget); + + if ($world_map.length == 0) { + return; + } + + var defaultOption = { + isDetailMap: true, //복잡 지도, 단순 지도 + clickableAll: false, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도. + selectCallback: null, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행. + hrefTemplate: '#', //도시가 클릭가능할 경우 지정할 href값. {0}은 도시 id로 변환됨 + useCachedMap: false, //맵 캐시를 사용 + + //아래부터는 post query에 들어갈 녀석 + year: null, //year값, 연감등에 사용 + month: null, //month값, 연감등에 사용 + aux: null, //기타 넣고 싶은 값을 입력 + neutralView: false, //clickable, 소속 국가, 첩보 여부 등을 반환여부를 설정 + showMe: true, //반환 값에 본인이 위치한 도시 값을 반환하도록 설정. neutralView와 별개 + + targetJson: 'j_map.php', + reqType: 'post', + dynamicMapTheme: false, + callback: null, + + //기타 보조 값 + startYear: null, + }; + + option = $.extend(defaultOption, option); + + var useCachedMap = option.useCachedMap; + var isDetailMap = option.isDetailMap; + var clickableAll = option.clickableAll; + var selectCallback = option.selectCallback; + var hrefTemplate = option.hrefTemplate; + + var cityPosition = getCityPosition(); + + var storedOldMapKey = 'sam.{0}.map'.format(serverNick); + var storedStartYear = 'sam.{0}.startYear'.format(serverNick); + //OBJ : startYear, year, month, cityList, nationList, spyList, shownByGeneralList, myCity + + function checkReturnObject(obj) { + if (!obj.result) { + var obj = $.Deferred(); + obj.reject('fail'); + return obj.promise(); + } + + if (!$.isNumeric(obj.startYear) || + !$.isNumeric(obj.year) || + !$.isNumeric(obj.month) + ) { + var obj = $.Deferred(); + obj.reject('fail'); + return obj.promise(); + } + + if (useCachedMap) { + localStorage.setItem(storedOldMapKey, JSON.stringify([serverID, obj])); + localStorage.setItem(storedStartYear, JSON.stringify(obj.startYear)); + } + + $world_map.removeClass('draw_required'); + + return obj; + } + + + + function setMapBackground(obj) { + function setTheme() { + var oldTheme = $world_map.data('currentTheme'); + var newTheme = obj.theme; + if (oldTheme === newTheme) { + return; + } + if (oldTheme) { + $world_map.removeClass('map_theme_' + oldTheme); + } + $world_map.addClass('map_theme_' + newTheme); + $world_map.data('currentTheme', newTheme); + } + if (option.dynamicMapTheme) { + setTheme(); + } + var startYear = obj.startYear; + var year = obj.year; + var month = obj.month; + + if (isDetailMap) { + $world_map.addClass('map_detail').removeClass('map_basic'); + } else { + $world_map.addClass('map_basic').removeClass('map_detail'); + } + + var $map_title = $('.map_title_text'); + if (year < startYear + 1) { + $map_title.css('color', 'magenta'); + } else if (year < startYear + 2) { + $map_title.css('color', 'orange'); + } else if (year < startYear + 3) { + $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('
')); + + $world_map.removeClass('map_string map_summer map_fall map_winter'); + if (month <= 3) { + $world_map.addClass('map_spring'); + } else if (month <= 6) { + $world_map.addClass('map_summer'); + } else if (month <= 9) { + $world_map.addClass('map_fall'); + } else { + $world_map.addClass('map_winter'); + } + + $map_title.html('{0}年 {1}月'.format(year, month)); + + return obj; + } + + function convertCityObjs(obj) { + //원본 Obj는 굉장히 간소하게 온다, Object 형태로 변환해서 사용한다. + + function toCityObj(arr) { + return { + id: arr[0], + level: arr[1], + state: arr[2], + nationId: (arr[3] > 0) ? arr[3] : null, + region: arr[4], + supply: (arr[5] != 0) + }; + } + + function toNationObj(arr) { + return { + id: arr[0], + name: arr[1], + color: arr[2], + capital: arr[3] + }; + } + + var cityList = obj.cityList.map(toCityObj); + var nationList = obj.nationList.map(toNationObj); + nationList = convertDictById(nationList); //array of object -> dict + + var spyList = obj.spyList; + var shownByGeneralList = convertSet(obj.shownByGeneralList); //Array -> Set + + var myCity = obj.myCity; + var myNation = obj.myNation; + + + function mergePositionInfo(city) { + var id = city.id; + if (!(id in cityPosition)) { + return city; + } + var xy_val = cityPosition[id]; + city.name = xy_val[0]; + city.x = xy_val[1]; + city.y = xy_val[2]; + return city; + } + + function mergeNationInfo(city) { + //nationId 값으로 isCapital, color, nation을 통합 + + var nationId = city.nationId; + if (nationId === null || !(nationId in nationList)) { + city.nationId = null; + city.nation = null; + city.color = null; + city.isCapital = false; + return city; + } + + var nationObj = nationList[nationId]; + city.nation = nationObj.name; + city.color = nationObj.color; + city.isCapital = (nationObj.capital == city.id); + + return city; + } + + function mergeClickable(city) { + //clickable = (remainSpy << 3) | (ourCity << 2) | (shownByGeneral << 1) | clickableAll + var id = city.id; + var nationId = city.nationId; + var clickable = 0; + if (id in spyList) { + clickable |= spyList[id] << 3; + } + if (myNation !== null && nationId == myNation) { + clickable |= 4; + } + if (shownByGeneralList.hasOwnProperty(id)) { + clickable |= 2; + } + if (myCity !== null && id == myCity) { + clickable |= 2; + } + if (clickableAll) { + clickable |= 1; + } + + + city.clickable = clickable; + return city; + } + + cityList = cityList + .map(mergePositionInfo) + .map(mergeNationInfo) + .map(mergeClickable) + .map(formatCityInfo); + + return { + 'cityList': cityList, + 'myCity': myCity + }; + } + + function drawDetailWorldMap(obj) { + + var $map_body = $(drawTarget + ' .map_body'); + + var cityList = obj.cityList; + var myCity = obj.myCity; + + cityList.forEach(function(city) { + var id = city.id; + $('.city_base_{0}'.format(id)).detach(); + //이전 도시는 지운다. + + var $cityObj = $('
'.format(id)); + $cityObj.addClass('city_level_{0}'.format(city.level)); + $cityObj.data('obj', city).css({ 'left': city.x - 20, 'top': city.y - 15 }); + + if ('color' in city && city.color !== null) { + var $bgObj = $('
'); + $cityObj.append($bgObj); + $bgObj.css({ 'background-image': 'url({0}/b{1}.png)'.format(pathConfig.gameImage, convColorValue(city.color)) }); + } + + var $linkObj = $(''); + $linkObj.data({ 'text': city.text, 'nation': city.nation, 'id': city.id }); + $cityObj.append($linkObj); + + var $imgObj = $('
'.format(pathConfig.gameImage, city.level)); + $linkObj.append($imgObj); + + + + if (city.state > 0) { + var $stateObj = $('
'.format(pathConfig.gameImage, city.state)); + $linkObj.append($stateObj); + } + + if (city.nationId && city.nationId > 0) { + var flagType = city.supply ? 'f' : 'd'; + var $flagObj = $('
'.format(pathConfig.gameImage, flagType, convColorValue(city.color))); + if (city.isCapital) { + var $capitalObj = $('
'.format(pathConfig.gameImage)); + $flagObj.append($capitalObj); + } + $imgObj.append($flagObj); + } + + var $nameObj = $('{0}'.format(city.name)); + $imgObj.append($nameObj); + + + $map_body.append($cityObj); + + + }); + + $world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city'); + + return obj; + } + + function drawBasicWorldMap(obj) { + + var $map_body = $(drawTarget + ' .map_body'); + + var cityList = obj.cityList; + var myCity = obj.myCity; + + cityList.forEach(function(city) { + var id = city.id; + $('.city_base_{0}'.format(id)).detach(); + //이전 도시는 지운다. + + var $cityObj = $('
'.format(id)); + $cityObj.addClass('city_level_{0}'.format(city.level)); + $cityObj.data('obj', city).css({ 'left': city.x - 20, 'top': city.y - 15 }); + + var $linkObj = $(''); + $linkObj.data({ 'text': city.text, 'nation': city.nation, 'id': city.id }); + $cityObj.append($linkObj); + + var $imgObj = $('
'); + if ('color' in city && city.color !== null) { + $imgObj.css({ 'background-color': city.color }); + } + $linkObj.append($imgObj); + + if (city.state > 0) { + var state_text = 'wrong'; + if (city.state < 10) { + state_text = 'good'; + } else if (city.state < 40) { + state_text = 'bad'; + } else if (city.state < 50) { + state_text = 'war'; + } + + var $stateObj = $('
'.format(state_text)); + $imgObj.append($stateObj); + } + + //단순 표기에서는 깃발 여부가 없음 + if (city.isCapital) { + var $capitalObj = $('
'); + $imgObj.append($capitalObj); + } + + var $nameObj = $('{0}'.format(city.name)); + $imgObj.append($nameObj); + + $map_body.append($cityObj); + }); + + $world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city'); + + return obj; + } + + function setMouseWork(obj) { + var $tooltip = $(drawTarget + ' .city_tooltip'); + var $tooltip_city = $tooltip.find('.city_name'); + var $tooltip_nation = $tooltip.find('.nation_name'); + + var $objs = $(drawTarget + ' .city_link'); + + var $map_body = $(drawTarget + ' .map_body'); + + //터치스크린 탭 + + if (!option.neutralView && is_touch_device()) { + $objs.on('touchstart', function(e) { + if (window.sam_toggleSingleTap) { + return true; + } + var $this = $(this); + + var touchMode = $this.data('touchMode'); + if ($tooltip_city.data('target') != $this.data('id')) { + $this.data('touchMode', 1); + } else if (touchMode === undefined) { + $this.data('touchMode', 1); + } else { + $this.data('touchMode', touchMode + 1); + } + $map_body.data('touchMode', 1); + + $tooltip_city.data('target', $this.data('id')); + + + }); + + $objs.on('touchend', function(e) { + if (window.sam_toggleSingleTap) { + return true; + } + var $this = $(this); + var position = $this.parent().position(); + $tooltip_city.html($this.data('text')); + + var nation_text = $this.data('nation'); + if (nation_text) { + $tooltip_nation.html(nation_text).show(); + } else { + $tooltip_nation.html('').hide(); + } + + var left = position.left; + var top = position.top; + + var scale = $map_body.data('scale'); + if (scale) { + left /= scale; + top /= scale; + } + + $tooltip.css({ 'top': top + 25, 'left': left + 35 }).show(); + + var touchMode = $this.data('touchMode'); + if (touchMode <= 1) { + return false; + } + + //xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다. + $this.data('touchMode', 0); + }); + + $map_body.on('touchend', function(e) { + if (window.sam_toggleSingleTap) { + return true; + } + //위의 touchend bind에 해당하지 않는 경우 -> 빈 지도 터치 + $tooltip.hide(); + }); + + } + + //Mouse over 모드 작동 + + $map_body.on('mousemove', function(e) { + if ($(this).data('touchMode')) { + return true; + } + + var rect = this.getBoundingClientRect(); + var left = (e.clientX - rect.left - this.clientLeft + this.scrollLeft); + var top = (e.clientY - rect.top - this.clientTop + this.scrollTop); + + var scale = $map_body.data('scale'); + if (scale) { + left /= scale; + top /= scale; + } + + $tooltip.css({ 'top': top + 10, 'left': left + 10 }); + }); + + $objs.on('mouseenter', function(e) { + if ($map_body.data('touchMode')) { + return true; + } + + var $this = $(this); + + $tooltip_city.data('target', $this.data('id')); + $tooltip_city.html($this.data('text')); + var nation_text = $this.data('nation'); + if (nation_text) { + $tooltip_nation.html(nation_text).show(); + } else { + $tooltip_nation.html('').hide(); + } + + $tooltip.show(); + }); + + $objs.on('mouseleave', function(event) { + $tooltip.hide(); + }); + + $objs.on('click', function(e) { + //xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다. + var touchMode = $(this).data('touchMode'); + if (touchMode === undefined) { + return; + } + + if (touchMode === 1) { + return false; + } + }); + + + return obj; + } + + function setCityClickable(obj) { + + obj.cityList.forEach(function(city) { + var $cityLink = $world_map.find('.city_base_{0} .city_link'.format(city.id)); + + if ('clickable' in city && city.clickable > 0) { + $cityLink.attr('href', hrefTemplate.format(city.id)); + } + + if (selectCallback) { + $cityLink.click(function() { + return selectCallback(city); + }); + } + }); + + return obj; + } + + function saveCityInfo(obj) { + $world_map.data('cityInfo', obj); + return obj; + } + + var $hideCityNameBtn = $world_map.find('.map_toggle_cityname'); + if (localStorage.getItem('sam.hideMapCityName') == 'yes') { + $world_map.addClass('hide_cityname'); + $hideCityNameBtn.addClass('active').attr('aria-pressed', 'true'); + } + + $hideCityNameBtn.click(function() { + //이전 상태 확인 + var state = !$hideCityNameBtn.hasClass('active'); + if (state) { + $world_map.addClass('hide_cityname'); + localStorage.setItem('sam.hideMapCityName', 'yes'); + } else { + $world_map.removeClass('hide_cityname'); + localStorage.setItem('sam.hideMapCityName', 'no'); + } + }); + + var $toggleSingleTapBtn = $world_map.find('.map_toggle_single_tap'); + if (localStorage.getItem('sam.toggleSingleTap') == 'yes') { + window.sam_toggleSingleTap = true; + $toggleSingleTapBtn.addClass('active').attr('aria-pressed', 'true'); + } else { + window.sam_toggleSingleTap = false; + } + + var $map_body = $(drawTarget + ' .map_body'); + + $toggleSingleTapBtn.click(function() { + //이전 상태 확인 + var state = !$toggleSingleTapBtn.hasClass('active'); + if (state) { + $map_body.removeData('touchMode'); + localStorage.setItem('sam.toggleSingleTap', 'yes'); + window.sam_toggleSingleTap = true; + } else { + localStorage.setItem('sam.toggleSingleTap', 'no'); + window.sam_toggleSingleTap = false; + } + }); + + if (isDetailMap) { + $world_map.addClass('map_detail'); + } else { + $world_map.removeClass('map_datail'); + } + + //deferred mode of jQuery. != promise-then. + var deferred = $.ajax({ + url: option.targetJson, + type: option.reqType, + dataType: 'json', + ifModified: true, + data: { + data: JSON.stringify({ + neutralView: option.neutralView, + year: option.year, + month: option.month, + showMe: option.showMe, + aux: option.aux + }) + } + }); + + var rawObject = null; + + deferred + .then(function(data) { + rawObject = data; + return data; + }) + .then(checkReturnObject) + .then(setMapBackground) + .then(convertCityObjs) + .then(isDetailMap ? drawDetailWorldMap : drawBasicWorldMap) + .then(setMouseWork) + .then(setCityClickable) + .then(saveCityInfo) + .then(function(data) { + if (option.callback) { + option.callback(data, rawObject); + } + + }); + + if ($world_map.hasClass('draw_required')) { + if (useCachedMap) { + //일단 불러옴 + do { + var storedMap = localStorage.getItem(storedOldMapKey); + if (!storedMap) { + break; + } + storedMap = JSON.parse(storedMap); + var storedServerID = storedMap[0]; + if (storedServerID != serverID) { + break; + } + + storedMap = storedMap[1]; + storedMap = setMapBackground(storedMap); + storedMap = convertCityObjs(storedMap); + if (isDetailMap) { + storedMap = drawDetailWorldMap(storedMap); + } else { + storedMap = drawBasicWorldMap(storedMap); + } + storedMap = setMouseWork(storedMap); + storedMap = setCityClickable(storedMap); + storedMap = saveCityInfo(storedMap); + } while (false); + } else if (option.year && option.month) { + var startYear = localStorage.getItem(storedStartYear); + if (startYear) { + startYear = JSON.parse(startYear); + } else { + startYear = option.year; + } + var tmp = { + year: option.year, + month: option.month, + startYear: startYear + }; + setMapBackground(tmp); + } + + + } +} +$(function() { + if (is_touch_device()) { + $('.map_body .map_toggle_single_tap').show(); + } }) \ No newline at end of file diff --git a/index.php b/index.php index 1a3005d3..ae3c6601 100644 --- a/index.php +++ b/index.php @@ -1,232 +1,281 @@ -isLoggedIn()) { - header('Location:i_entrance/entrance.php'); - die(); -} - -?> - - - - - - - - 삼국지 모의전투 HiDCHe - - - - - - - - - - - - - - - - - - - -
-
-
-

삼국지 모의전투 HiDCHe

-
-
-
-

- 로그인 -

-
- -
-
- -
- -
-
- - -
- -
- -
-
- - -
-
-
- -
-
-
-
-
-
-
-
-
-
-
개인정보처리방침 & 이용약관
© 2020 • HideD -
크롬과 파이어폭스에 최적화되어있습니다.
-
-
- - - - - +isLoggedIn()) { + header('Location:i_entrance/entrance.php'); + die(); +} + +$runningServer = null; + +foreach(ServConfig::getServerList() as $setting){ + if(!$setting->isExists()){ + continue; + } + if(!$setting->isRunning()){ + continue; + } + $runningServer = [ + 'color'=>$setting->getColor(), + 'korName'=>$setting->getKorName(), + 'name'=>$setting->getShortName(), + 'exists'=>$setting->isExists(), + 'enable'=>$setting->isRunning() + ]; +} + +if($runningServer){ + $subTemplates = new \League\Plates\Engine(__DIR__.'/'.$runningServer['name'].'/templates'); +} + +?> + + + + + + + + 삼국지 모의전투 HiDCHe + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

삼국지 모의전투 HiDCHe

+
+
+
+

+ 로그인 +

+
+ +
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+

+ 현황 +

+
+ render('map', [ + 'mapTheme' => '' + ])?> +
+
+
+
+
+
+ +
+
+
개인정보처리방침 & 이용약관
© 2020 • HideD +
크롬과 파이어폭스에 최적화되어있습니다.
+
+ + + + + \ No newline at end of file diff --git a/js/login.js b/js/login.js index 7fdc8631..6ccaa9b7 100644 --- a/js/login.js +++ b/js/login.js @@ -1,93 +1,117 @@ -$(document).ready( function () { - $( "#main_form" ).validate( { - rules: { - username: { - required: true - }, - password: { - required: true, - } - }, - messages: { - username: { - required: "유저명을 입력해주세요" - }, - password: { - required: "비밀번호를 입력해주세요" - } - }, - errorElement: "div", - errorPlacement: function ( error, element ) { - // Add the `help-block` class to the error element - error.addClass( "invalid-feedback" ); - - if ( element.prop( "type" ) === "checkbox" ) { - error.insertAfter( element.parent( "label" ) ); - } else { - error.insertAfter( element ); - } - }, - highlight: function ( element, errorClass, validClass ) { - $( element ).addClass( "is-invalid" ).removeClass( "is-valid" ); - }, - unhighlight: function (element, errorClass, validClass) { - $( element ).addClass( "is-valid" ).removeClass( "is-invalid" ); - } - } ); - - $( "#main_form" ).submit(function(){ - var raw_password = $('#password').val(); - var salt = $('#global_salt').val(); - var hash_pw = sha512(salt + raw_password + salt); - - $.post({ - url:'j_login.php', - dataType:'json', - data:{ - 'username':$('#username').val(), - 'password':hash_pw - } - }).then(function(obj){ - if(obj.result){ - window.location.href = "./"; - return; - } - if(!obj.reqOTP){ - alert(obj.reason); - return; - } - - var $modal = $('#modalOTP').modal(); - $modal.on('shown.bs.modal', function(){ - $('#otp_code').focus(); - }); - - - }); - return false; - }); - - $('#otp_form').submit(function(){ - $.post({ - url:'oauth_kakao/j_check_OTP.php', - dataType:'json', - data:{ - 'otp':$('#otp_code').val(), - } - }).then(function(obj){ - if(obj.result){ - alert(obj.reason); - window.location.href = "./"; - return; - } - - alert(obj.reason); - - if(obj.reset){ - $('#modalOTP').modal('hide') - return; - } - }); - return false; - }) -} ); \ No newline at end of file +$(document).ready(function() { + $("#main_form").validate({ + rules: { + username: { + required: true + }, + password: { + required: true, + } + }, + messages: { + username: { + required: "유저명을 입력해주세요" + }, + password: { + required: "비밀번호를 입력해주세요" + } + }, + errorElement: "div", + errorPlacement: function(error, element) { + // Add the `help-block` class to the error element + error.addClass("invalid-feedback"); + + if (element.prop("type") === "checkbox") { + error.insertAfter(element.parent("label")); + } else { + error.insertAfter(element); + } + }, + highlight: function(element, errorClass, validClass) { + $(element).addClass("is-invalid").removeClass("is-valid"); + }, + unhighlight: function(element, errorClass, validClass) { + $(element).addClass("is-valid").removeClass("is-invalid"); + } + }); + + $("#main_form").submit(function() { + var raw_password = $('#password').val(); + var salt = $('#global_salt').val(); + var hash_pw = sha512(salt + raw_password + salt); + + $.post({ + url: 'j_login.php', + dataType: 'json', + data: { + 'username': $('#username').val(), + 'password': hash_pw + } + }).then(function(obj) { + if (obj.result) { + window.location.href = "./"; + return; + } + if (!obj.reqOTP) { + alert(obj.reason); + return; + } + + var $modal = $('#modalOTP').modal(); + $modal.on('shown.bs.modal', function() { + $('#otp_code').focus(); + }); + + + }); + return false; + }); + + $('#otp_form').submit(function() { + $.post({ + url: 'oauth_kakao/j_check_OTP.php', + dataType: 'json', + data: { + 'otp': $('#otp_code').val(), + } + }).then(function(obj) { + if (obj.result) { + alert(obj.reason); + window.location.href = "./"; + return; + } + + alert(obj.reason); + + if (obj.reset) { + $('#modalOTP').modal('hide') + return; + } + }); + return false; + }); + + + if (document.body.clientWidth < 700) { + var targetWidth = document.body.clientWidth * 0.9; + var scale = targetWidth / 700; + var $map = $('#running_map'); + $map.find('.col').css('max-width', targetWidth); + $map.find('.card').css('width', targetWidth); + $map.find('.map-container').css({ + 'transform-origin': 'top left', + 'transform': 'scale({0}, {0})'.format(scale), + 'height': 500 * scale, + }); + $map.find('.map_body').data('scale', scale); + } + + reloadWorldMap({ + targetJson: "{0}/j_map_recent.php".format(runningServer.name), + reqType: 'get', + dynamicMapTheme: true, + callback: function(data, rawObject) { + $('#running_map .card-body').html(rawObject.history); + } + }); +}); \ No newline at end of file