上传文件至 /
Signed-off-by: whr12386 <2654095812@qq.com>
This commit is contained in:
commit
3f45b47256
501
editor-mobile.html
Normal file
501
editor-mobile.html
Normal file
@ -0,0 +1,501 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1,maximum-scale=1,initial-scale=1,user-scalable=no" />
|
||||
<link href="_server/css/editor_mobile.css" rel="stylesheet">
|
||||
<link href="_server/CodeMirror/codemirror.css" rel="stylesheet">
|
||||
<link href="_server/thirdparty/awesomplete.css" rel="stylesheet">
|
||||
<link id="color_css" rel="stylesheet">
|
||||
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
if(innerWidth>innerHeight){ //pic:1242*2208 | chrome info:1340*2380
|
||||
confirm('宽大于高的设备请使用正常版本的editor, 点击确定跳转')?(window.location='./editor.html'):'';
|
||||
}
|
||||
if (location.protocol.indexOf("http")!=0) {
|
||||
alert("请在启动服务中打开本编辑器!不然包括编辑在内的绝大多数功能都无法使用。");
|
||||
}
|
||||
</script>
|
||||
<div class="main">
|
||||
<div id="left" style="z-index:-1;opacity: 0;"><!-- map -->
|
||||
<div id="arrEditor">
|
||||
<table class="col" id='arrColMark'></table>
|
||||
<table class="row" id='arrRowMark'></table>
|
||||
<div id="mapEditArea">
|
||||
<textarea cols="10" rows="10" id="pout"></textarea>
|
||||
</div>
|
||||
<div id="editTip">
|
||||
<input id='newFileName' placeholder="新楼层id" style="width: 100px"/>
|
||||
<span style="vertical-align: bottom">宽</span>
|
||||
<input id='newMapWidth' style="width: 20px"/>
|
||||
<span style="vertical-align: bottom">高</span>
|
||||
<input id='newMapHeight' style="width: 20px"/>
|
||||
<input type="checkbox" id='newMapStatus' checked='checked' style='vertical-align: bottom'/>
|
||||
<span style='vertical-align: bottom;'>保留楼层属性</span>
|
||||
<br/>
|
||||
<input type="button" value="新建空白地图" id='newMap'/>
|
||||
</div>
|
||||
<div id='editBtns'>
|
||||
<input type="button" value="导出并复制地图" id="exportMap"/>
|
||||
<input type="button" value="导入地图" id="importMap"/>
|
||||
<input type="button" value="清除地图" id='clearMapButton'/>
|
||||
<input type="button" value="删除地图" id="deleteMap"/>
|
||||
</div>
|
||||
<input type="button" value="批量创建空白地图 ↓" id='newMaps'/>
|
||||
<div id='newFloors' style='display:none'>
|
||||
<span style="vertical-align: bottom">楼层ID格式: </span>
|
||||
<input id='newFloorIds' style="width: 70px" value='MT${i}'/>
|
||||
<br/>
|
||||
<span style="vertical-align: bottom">地图中文名格式: </span>
|
||||
<input id='newFloorTitles' style="width: 100px" value='主塔 ${i} 层'/>
|
||||
<br/>
|
||||
<span style="vertical-align: bottom">状态栏名称: </span>
|
||||
<input id='newFloorNames' style="width: 70px" value='${i}'/>
|
||||
<br/>
|
||||
<span style="vertical-align: bottom">宽</span>
|
||||
<input id='newMapsWidth' style="width: 20px"/>
|
||||
<span style="vertical-align: bottom">高</span>
|
||||
<input id='newMapsHeight' style="width: 20px"/>
|
||||
<input type="checkbox" id='newMapsStatus' checked='checked' style='vertical-align: bottom'/>
|
||||
<span style='vertical-align: bottom; margin-left: -4px'>保留楼层属性</span>
|
||||
<br/>
|
||||
<span style="vertical-align: bottom">从 i=</span>
|
||||
<input id='newMapsFrom' value="1" style="width: 20px"/>
|
||||
<span style="vertical-align: bottom">到</span>
|
||||
<input id='newMapsTo' value="5" style="width: 20px"/>
|
||||
<input type="button" value="确认创建" id='createNewMaps'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left1" class='leftTab' style="z-index:-1;opacity: 0;"><!-- appendpic -->
|
||||
<h3 class="leftTabHeader">追加素材</h3>
|
||||
<div class="leftTabContent">
|
||||
<p>
|
||||
<input id="selectFileBtn" type="button" value="导入文件到画板"/>
|
||||
<select id="selectAppend"></select>
|
||||
<!-- ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48"] -->
|
||||
<input id="appendConfirm" type="button" value="追加"/>
|
||||
<input id="quickAppendConfirm" type="button" value="快速追加"/>
|
||||
<span style="font-size: 13px">自动注册</span><input id="appendRegister" type="checkbox" checked/>
|
||||
</p>
|
||||
<p>
|
||||
色相:<input id='changeColorInput' type="range" min="0" max="12" step="1" value="0" list="huelists" style="width: 60%;margin-left: 3%;vertical-align: middle">
|
||||
<datalist id="huelists" style="display: none">
|
||||
<option value="0"/><option value="1"/><option value="2"/>
|
||||
<option value="3"/><option value="4"/><option value="5"/>
|
||||
<option value="6"/><option value="7"/><option value="8"/>
|
||||
<option value="9"/><option value="10"/><option value="11"/><option value="12"/>
|
||||
</datalist>
|
||||
</p>
|
||||
<div id="appendPicCanvas" style="position:relative;overflow: auto;height:470px;">
|
||||
<canvas style="position:absolute"></canvas><!-- 用于画出灰白相间背景 -->
|
||||
<canvas style="position:absolute"></canvas><!-- 用于画出选中文件 -->
|
||||
<canvas style="position:absolute;z-index:100"></canvas><!-- 用于响应鼠标点击 -->
|
||||
<canvas style="position:absolute;display:none;"></canvas><!-- 画出追加后的sprite用于储存 -->
|
||||
<div id="appendPicSelection">
|
||||
<div class="appendSelection"><span style="top: 0; left: 2px;">1</span></div>
|
||||
<div class="appendSelection"><span style="top: 0; left: 14px;">2</span></div>
|
||||
<div class="appendSelection"><span style="top: 12px; left: 2px;">3</span></div>
|
||||
<div class="appendSelection"><span style="top: 12px; left: 14px;">4</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left2" class='leftTab' style="z-index:-1;opacity: 0;"><!-- loc -->
|
||||
<h3 class="leftTabHeader">地图选点 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.uifunctions.addAutoEvent()">添加自动事件页</button> <button onclick="editor_multi.editCommentJs('loc')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<p id='pos_a6771a78_a099_417c_828f_0a24851ebfce' style="margin-left: 15px">0,0</p>
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_3d846fc4_7644_44d1_aa04_433d266a73df'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left3" class='leftTab' style="z-index:-1;opacity: 0;"><!-- enemyitem -->
|
||||
<h3 class="leftTabHeader">图块属性 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.mode.changeDoubleClickModeByButton('add')">添加</button> <button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button> <button onclick="editor_multi.editCommentJs('enemyitem')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div id="enemyItemTable"><!-- enemy and item -->
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_a3f03d4c_55b8_4ef6_b362_b345783acd72'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="margin-top: -10px; margin-bottom: 10px">
|
||||
<button id="copyEnemyItem">复制属性</button>
|
||||
<button id="pasteEnemyItem">粘贴属性</button>
|
||||
<button id="clearEnemyItem">清空属性</button>
|
||||
<button id="clearAllEnemyItem">批量清空属性</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id='newIdIdnum'><!-- id and idnum -->
|
||||
<input placeholder="新id(唯一标识符)"/>
|
||||
<input placeholder="新idnum(10000以内数字)"/>
|
||||
<button>确定</button>
|
||||
<br/>
|
||||
<button style="margin-top: 10px">自动注册</button>
|
||||
<button style="margin-top: 10px; margin-left: 5px">删除此素材</button>
|
||||
<button style="margin-top: 10px; margin-left: 5px">以此素材为模板追加</button>
|
||||
</div>
|
||||
<div id='changeId'><!-- id and idnum -->
|
||||
<input placeholder="修改图块id为" style="width: 100px"/>
|
||||
<button>确定</button>
|
||||
<button style="margin-left: 5px">删除此素材</button>
|
||||
<button style="margin-left: 5px">以此素材为模板追加</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left4" class='leftTab' style="z-index:-1;opacity: 0;"><!-- floor -->
|
||||
<h3 class="leftTabHeader">楼层属性 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.mode.changeDoubleClickModeByButton('add')">添加</button> <button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button> <button onclick="editor_multi.editCommentJs('floor')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_4a3b1b09_b2fb_4bdf_b9ab_9f4cdac14c74'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id='changeFloorId'><!-- id and idnum -->
|
||||
<input placeholder="修改floorId为"/>
|
||||
<button>确定</button>
|
||||
</div>
|
||||
<div id='changeFloorSize' style="font-size: 13px;">
|
||||
修改地图大小:宽<input style="width: 25px;" value="13" />,高<input style="width: 25px;" value="13" />,
|
||||
偏移x<input style="width: 25px;" value="0" /> y<input style="width: 25px;" value="0" />
|
||||
<button>确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left5" class='leftTab' style="z-index:-1;opacity: 0;"><!-- tower -->
|
||||
<h3 class="leftTabHeader">全塔属性 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.mode.changeDoubleClickModeByButton('add')">添加</button> <button onclick="editor_multi.editCommentJs('tower')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_b6a03e4c_5968_4633_ac40_0dfdd2c9cde5'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left6" class='leftTab' style="z-index:-1;opacity: 0;">
|
||||
<div style="position: relative; height: 95%"><!-- eventsEditor -->
|
||||
<h3>事件编辑器
|
||||
<!--
|
||||
<button onclick="editor_blockly.showXML()">Show XML</button>
|
||||
<button onclick="editor_blockly.runCode()">console.log(obj=code)</button>
|
||||
-->
|
||||
<button onclick="editor_blockly.confirm()">确认</button>
|
||||
<button onclick="editor_blockly.confirm(true)">应用</button>
|
||||
<button id='blocklyParse' onclick="editor_blockly.parse()">解析</button>
|
||||
<button onclick="editor_blockly.cancel()">取消</button>
|
||||
<!-- 手机端放不下,因此不显示搜索框 -->
|
||||
<div style="display: none">
|
||||
<div class="searchLogo"></div>
|
||||
<input type="text" id="searchBlock" placeholder="搜索事件块..."/>
|
||||
</div>
|
||||
<button class="cpPanel" onclick="editor_blockly.selectPointFromButton()">地图选点</button>
|
||||
<button class="cpPanel" onclick="editor.uievent.searchUsedFlags()" style="margin-left:5px">变量出现位置搜索</button>
|
||||
<input type="checkbox" class="cpPanel" id="blocklyReplace" onchange="editor_blockly.triggerReplace()" style="margin-left: 10px" />
|
||||
<span class="cpPanel" style="margin-left: -4px; font-size: 13px">开启中文名替换</span>
|
||||
<input type="checkbox" class="cpPanel" id="blocklyExpandCompare" onchange="editor_blockly.triggerExpandCompare()" style="margin-left: 10px" />
|
||||
<span class="cpPanel" style="margin-left: -4px; font-size: 13px">展开值块逻辑运算</span>
|
||||
<xml id="toolbox" style="display:none">
|
||||
</xml>
|
||||
</h3>
|
||||
<div style="position: relative;height: 100%">
|
||||
<div id="blocklyArea">
|
||||
<div id="blocklyDiv"></div>
|
||||
</div>
|
||||
<textarea id="codeArea" spellcheck="false"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="colorPanel" class="cpPanel" style="display: none">
|
||||
<input class="color" id="colorPicker" value="255,215,0,1"/>
|
||||
<button onclick="confirmColor()">确定</button>
|
||||
</div>
|
||||
<div id="left7" style="z-index:-1;opacity: 0;"><!-- 多行文本编辑器 -->
|
||||
<div>
|
||||
<button onclick="editor_multi.confirm()">确认</button>
|
||||
<button onclick="editor_multi.cancel()">取消</button>
|
||||
<button onclick="editor_multi.confirm(true)">应用</button>
|
||||
<button onclick="editor_multi.format()">格式化</button>
|
||||
<button id="editor_multi_preview" style="display: none;">预览</button>
|
||||
<input type="checkbox" onclick="editor_multi.toggerLint()" id="lintCheckbox"
|
||||
style="vertical-align: middle;margin-left:6px"/>
|
||||
<span style="vertical-align: middle; margin-left: -3px">语法检查</span>
|
||||
<select id="codemirrorCommands" onchange="editor_multi.doCommand(this)" style="vertical-align: middle; margin-left: 6px;"></select>
|
||||
<span>字体大小</span>
|
||||
<input style="width: 40px" type="number" onchange="editor_multi.setFontSize()" id="editor_multi_fontsize" />
|
||||
<span>字体加粗</span>
|
||||
<input style="width: 40px" type="checkbox" onchange="editor_multi.setFontSize()" id="editor_multi_fontweight" />
|
||||
</div>
|
||||
<textarea id="multiLineCode" name="multiLineCode"></textarea>
|
||||
</div>
|
||||
<div id="left8" class='leftTab' style="z-index:-1;opacity: 0;"><!-- functions -->
|
||||
<h3 class="leftTabHeader">脚本编辑 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor_multi.editCommentJs('functions')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_e260a2be_5690_476a_b04e_dacddede78b3'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left9" class='leftTab' style="z-index:-1;opacity: 0;"><!-- commonevent -->
|
||||
<h3 class="leftTabHeader">公共事件 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.table.addfunc()">添加</button> <button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button> <button onclick="editor_multi.editCommentJs('commonevent')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_b7bf0124_99fd_4af8_ae2f_0017f04a7c7d'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left10" class='leftTab' style="z-index:-1;opacity: 0;"><!-- plugins -->
|
||||
<h3 class="leftTabHeader">插件编写 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.table.addfunc()">添加</button> <button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button> <button onclick="editor_multi.editCommentJs('plugins')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_e2c034ec_47c6_48ae_8db8_4f8f32fea2d6'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mid">
|
||||
<div class="col" id='mapColMark'></div>
|
||||
<div class="row" id='mapRowMark'></div>
|
||||
<div class="map" id="mapEdit">
|
||||
<canvas class='gameCanvas' id='ebm'></canvas>
|
||||
<canvas class='gameCanvas' id='efg'></canvas>
|
||||
<canvas class='gameCanvas' id='eui' style='z-index:100'></canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="mid2" style="display: none">
|
||||
<p style="margin: 10px"><span id='lastUsedTitle'></span> <button id='clearLastUsedBtn'>清除</button></p>
|
||||
<div class="map" style="height: 160px; margin-top: 25px" id="lastUsedDiv">
|
||||
<canvas class='gameCanvas' id='lastUsed'></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div id="right" style="z-index:-1;opacity: 0;">
|
||||
<div id="iconLib">
|
||||
<div id="iconImages"></div>
|
||||
<div id="selectBox">
|
||||
<div id='dataSelection' style="display:none"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="iconExpandBtn"></button>
|
||||
</div>
|
||||
<div id="down">
|
||||
<div style="margin:0.5rem">
|
||||
<div class="tools">
|
||||
<div id="tip"></div>
|
||||
<span id='mobileview'>
|
||||
<input type="button" value="数据区"/>
|
||||
<input type="button" value="地图区"/>
|
||||
<br />
|
||||
<input type="button" value="素材库"/>
|
||||
<input type="button" value="前往游戏" onclick="window.location='./index.html'"/>
|
||||
</span>
|
||||
<div id="menuDiv">
|
||||
<div id="midMenu" style="display:none">
|
||||
<div id='extraEvent' class='menuitem' style="display:none"><div class="menuitem-content"></div></div>
|
||||
<div id='chooseThis' class="menuitem"><div class="menuitem-content">选中此点</div></div>
|
||||
<div id='chooseInRight' class="menuitem"><div class="menuitem-content">在素材区选中此图块</div></div>
|
||||
<div id='copyLoc' class="menuitem"><div class="menuitem-content">复制此事件</div></div>
|
||||
<div id='pasteLoc' class="menuitem"><div class="menuitem-content">粘贴到此事件</div></div>
|
||||
<div id='clearEvent' class="menuitem"><div class="menuitem-content">仅清空此点事件</div></div>
|
||||
<div id='clearLoc' class="menuitem"><div class="menuitem-content">清空此点及事件</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<select id="editModeSelect" style="font-size: 12px">
|
||||
<option value="map">地图编辑</option>
|
||||
<option value="loc">地图选点</option>
|
||||
<option value="enemyitem">图块属性</option>
|
||||
<option value="floor">楼层属性</option>
|
||||
<option value="tower">全塔属性</option>
|
||||
<option value="functions">脚本编辑</option>
|
||||
<option value="appendpic">追加素材</option>
|
||||
<option value="commonevent">公共事件</option>
|
||||
<option value="plugins">插件编写</option>
|
||||
</select>
|
||||
<span style="font-size: 12px"><input type="checkbox" id="showMovable"/>通行度</span>
|
||||
<select id="editorTheme" style="font-size: 11px;">
|
||||
<option value="editor_color">默认白</option>
|
||||
<option value="editor_color_dark">夜间黑</option>
|
||||
</select>
|
||||
<select id="brushMod" style="clear:right">
|
||||
<option value="line">画线</option>
|
||||
<option value="rectangle">画矩形</option>
|
||||
<option value="tileset">tile平铺</option>
|
||||
<option value="fill">填充模式</option>
|
||||
</select>
|
||||
<select id="layerMod" style="float:left;margin-right:3px">
|
||||
<option value="bgmap">背景层</option>
|
||||
<option value="map" selected>事件层</option>
|
||||
<option value="fgmap">前景层</option>
|
||||
</select>
|
||||
<div id="viewportButtons" style="float:left">
|
||||
<input type="button" style="padding:1px 1px" value="←"/>
|
||||
<input type="button" style="padding:1px 6px" value="↑"/>
|
||||
<input type="button" style="padding:1px 6px" value="↓"/>
|
||||
<input type="button" style="padding:1px 1px" value="→"/>
|
||||
<input type="button" id="bigmapBtn" value="大地图" style="margin-left: 5px"/>
|
||||
</div>
|
||||
<select id="selectFloor" style="clear:left"></select>
|
||||
<input type="button" value="选层" id='selectFloorBtn'/>
|
||||
<input type="button" value="保存地图" id='saveFloor'/>
|
||||
<input type="button" value="后退" id="undoFloor" style="display: none;"/>
|
||||
<input type="button" value="帮助文档" id="openDoc" />
|
||||
<span id='mobileeditdata' style="display:none">
|
||||
<input type="button" value="编辑"/>
|
||||
<input type="button" value="显示完整名称" style="display: none;"/>
|
||||
<input type="button" value="显示完整注释"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- <script>/* -->
|
||||
|
||||
<div id="gameInject" style='display: none'></div>
|
||||
|
||||
<!-- UI预览 & 地图选点 -->
|
||||
<div id='uieventDiv' style='display: none'>
|
||||
<div id='uieventDialog'>
|
||||
<div id="uieventHead">
|
||||
<span id="uieventTitle"></span>
|
||||
<select id="uieventSelect" style="margin-left: 20px"></select>
|
||||
<button id="uieventNo">关闭</button>
|
||||
<button id="uieventYes">确定</button>
|
||||
</div>
|
||||
<hr style="clear: both; margin-top: 0"/>
|
||||
<div id='uieventBody'>
|
||||
<canvas class='gameCanvas' id='uievent'></canvas>
|
||||
<div id="selectPointBox"></div>
|
||||
<div id="uieventExtraBody" style="display: none"></div>
|
||||
</div>
|
||||
<div id="selectPoint">
|
||||
<select id="selectPointFloor"></select>
|
||||
<div id="selectPointButtons">
|
||||
<input type="button" value="←"/>
|
||||
<input type="button" value="↑"/>
|
||||
<input type="button" value="↓"/>
|
||||
<input type="button" value="→"/>
|
||||
<input type="button" value="大地图" style="margin-left: 5px"/>
|
||||
<input type="button" value="复制楼层ID">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- */</script> -->
|
||||
|
||||
<!-- =========================================================== -->
|
||||
|
||||
<!-- <script src='_server/vendor/vue.min.js'></script> -->
|
||||
<!-- <script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script> -->
|
||||
<!-- <script src='_server/vendor/polyfill.min.js'></script> -->
|
||||
<script src='_server/fs.js'></script>
|
||||
<script src='_server/editor_config.js'></script>
|
||||
<script src='_server/editor_util.js'></script>
|
||||
<script src='_server/editor_game.js'></script>
|
||||
<script src='_server/editor_file.js'></script>
|
||||
<script src='_server/editor_table.js'></script>
|
||||
<script src='_server/editor_mode.js'></script>
|
||||
<script src='_server/editor_ui.js'></script>
|
||||
<script src='_server/editor_uievent.js'></script>
|
||||
<script src='_server/editor_mappanel.js'></script>
|
||||
<script src='_server/editor_datapanel.js'></script>
|
||||
<script src='_server/editor_materialpanel.js'></script>
|
||||
<script src='_server/editor_listen.js'></script>
|
||||
<script src='libs/thirdparty/lz-string.min.js'></script>
|
||||
<script src='libs/thirdparty/localforage.min.js'></script>
|
||||
<script src='libs/thirdparty/zip.min.js'></script>
|
||||
<script src='_server/editor.js'></script>
|
||||
<script>
|
||||
editor.isMobile=true;
|
||||
editor.init(function () {
|
||||
editor.listen();
|
||||
editor.mode_listen();
|
||||
editor.mobile_listen();
|
||||
});
|
||||
//main.listen();
|
||||
</script>
|
||||
|
||||
<!-- hightlight textarea -->
|
||||
<script src='_server/editor_multi.js'></script>
|
||||
<!-- blockly -->
|
||||
<script src="_server/blockly/Converter.bundle.min.js"></script>
|
||||
<script src="_server/blockly/blockly_compressed.js"></script>
|
||||
<script src="_server/blockly/blocks_compressed.js"></script>
|
||||
<script src="_server/blockly/javascript_compressed.js"></script>
|
||||
<script src="_server/blockly/zh-hans.js"></script>
|
||||
<script src='_server/MotaActionParser.js'></script>
|
||||
<script src='_server/editor_blocklyconfig.js'></script>
|
||||
<script src='_server/editor_blockly.js'></script>
|
||||
<!-- codemirror -->
|
||||
<script src="_server/CodeMirror/codeMirror.bundle.min.js"></script>
|
||||
<script src="_server/CodeMirror/beautify.min.js"></script>
|
||||
<script src="_server/CodeMirror/jshint.min.js"></script>
|
||||
<script src="_server/CodeMirror/codeMirror.plugin.min.js"></script>
|
||||
<script src="_server/CodeMirror/acorn.min.js"></script>
|
||||
<script src="_server/CodeMirror/defs.js"></script>
|
||||
<script src="_server/CodeMirror/tern.min.js"></script>
|
||||
<!-- thirdparty -->
|
||||
<script src="_server/thirdparty/color.all.min.js"></script>
|
||||
<script src="_server/thirdparty/awesomplete.min.js"></script>
|
||||
<script src="_server/thirdparty/caret-position.js"></script>
|
||||
<script src="_server/thirdparty/jsColor.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
485
editor.html
Normal file
485
editor.html
Normal file
@ -0,0 +1,485 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link href="_server/css/editor.css" rel="stylesheet">
|
||||
<link href="_server/CodeMirror/codemirror.css" rel="stylesheet">
|
||||
<link href="_server/thirdparty/awesomplete.css" rel="stylesheet">
|
||||
<link id="color_css" rel="stylesheet">
|
||||
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
if(innerWidth<innerHeight){ //pic:1242*2208 | chrome info:1340*2380
|
||||
confirm('高大于宽的设备请使用移动版本的editor, 点击确定跳转')?(window.location='./editor-mobile.html'):'';
|
||||
}
|
||||
if (location.protocol.indexOf("http")!=0) {
|
||||
alert("请在启动服务中打开本编辑器!不然包括编辑在内的绝大多数功能都无法使用。");
|
||||
}
|
||||
</script>
|
||||
<div class="main">
|
||||
<div id="left" style="z-index:-1;opacity: 0;"><!-- map -->
|
||||
<div id="arrEditor">
|
||||
<table class="col" id='arrColMark'></table>
|
||||
<table class="row" id='arrRowMark'></table>
|
||||
<div id="mapEditArea">
|
||||
<textarea cols="10" rows="10" id="pout"></textarea>
|
||||
</div>
|
||||
<div id="editTip">
|
||||
<input type="button" value="新建空白地图" id='newMap'/>
|
||||
<input id='newFileName' placeholder="新楼层id" style="width: 70px"/>
|
||||
<span style="vertical-align: bottom">宽</span>
|
||||
<input id='newMapWidth' style="width: 20px"/>
|
||||
<span style="vertical-align: bottom">高</span>
|
||||
<input id='newMapHeight' style="width: 20px"/>
|
||||
<input type="checkbox" id='newMapStatus' checked='checked' style='vertical-align: bottom'/>
|
||||
<span style='vertical-align: bottom; margin-left: -4px'>保留楼层属性</span>
|
||||
</div>
|
||||
<div id="editBtns">
|
||||
<input type="button" value="导出并复制地图" id="exportMap"/>
|
||||
<input type="button" value="从框中导入地图" id="importMap"/>
|
||||
<input type="button" value="清除地图" id='clearMapButton'/>
|
||||
<input type="button" value="删除地图" id="deleteMap"/>
|
||||
</div>
|
||||
<input type="button" value="批量创建空白地图 ↓" id='newMaps'/>
|
||||
<div id='newFloors' style='display:none'>
|
||||
<span style="vertical-align: bottom">楼层ID格式: </span>
|
||||
<input id='newFloorIds' style="width: 70px" value='MT${i}'/>
|
||||
<span style="vertical-align: bottom">地图中文名格式: </span>
|
||||
<input id='newFloorTitles' style="width: 100px" value='主塔 ${i} 层'/>
|
||||
<br/>
|
||||
<span style="vertical-align: bottom">状态栏名称: </span>
|
||||
<input id='newFloorNames' style="width: 70px" value='${i}'/>
|
||||
<span style="vertical-align: bottom">宽</span>
|
||||
<input id='newMapsWidth' style="width: 20px"/>
|
||||
<span style="vertical-align: bottom">高</span>
|
||||
<input id='newMapsHeight' style="width: 20px"/>
|
||||
<input type="checkbox" id='newMapsStatus' checked='checked' style='vertical-align: bottom'/>
|
||||
<span style='vertical-align: bottom; margin-left: -4px'>保留楼层属性</span>
|
||||
<br/>
|
||||
<span style="vertical-align: bottom">从 i=</span>
|
||||
<input id='newMapsFrom' value="1" style="width: 20px"/>
|
||||
<span style="vertical-align: bottom">到</span>
|
||||
<input id='newMapsTo' value="5" style="width: 20px"/>
|
||||
<input type="button" value="确认创建" id='createNewMaps'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left1" class='leftTab' style="z-index:-1;opacity: 0;"><!-- appendpic -->
|
||||
<h3 class="leftTabHeader">追加素材</h3>
|
||||
<div class="leftTabContent">
|
||||
<p>
|
||||
<input id="selectFileBtn" type="button" value="导入文件到画板"/>
|
||||
<select id="selectAppend"></select>
|
||||
<!-- ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48"] -->
|
||||
<input id="appendConfirm" type="button" value="追加"/>
|
||||
<input id="quickAppendConfirm" type="button" value="快速追加"/>
|
||||
<span style="font-size: 13px"> 自动注册</span><input id="appendRegister" type="checkbox" checked/>
|
||||
</p>
|
||||
<p><small>从V2.7.1开始,你可以直接将素材图片拖到对应的素材区,将自动追加并注册。同时,4x4的道具素材已支持快速追加一次16个。</small></p>
|
||||
<p>
|
||||
色相:<input id='changeColorInput' type="range" min="0" max="12" step="1" value="0" list="huelists" style="width: 60%;margin-left: 3%;vertical-align: middle">
|
||||
<datalist id="huelists" style="display: none">
|
||||
<option value="0"/><option value="1"/><option value="2"/>
|
||||
<option value="3"/><option value="4"/><option value="5"/>
|
||||
<option value="6"/><option value="7"/><option value="8"/>
|
||||
<option value="9"/><option value="10"/><option value="11"/><option value="12"/>
|
||||
</datalist>
|
||||
</p>
|
||||
<div id="appendPicCanvas" style="position:relative;overflow: auto;height:470px;">
|
||||
<canvas style="position:absolute"></canvas><!-- 用于画出灰白相间背景 -->
|
||||
<canvas style="position:absolute"></canvas><!-- 用于画出选中文件 -->
|
||||
<canvas style="position:absolute;z-index:100"></canvas><!-- 用于响应鼠标点击 -->
|
||||
<canvas style="position:absolute;display:none;"></canvas><!-- 画出追加后的sprite用于储存 -->
|
||||
<div id="appendPicSelection">
|
||||
<div class="appendSelection"><span style="top: 0; left: 2px;">1</span></div>
|
||||
<div class="appendSelection"><span style="top: 0; left: 14px;">2</span></div>
|
||||
<div class="appendSelection"><span style="top: 12px; left: 2px;">3</span></div>
|
||||
<div class="appendSelection"><span style="top: 12px; left: 14px;">4</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left2" class='leftTab' style="z-index:-1;opacity: 0;"><!-- loc -->
|
||||
<h3 class="leftTabHeader">地图选点 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.uifunctions.addAutoEvent()">添加自动事件页</button> <button onclick="editor_multi.editCommentJs('loc')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<p id='pos_a6771a78_a099_417c_828f_0a24851ebfce' style="margin-left: 15px">0,0</p>
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_3d846fc4_7644_44d1_aa04_433d266a73df'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left3" class='leftTab' style="z-index:-1;opacity: 0;"><!-- enemyitem -->
|
||||
<h3 class="leftTabHeader">图块属性 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.mode.changeDoubleClickModeByButton('add')">添加</button> <button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button> <button onclick="editor_multi.editCommentJs('enemyitem')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div id="enemyItemTable"><!-- enemy and item -->
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_a3f03d4c_55b8_4ef6_b362_b345783acd72'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="margin-top: -10px; margin-bottom: 10px">
|
||||
<button id="copyEnemyItem">复制属性</button>
|
||||
<button id="pasteEnemyItem">粘贴属性</button>
|
||||
<button id="clearEnemyItem">清空属性</button>
|
||||
<button id="clearAllEnemyItem">批量清空属性</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id='newIdIdnum'><!-- id and idnum -->
|
||||
<input placeholder="新id(唯一标识符)"/>
|
||||
<input placeholder="新idnum(10000以内数字)"/>
|
||||
<button>确定</button>
|
||||
<br/>
|
||||
<button style="margin-top: 10px">自动注册</button>
|
||||
<button style="margin-top: 10px; margin-left: 5px">删除此素材</button>
|
||||
<button style="margin-top: 10px; margin-left: 5px">以此素材为模板追加</button>
|
||||
</div>
|
||||
<div id='changeId'><!-- id and idnum -->
|
||||
<input placeholder="修改图块id为" style="width: 100px"/>
|
||||
<button>确定</button>
|
||||
<button style="margin-left: 5px">删除此素材</button>
|
||||
<button style="margin-left: 5px">以此素材为模板追加</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left4" class='leftTab' style="z-index:-1;opacity: 0;"><!-- floor -->
|
||||
<h3 class="leftTabHeader">楼层属性 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.mode.changeDoubleClickModeByButton('add')">添加</button> <button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button> <button onclick="editor_multi.editCommentJs('floor')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_4a3b1b09_b2fb_4bdf_b9ab_9f4cdac14c74'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id='changeFloorId'><!-- id and idnum -->
|
||||
<input placeholder="修改floorId为"/>
|
||||
<button>确定</button>
|
||||
</div>
|
||||
<div id='changeFloorSize' style="font-size: 13px;">
|
||||
修改地图大小:宽<input style="width: 25px;" value="13" />,高<input style="width: 25px;" value="13" />,
|
||||
偏移x<input style="width: 25px;" value="0" /> y<input style="width: 25px;" value="0" />
|
||||
<button>确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left5" class='leftTab' style="z-index:-1;opacity: 0;"><!-- tower -->
|
||||
<h3 class="leftTabHeader">全塔属性 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.mode.changeDoubleClickModeByButton('add')">添加</button> <button onclick="editor_multi.editCommentJs('tower')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_b6a03e4c_5968_4633_ac40_0dfdd2c9cde5'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left6" class='leftTab' style="z-index:-1;opacity: 0;">
|
||||
<div style="position: relative; height: 95%"><!-- eventsEditor -->
|
||||
<h3>事件编辑器
|
||||
<!--
|
||||
<button onclick="editor_blockly.showXML()">Show XML</button>
|
||||
<button onclick="editor_blockly.runCode()">console.log(obj=code)</button>
|
||||
-->
|
||||
<button onclick="editor_blockly.confirm()">确认</button>
|
||||
<button onclick="editor_blockly.confirm(true)">应用</button>
|
||||
<button id='blocklyParse' onclick="editor_blockly.parse()">解析</button>
|
||||
<button onclick="editor_blockly.cancel()">取消</button>
|
||||
<div style="position: relative; display: inline-block; margin-left: 10px">
|
||||
<div class="searchLogo"></div>
|
||||
<input type="text" id="searchBlock" placeholder="搜索事件块..."/>
|
||||
</div>
|
||||
<button class="cpPanel" onclick="editor_blockly.selectPointFromButton()" style="margin-left:5px">地图选点</button>
|
||||
<button class="cpPanel" onclick="editor.uievent.searchUsedFlags()" style="margin-left:5px">变量出现位置搜索</button>
|
||||
<input type="checkbox" class="cpPanel" id="blocklyReplace" onchange="editor_blockly.triggerReplace()" style="margin-left: 10px" />
|
||||
<span class="cpPanel" style="margin-left: -4px; font-size: 13px">开启中文名替换</span>
|
||||
<input type="checkbox" class="cpPanel" id="blocklyExpandCompare" onchange="editor_blockly.triggerExpandCompare()" style="margin-left: 10px" />
|
||||
<span class="cpPanel" style="margin-left: -4px; font-size: 13px">展开值块逻辑运算</span>
|
||||
<xml id="toolbox" style="display:none">
|
||||
</xml>
|
||||
</h3>
|
||||
<div style="position: relative;height: 100%">
|
||||
<div id="blocklyArea">
|
||||
<div id="blocklyDiv"></div>
|
||||
</div>
|
||||
<textarea id="codeArea" spellcheck="false"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="colorPanel" class="cpPanel" style="display: none">
|
||||
<input class="color" id="colorPicker" value="255,215,0,1"/>
|
||||
<button onclick="confirmColor()">确定</button>
|
||||
</div>
|
||||
<div id="left7" style="z-index:-1;opacity: 0;"><!-- 多行文本编辑器 -->
|
||||
<div>
|
||||
<button onclick="editor_multi.confirm()">确认</button>
|
||||
<button onclick="editor_multi.cancel()">取消</button>
|
||||
<button onclick="editor_multi.confirm(true)">应用</button>
|
||||
<button onclick="editor_multi.format()">格式化</button>
|
||||
<button id="editor_multi_preview" style="display: none;">预览</button>
|
||||
<input type="checkbox" onclick="editor_multi.toggerLint()" id="lintCheckbox"
|
||||
style="vertical-align: middle;margin-left:6px"/>
|
||||
<span style="vertical-align: middle; margin-left: -3px">语法检查</span>
|
||||
<select id="codemirrorCommands" onchange="editor_multi.doCommand(this)" style="vertical-align: middle; margin-left: 6px;"></select>
|
||||
<span>字体大小</span>
|
||||
<input style="width: 40px" type="number" onchange="editor_multi.setFontSize()" id="editor_multi_fontsize" />
|
||||
<span>字体加粗</span>
|
||||
<input style="width: 40px" type="checkbox" onchange="editor_multi.setFontSize()" id="editor_multi_fontweight" />
|
||||
</div>
|
||||
<textarea id="multiLineCode" name="multiLineCode"></textarea>
|
||||
</div>
|
||||
<div id="left8" class='leftTab' style="z-index:-1;opacity: 0;"><!-- functions -->
|
||||
<h3 class="leftTabHeader">脚本编辑 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor_multi.editCommentJs('functions')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_e260a2be_5690_476a_b04e_dacddede78b3'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left9" class='leftTab' style="z-index:-1;opacity: 0;"><!-- commonevent -->
|
||||
<h3 class="leftTabHeader">公共事件 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.table.addfunc()">添加</button> <button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button> <button onclick="editor_multi.editCommentJs('commonevent')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_b7bf0124_99fd_4af8_ae2f_0017f04a7c7d'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left10" class='leftTab' style="z-index:-1;opacity: 0;"><!-- plugins -->
|
||||
<h3 class="leftTabHeader">插件编写 <button onclick="editor.mode.onmode('save')">保存</button> <button onclick="editor.table.addfunc()">添加</button> <button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button> <button onclick="editor_multi.editCommentJs('plugins')">配置表格</button>
|
||||
</h3>
|
||||
<div class="leftTabContent">
|
||||
<div class='etable'>
|
||||
<table>
|
||||
<tbody id='table_e2c034ec_47c6_48ae_8db8_4f8f32fea2d6'>
|
||||
<tr>
|
||||
<td>条目</td>
|
||||
<td>注释</td>
|
||||
<td>值</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mid">
|
||||
<table class="col" id='mapColMark'></table>
|
||||
<table class="row" id='mapRowMark'></table>
|
||||
<div class="map" id="mapEdit">
|
||||
<canvas class='gameCanvas' id='ebm'></canvas>
|
||||
<canvas class='gameCanvas' id='efg'></canvas>
|
||||
<canvas class='gameCanvas' id='eui' style='z-index:100'></canvas>
|
||||
</div>
|
||||
<div class="tools">
|
||||
<div id="tip"></div>
|
||||
<select id="editModeSelect" style="font-size: 12px">
|
||||
<option value="map">地图编辑(Z)</option>
|
||||
<option value="loc">地图选点(X)</option>
|
||||
<option value="enemyitem">图块属性(C)</option>
|
||||
<option value="floor">楼层属性(V)</option>
|
||||
<option value="tower">全塔属性(B)</option>
|
||||
<option value="functions">脚本编辑(N)</option>
|
||||
<option value="appendpic">追加素材(M)</option>
|
||||
<option value="commonevent">公共事件(,)</option>
|
||||
<option value="plugins">插件编写(.)</option>
|
||||
</select>
|
||||
<span style="font-size: 12px"><input type="checkbox" id="showMovable" style="margin-left:0;margin-right: 2px"/>通行度</span>
|
||||
<select id="editorTheme" style="margin-left: 0; font-size: 11px;">
|
||||
<option value="editor_color">默认白</option>
|
||||
<option value="editor_color_dark">夜间黑</option>
|
||||
</select>
|
||||
<br/>
|
||||
<span style="font-size: 12px;">
|
||||
<input type="radio" id="brushMod" name="brushMod" value="line" checked="checked" />线
|
||||
<input type="radio" id="brushMod2" name="brushMod" value="rectangle" />矩形
|
||||
<input type="radio" id="brushMod3" name="brushMod" value="tileset" />tile平铺
|
||||
<input type="radio" id="brushMod4" name="brushMod" value="fill" />填充
|
||||
|
||||
</span>
|
||||
<br/>
|
||||
<span style="font-size: 12px">
|
||||
<input type="radio" id="layerMod2" name="layerMod" value="bgmap" />背景层
|
||||
<input type="radio" id="layerMod" name="layerMod" value="map" checked="checked" style="margin-left: 5px" />事件层
|
||||
<input type="radio" id="layerMod3" name="layerMod" value="fgmap" style="margin-left: 5px" />前景层
|
||||
</span>
|
||||
<br>
|
||||
<div id="viewportButtons" style="margin-bottom: 7px">
|
||||
<input type="button" value="←"/>
|
||||
<input type="button" value="↑"/>
|
||||
<input type="button" value="↓"/>
|
||||
<input type="button" value="→"/>
|
||||
<input type="button" id='bigmapBtn' value="大地图" style="margin-left: 5px"/>
|
||||
</div>
|
||||
<select id="selectFloor" style="margin-bottom: 5px;"></select>
|
||||
<input type="button" value="选层" id='selectFloorBtn'/>
|
||||
<input type="button" value="保存地图" id='saveFloor'/>
|
||||
<input type="button" value="后退" id="undoFloor" style="display: none;" />
|
||||
<input type="button" value="帮助文档" id="openDoc" />
|
||||
<input type="button" value="前往游戏" onclick="window.open('./index.html', '_blank')"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mid2">
|
||||
<p style="margin: 10px"><span id='lastUsedTitle'></span><small>(Ctrl+滚轮放缩,右键置顶)</small> <button id='clearLastUsedBtn'>清除</button></p>
|
||||
<div class="map" id="lastUsedDiv">
|
||||
<canvas id='lastUsed' class="gameCanvas" style="overflow: hidden"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div id="right">
|
||||
<div id="iconLib">
|
||||
<div id="iconImages"></div>
|
||||
<div id="selectBox">
|
||||
<div id='dataSelection' style="display:none"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="iconExpandBtn"></button>
|
||||
</div>
|
||||
<div id="menuDiv">
|
||||
<div id="midMenu" style="display:none">
|
||||
<div id='extraEvent' class='menuitem' style="display:none"><div class="menuitem-content"></div></div>
|
||||
<div id='chooseThis' class="menuitem"><div class="menuitem-content">选中此点</div></div>
|
||||
<div id='chooseInRight' class="menuitem"><div class="menuitem-content">在素材区选中此图块</div></div>
|
||||
<div id='copyLoc' class="menuitem"><div class="menuitem-content">复制此事件</div></div>
|
||||
<div id='pasteLoc' class="menuitem"><div class="menuitem-content">粘贴到此事件</div></div>
|
||||
<div id='clearEvent' class="menuitem"><div class="menuitem-content">仅清空此点事件</div></div>
|
||||
<div id='clearLoc' class="menuitem"><div class="menuitem-content">清空此点及事件</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <script>/* -->
|
||||
|
||||
<div id="gameInject" style='display: none'></div>
|
||||
|
||||
<!-- UI预览 & 地图选点 -->
|
||||
<div id='uieventDiv' style='display: none'>
|
||||
<div id='uieventDialog'>
|
||||
<div id="uieventHead">
|
||||
<span id="uieventTitle"></span>
|
||||
<select id="uieventSelect" style="margin-left: 20px"></select>
|
||||
<button id="uieventNo">关闭</button>
|
||||
<button id="uieventYes">确定</button>
|
||||
</div>
|
||||
<hr style="clear: both; margin-top: 0"/>
|
||||
<div id='uieventBody'>
|
||||
<canvas class='gameCanvas' id='uievent'></canvas>
|
||||
<div id="selectPointBox"></div>
|
||||
<div id="uieventExtraBody" style="display: none; margin-top: -10px"></div>
|
||||
</div>
|
||||
<div id="selectPoint">
|
||||
<select id="selectPointFloor"></select>
|
||||
<div id="selectPointButtons">
|
||||
<input type="button" value="←"/>
|
||||
<input type="button" value="↑"/>
|
||||
<input type="button" value="↓"/>
|
||||
<input type="button" value="→"/>
|
||||
<input type="button" value="切换大地图" style="margin-left: 10px;">
|
||||
<input type="button" value="复制楼层ID">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- */</script> -->
|
||||
|
||||
<!-- =========================================================== -->
|
||||
|
||||
<!-- <script src='_server/vendor/vue.min.js'></script> -->
|
||||
<!-- <script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script> -->
|
||||
<!-- <script src='_server/vendor/polyfill.min.js'></script> -->
|
||||
<script src='_server/fs.js'></script>
|
||||
<script src='_server/editor_config.js'></script>
|
||||
<script src='_server/editor_util.js'></script>
|
||||
<script src='_server/editor_game.js'></script>
|
||||
<script src='_server/editor_file.js'></script>
|
||||
<script src='_server/editor_table.js'></script>
|
||||
<script src='_server/editor_mode.js'></script>
|
||||
<script src='_server/editor_ui.js'></script>
|
||||
<script src='_server/editor_uievent.js'></script>
|
||||
<script src='_server/editor_mappanel.js'></script>
|
||||
<script src='_server/editor_datapanel.js'></script>
|
||||
<script src='_server/editor_materialpanel.js'></script>
|
||||
<script src='_server/editor_listen.js'></script>
|
||||
<script src='libs/thirdparty/lz-string.min.js'></script>
|
||||
<script src='libs/thirdparty/localforage.min.js'></script>
|
||||
<script src='libs/thirdparty/zip.min.js'></script>
|
||||
<script src='_server/editor.js'></script>
|
||||
<script>
|
||||
editor.init(function () {
|
||||
editor.listen();
|
||||
editor.mode_listen();
|
||||
editor.mobile_listen();
|
||||
});
|
||||
//main.listen();
|
||||
</script>
|
||||
|
||||
<!-- hightlight textarea -->
|
||||
<script src='_server/editor_multi.js'></script>
|
||||
<!-- blockly -->
|
||||
<script src="_server/blockly/Converter.bundle.min.js"></script>
|
||||
<script src="_server/blockly/blockly_compressed.js"></script>
|
||||
<script src="_server/blockly/blocks_compressed.js"></script>
|
||||
<script src="_server/blockly/javascript_compressed.js"></script>
|
||||
<script src="_server/blockly/zh-hans.js"></script>
|
||||
<script src='_server/MotaActionParser.js'></script>
|
||||
<script src='_server/editor_blocklyconfig.js'></script>
|
||||
<script src='_server/editor_blockly.js'></script>
|
||||
<!-- codemirror -->
|
||||
<script src="_server/CodeMirror/codeMirror.bundle.min.js"></script>
|
||||
<script src="_server/CodeMirror/beautify.min.js"></script>
|
||||
<script src="_server/CodeMirror/jshint.min.js"></script>
|
||||
<script src="_server/CodeMirror/codeMirror.plugin.min.js"></script>
|
||||
<script src="_server/CodeMirror/acorn.min.js"></script>
|
||||
<script src="_server/CodeMirror/defs.js"></script>
|
||||
<script src="_server/CodeMirror/tern.min.js"></script>
|
||||
<!-- thirdparty -->
|
||||
<script src="_server/thirdparty/color.all.min.js"></script>
|
||||
<script src="_server/thirdparty/awesomplete.min.js"></script>
|
||||
<script src="_server/thirdparty/caret-position.js"></script>
|
||||
<script src="_server/thirdparty/jsColor.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
208
index.html
Normal file
208
index.html
Normal file
@ -0,0 +1,208 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv='content-type' content='text/html' charset='utf-8'>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=Edge, chrome=1'>
|
||||
<meta name='author' content='ckcz123'>
|
||||
<meta name='viewport'
|
||||
content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=yes'>
|
||||
<title>HTML5魔塔</title>
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="screen-orientation" content="portrait">
|
||||
<meta name="full-screen" content="yes">
|
||||
<meta name="browsermode" content="application">
|
||||
<meta name="x5-orientation" content="portrait">
|
||||
<meta name="x5-fullscreen" content="true">
|
||||
<meta name="x5-page-mode" content="app">
|
||||
<link type='text/css' href='styles.css' rel='stylesheet'>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- <div id="stars"></div>
|
||||
<div id="stars2"></div>
|
||||
<div id="stars3"></div> -->
|
||||
<div id='startImageBackgroundDiv'>
|
||||
<div id='startImageDiv'></div>
|
||||
<img id='startImageLogo' />
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
var startImageBackgroundDiv = document.getElementById('startImageBackgroundDiv');
|
||||
var startImageLogo = document.getElementById('startImageLogo');
|
||||
var startImageDiv = document.getElementById('startImageDiv');
|
||||
startImageLogo.onload = function () {
|
||||
startImageBackgroundDiv.style.display = 'block';
|
||||
var onAnimationEnd = function () {
|
||||
startImageBackgroundDiv.style.display = 'none';
|
||||
startImageLogo.classList.remove("startImageAnimation");
|
||||
startImageDiv.classList.remove("startImageDivAnimation");
|
||||
}
|
||||
startImageDiv.addEventListener("webkitAnimationEnd", onAnimationEnd);
|
||||
startImageDiv.addEventListener("animationend", onAnimationEnd);
|
||||
startImageLogo.classList.add("startImageAnimation");
|
||||
startImageDiv.classList.add("startImageDivAnimation");
|
||||
// 注释下面这句话以禁止单击立刻跳过开场动画
|
||||
startImageBackgroundDiv.onclick = onAnimationEnd;
|
||||
}
|
||||
startImageLogo.onerror = function () { }
|
||||
startImageLogo.src = "logo.png";
|
||||
})();
|
||||
</script>
|
||||
<!-- injection -->
|
||||
<div id='gameGroup'>
|
||||
<p id='mainTips'>请稍候...</p>
|
||||
<img id='musicBtn'>
|
||||
<div id='startPanel'>
|
||||
<div id='startTop'>
|
||||
<div id='startTopProgressBar'>
|
||||
<div id='startTopProgress'></div>
|
||||
</div>
|
||||
<p id='startTopLoadTips'>资源即将开始加载</p>
|
||||
<p id='startTopHint'>HTML5魔塔游戏平台,享受更多魔塔游戏:<br />https://h5mota.com/</p>
|
||||
</div>
|
||||
<img id='startBackground'>
|
||||
<p id='startLogo'></p>
|
||||
<div id='startButtonGroup'>
|
||||
<div id='startButtons'>
|
||||
<span class='startButton' id='playGame'>开始游戏</span>
|
||||
<span class='startButton' id='loadGame'>载入游戏</span>
|
||||
<span class='startButton' id='replayGame'>录像回放</span>
|
||||
</div>
|
||||
<div id='levelChooseButtons'></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='floorMsgGroup'>
|
||||
<p id='logoLabel'></p>
|
||||
<p id='versionLabel'></p>
|
||||
<p id='floorNameLabel'></p>
|
||||
</div>
|
||||
<div id='statusBar' class="clearfix">
|
||||
<div class="status" id="floorCol">
|
||||
<img id="img-floor">
|
||||
<p class='statusLabel statusText' id='floor'></p>
|
||||
</div>
|
||||
<div class="status" id="nameCol">
|
||||
<img id="img-name">
|
||||
<p class='statusLabel statusText' id='name'></p>
|
||||
</div>
|
||||
<div class="status" id="lvCol">
|
||||
<img id="img-lv">
|
||||
<p class='statusLabel statusText' id='lv'></p>
|
||||
</div>
|
||||
<div class="status" id='hpmaxCol'>
|
||||
<img id="img-hpmax">
|
||||
<p class='statusLabel statusText' id='hpmax'></p>
|
||||
</div>
|
||||
<div class="status" id='hpCol'>
|
||||
<img id="img-hp">
|
||||
<p class='statusLabel statusText' id='hp'></p>
|
||||
</div>
|
||||
<div class="status" id='manaCol'>
|
||||
<img id="img-mana">
|
||||
<p class='statusLabel statusText' id='mana'></p>
|
||||
</div>
|
||||
<div class="status" id='atkCol'>
|
||||
<img id="img-atk">
|
||||
<p class='statusLabel statusText' id='atk'></p>
|
||||
</div>
|
||||
<div class="status" id='defCol'>
|
||||
<img id="img-def">
|
||||
<p class='statusLabel statusText' id='def'></p>
|
||||
</div>
|
||||
<div class="status" id="mdefCol">
|
||||
<img id="img-mdef">
|
||||
<p class='statusLabel statusText' id='mdef'></p>
|
||||
</div>
|
||||
<div class="status" id="moneyCol">
|
||||
<img id="img-money">
|
||||
<p class='statusLabel statusText' id='money'></p>
|
||||
</div>
|
||||
<div class="status" id="expCol">
|
||||
<img id="img-exp">
|
||||
<p class='statusLabel statusText' id='exp'></p>
|
||||
</div>
|
||||
<div class="status" id="upCol">
|
||||
<img id="img-up">
|
||||
<p class='statusLabel statusText' id='up'></p>
|
||||
</div>
|
||||
<div class="status" id="skillCol">
|
||||
<img id="img-skill">
|
||||
<p class='statusLabel statusText' id='skill' style='font-style: normal'></p>
|
||||
</div>
|
||||
<div class="status" id='keyCol'>
|
||||
<span class='statusLabel' id='yellowKey' style="color:#FFCCAA"></span>
|
||||
<span class='statusLabel' id='blueKey' style="color:#AAAADD"></span>
|
||||
<span class='statusLabel' id='redKey' style="color:#FF8888"></span>
|
||||
<span class='statusLabel' id='greenKey' style="color:#88FF88"></span>
|
||||
</div>
|
||||
<div class="status" id='pzfCol'>
|
||||
<span class='statusLabel' id='pickaxe' style="color: #BC6E27"></span>
|
||||
<span class='statusLabel' id='bomb' style="color: #FA14B9"></span>
|
||||
<span class='statusLabel' id='fly' style="color: #8DB600"></span>
|
||||
</div>
|
||||
<div class="status" id="debuffCol">
|
||||
<span class='statusLabel' id='poison' style="color: #AFFCA8;"></span>
|
||||
<span class='statusLabel' id='weak' style="color: #FECCD0;"></span>
|
||||
<span class='statusLabel' id='curse' style="color: #C2F4E7;"></span>
|
||||
</div>
|
||||
|
||||
<!-- 状态栏canvas化 -->
|
||||
<canvas id="statusCanvas" style="position: absolute; left: 0; top: 0;"></canvas>
|
||||
</div>
|
||||
<div id="toolBar" class="clearfix">
|
||||
<img class="tools" id='img-book'>
|
||||
<img class="tools" id='img-fly'>
|
||||
<img class="tools" id='img-toolbox'>
|
||||
<img class="tools" id='img-keyboard'>
|
||||
<img class="tools" id='img-shop'>
|
||||
<img class="tools" id='img-save'>
|
||||
<img class="tools" id='img-load'>
|
||||
<img class="tools" id='img-settings'>
|
||||
<img class="tools" id='img-btn1' style='display:none'>
|
||||
<img class="tools" id='img-btn2' style='display:none'>
|
||||
<img class="tools" id='img-btn3' style='display:none'>
|
||||
<img class="tools" id='img-btn4' style='display:none'>
|
||||
<img class="tools" id='img-btn5' style='display:none'>
|
||||
<img class="tools" id='img-btn6' style='display:none'>
|
||||
<img class="tools" id='img-btn7' style='display:none'>
|
||||
<img class="tools" id='img-btn8' style='display:none'>
|
||||
<p class="statusLabel tools" id="hard"></p>
|
||||
</div>
|
||||
<div id="gameDraw">
|
||||
<div id="gif"></div>
|
||||
<div id="gif2"></div>
|
||||
<canvas class='gameCanvas anti-aliasing' id='bg'></canvas>
|
||||
<canvas class='gameCanvas anti-aliasing' id='event'></canvas>
|
||||
<canvas class='gameCanvas anti-aliasing' id='hero'></canvas>
|
||||
<canvas class='gameCanvas anti-aliasing' id='event2'></canvas>
|
||||
<canvas class='gameCanvas anti-aliasing' id='fg'></canvas>
|
||||
<canvas class='gameCanvas' id='damage'></canvas>
|
||||
<canvas class='gameCanvas' id='animate'></canvas>
|
||||
<canvas class='gameCanvas' id='curtain'></canvas>
|
||||
<canvas class='gameCanvas' id='ui'></canvas>
|
||||
<canvas class='gameCanvas' id='data'>此浏览器不支持HTML5</canvas>
|
||||
<div id="next"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='inputDiv'>
|
||||
<div id='inputDialog'>
|
||||
<p id="inputMessage">请输入文字...</p>
|
||||
<input id='inputBox' type="text" autocomplete="off" />
|
||||
<button id='inputYes'>确定</button>
|
||||
<button id='inputNo'>取消</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ui-editor"></div>
|
||||
<!-- injection -->
|
||||
<script src='libs/thirdparty/lz-string.min.js'></script>
|
||||
<script src='libs/thirdparty/priority-queue.min.js'></script>
|
||||
<script src='libs/thirdparty/localforage.min.js'></script>
|
||||
<script src='libs/thirdparty/zip.min.js'></script>
|
||||
<script id='mainScript' src='main.js'></script>
|
||||
<script>main.init('play'); main.listen();</script>
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
996
main.js
Normal file
996
main.js
Normal file
@ -0,0 +1,996 @@
|
||||
/// <reference path="./runtime.d.ts" />
|
||||
function main() {
|
||||
//------------------------ 用户修改内容 ------------------------//
|
||||
|
||||
this.version = '2.10.3'; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。
|
||||
|
||||
this.useCompress = false; // 是否使用压缩文件
|
||||
// 当你即将发布你的塔时,请使用“JS代码压缩工具”将所有js代码进行压缩,然后将这里的useCompress改为true。
|
||||
// 请注意,只有useCompress是false时才会读取floors目录下的文件,为true时会直接读取libs目录下的floors.min.js文件。
|
||||
// 如果要进行剧本的修改请务必将其改成false。
|
||||
|
||||
this.bgmRemote = false; // 是否采用远程BGM
|
||||
this.bgmRemoteRoot = 'https://h5mota.com/music/'; // 远程BGM的根目录
|
||||
|
||||
this.isCompetition = false; // 是否是比赛模式
|
||||
|
||||
this.savePages = 1000; // 存档页数,每页可存5个;默认为1000页5000个存档
|
||||
this.criticalUseLoop = 1; // 循环临界的分界
|
||||
|
||||
//------------------------ 用户修改内容 END ------------------------//
|
||||
|
||||
this.dom = {
|
||||
body: document.body,
|
||||
gameGroup: document.getElementById('gameGroup'),
|
||||
mainTips: document.getElementById('mainTips'),
|
||||
musicBtn: document.getElementById('musicBtn'),
|
||||
enlargeBtn: document.createElement('img'),
|
||||
startPanel: document.getElementById('startPanel'),
|
||||
startTop: document.getElementById('startTop'),
|
||||
startTopProgressBar: document.getElementById('startTopProgressBar'),
|
||||
startTopProgress: document.getElementById('startTopProgress'),
|
||||
startTopLoadTips: document.getElementById('startTopLoadTips'),
|
||||
startBackground: document.getElementById('startBackground'),
|
||||
startLogo: document.getElementById('startLogo'),
|
||||
startButtonGroup: document.getElementById('startButtonGroup'),
|
||||
floorMsgGroup: document.getElementById('floorMsgGroup'),
|
||||
logoLabel: document.getElementById('logoLabel'),
|
||||
versionLabel: document.getElementById('versionLabel'),
|
||||
floorNameLabel: document.getElementById('floorNameLabel'),
|
||||
statusBar: document.getElementById('statusBar'),
|
||||
status: document.getElementsByClassName('status'),
|
||||
toolBar: document.getElementById('toolBar'),
|
||||
tools: document.getElementsByClassName('tools'),
|
||||
gameCanvas: document.getElementsByClassName('gameCanvas'),
|
||||
gif: document.getElementById('gif'),
|
||||
gif2: document.getElementById('gif2'),
|
||||
gameDraw: document.getElementById('gameDraw'),
|
||||
startButtons: document.getElementById('startButtons'),
|
||||
playGame: document.getElementById('playGame'),
|
||||
loadGame: document.getElementById('loadGame'),
|
||||
replayGame: document.getElementById('replayGame'),
|
||||
levelChooseButtons: document.getElementById('levelChooseButtons'),
|
||||
data: document.getElementById('data'),
|
||||
statusLabels: document.getElementsByClassName('statusLabel'),
|
||||
statusTexts: document.getElementsByClassName('statusText'),
|
||||
floorCol: document.getElementById('floorCol'),
|
||||
nameCol: document.getElementById('nameCol'),
|
||||
lvCol: document.getElementById('lvCol'),
|
||||
hpmaxCol: document.getElementById('hpmaxCol'),
|
||||
hpCol: document.getElementById('hpCol'),
|
||||
manaCol: document.getElementById('manaCol'),
|
||||
atkCol: document.getElementById('atkCol'),
|
||||
defCol: document.getElementById('defCol'),
|
||||
mdefCol: document.getElementById('mdefCol'),
|
||||
moneyCol: document.getElementById('moneyCol'),
|
||||
expCol: document.getElementById('expCol'),
|
||||
upCol: document.getElementById('upCol'),
|
||||
keyCol: document.getElementById('keyCol'),
|
||||
pzfCol: document.getElementById('pzfCol'),
|
||||
debuffCol: document.getElementById('debuffCol'),
|
||||
skillCol: document.getElementById('skillCol'),
|
||||
hard: document.getElementById('hard'),
|
||||
statusCanvas: document.getElementById('statusCanvas'),
|
||||
statusCanvasCtx: document
|
||||
.getElementById('statusCanvas')
|
||||
.getContext('2d'),
|
||||
inputDiv: document.getElementById('inputDiv'),
|
||||
inputMessage: document.getElementById('inputMessage'),
|
||||
inputBox: document.getElementById('inputBox'),
|
||||
inputYes: document.getElementById('inputYes'),
|
||||
inputNo: document.getElementById('inputNo'),
|
||||
next: document.getElementById('next')
|
||||
};
|
||||
this.mode = 'play';
|
||||
this.loadList = [
|
||||
'loader',
|
||||
'control',
|
||||
'utils',
|
||||
'items',
|
||||
'icons',
|
||||
'maps',
|
||||
'enemys',
|
||||
'events',
|
||||
'actions',
|
||||
'data',
|
||||
'ui',
|
||||
'extensions',
|
||||
'core'
|
||||
];
|
||||
this.pureData = [
|
||||
'data',
|
||||
'enemys',
|
||||
'icons',
|
||||
'maps',
|
||||
'items',
|
||||
'functions',
|
||||
'events',
|
||||
'plugins'
|
||||
];
|
||||
this.materials = [
|
||||
'animates',
|
||||
'enemys',
|
||||
'items',
|
||||
'npcs',
|
||||
'terrains',
|
||||
'enemy48',
|
||||
'npc48',
|
||||
'icons'
|
||||
];
|
||||
|
||||
this.statusBar = {
|
||||
image: {
|
||||
floor: document.getElementById('img-floor'),
|
||||
name: document.getElementById('img-name'),
|
||||
lv: document.getElementById('img-lv'),
|
||||
hpmax: document.getElementById('img-hpmax'),
|
||||
hp: document.getElementById('img-hp'),
|
||||
mana: document.getElementById('img-mana'),
|
||||
atk: document.getElementById('img-atk'),
|
||||
def: document.getElementById('img-def'),
|
||||
mdef: document.getElementById('img-mdef'),
|
||||
money: document.getElementById('img-money'),
|
||||
exp: document.getElementById('img-exp'),
|
||||
up: document.getElementById('img-up'),
|
||||
skill: document.getElementById('img-skill'),
|
||||
book: document.getElementById('img-book'),
|
||||
fly: document.getElementById('img-fly'),
|
||||
toolbox: document.getElementById('img-toolbox'),
|
||||
keyboard: document.getElementById('img-keyboard'),
|
||||
shop: document.getElementById('img-shop'),
|
||||
save: document.getElementById('img-save'),
|
||||
load: document.getElementById('img-load'),
|
||||
settings: document.getElementById('img-settings'),
|
||||
btn1: document.getElementById('img-btn1'),
|
||||
btn2: document.getElementById('img-btn2'),
|
||||
btn3: document.getElementById('img-btn3'),
|
||||
btn4: document.getElementById('img-btn4'),
|
||||
btn5: document.getElementById('img-btn5'),
|
||||
btn6: document.getElementById('img-btn6'),
|
||||
btn7: document.getElementById('img-btn7'),
|
||||
btn8: document.getElementById('img-btn8')
|
||||
},
|
||||
icons: {
|
||||
floor: 0,
|
||||
name: null,
|
||||
lv: 1,
|
||||
hpmax: 2,
|
||||
hp: 3,
|
||||
atk: 4,
|
||||
def: 5,
|
||||
mdef: 6,
|
||||
money: 7,
|
||||
exp: 8,
|
||||
up: 9,
|
||||
book: 10,
|
||||
fly: 11,
|
||||
toolbox: 12,
|
||||
keyboard: 13,
|
||||
shop: 14,
|
||||
save: 15,
|
||||
load: 16,
|
||||
settings: 17,
|
||||
play: 18,
|
||||
pause: 19,
|
||||
stop: 20,
|
||||
speedDown: 21,
|
||||
speedUp: 22,
|
||||
rewind: 23,
|
||||
equipbox: 24,
|
||||
mana: 25,
|
||||
skill: 26,
|
||||
btn1: 27,
|
||||
btn2: 28,
|
||||
btn3: 29,
|
||||
btn4: 30,
|
||||
btn5: 31,
|
||||
btn6: 32,
|
||||
btn7: 33,
|
||||
btn8: 34
|
||||
},
|
||||
floor: document.getElementById('floor'),
|
||||
name: document.getElementById('name'),
|
||||
lv: document.getElementById('lv'),
|
||||
hpmax: document.getElementById('hpmax'),
|
||||
hp: document.getElementById('hp'),
|
||||
mana: document.getElementById('mana'),
|
||||
atk: document.getElementById('atk'),
|
||||
def: document.getElementById('def'),
|
||||
mdef: document.getElementById('mdef'),
|
||||
money: document.getElementById('money'),
|
||||
exp: document.getElementById('exp'),
|
||||
up: document.getElementById('up'),
|
||||
skill: document.getElementById('skill'),
|
||||
yellowKey: document.getElementById('yellowKey'),
|
||||
blueKey: document.getElementById('blueKey'),
|
||||
redKey: document.getElementById('redKey'),
|
||||
greenKey: document.getElementById('greenKey'),
|
||||
poison: document.getElementById('poison'),
|
||||
weak: document.getElementById('weak'),
|
||||
curse: document.getElementById('curse'),
|
||||
pickaxe: document.getElementById('pickaxe'),
|
||||
bomb: document.getElementById('bomb'),
|
||||
fly: document.getElementById('fly'),
|
||||
hard: document.getElementById('hard')
|
||||
};
|
||||
this.floors = {};
|
||||
this.canvas = {};
|
||||
|
||||
this.__VERSION__ = '2.10.3';
|
||||
this.__VERSION_CODE__ = 512;
|
||||
}
|
||||
|
||||
main.prototype.init = function (mode, callback) {
|
||||
for (var i = 0; i < main.dom.gameCanvas.length; i++) {
|
||||
main.canvas[main.dom.gameCanvas[i].id] =
|
||||
main.dom.gameCanvas[i].getContext('2d');
|
||||
}
|
||||
main.mode = mode;
|
||||
|
||||
main.loadJs('project', main.pureData, function () {
|
||||
var mainData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main;
|
||||
for (var ii in mainData) main[ii] = mainData[ii];
|
||||
|
||||
main.dom.startLogo.style = main.styles.startLogoStyle;
|
||||
main.dom.startButtonGroup.style = main.styles.startButtonsStyle;
|
||||
main.levelChoose = main.levelChoose || [];
|
||||
main.levelChoose.forEach(function (value) {
|
||||
var span = document.createElement('span');
|
||||
span.setAttribute('class', 'startButton');
|
||||
span.innerText = value.title || '';
|
||||
(function (span, str_) {
|
||||
span.onclick = function () {
|
||||
core.events.startGame(str_);
|
||||
};
|
||||
})(span, value.name || '');
|
||||
main.dom.levelChooseButtons.appendChild(span);
|
||||
});
|
||||
main.createOnChoiceAnimation();
|
||||
main.importFonts(main.fonts);
|
||||
|
||||
main.loadJs('libs', main.loadList, function () {
|
||||
main.core = core;
|
||||
|
||||
for (i = 0; i < main.loadList.length; i++) {
|
||||
var name = main.loadList[i];
|
||||
if (name === 'core') continue;
|
||||
main.core[name] = new window[name]();
|
||||
}
|
||||
|
||||
main.loadFloors(function () {
|
||||
var coreData = {};
|
||||
[
|
||||
'dom',
|
||||
'statusBar',
|
||||
'canvas',
|
||||
'images',
|
||||
'tilesets',
|
||||
'materials',
|
||||
'animates',
|
||||
'bgms',
|
||||
'sounds',
|
||||
'floorIds',
|
||||
'floors',
|
||||
'floorPartitions'
|
||||
].forEach(function (t) {
|
||||
coreData[t] = main[t];
|
||||
});
|
||||
main.core.init(coreData, callback);
|
||||
main.core.resize();
|
||||
// 自动放缩最大化
|
||||
if (!main.replayChecking) {
|
||||
return;
|
||||
if (core.getLocalStorage('autoScale') == null) {
|
||||
core.setLocalStorage('autoScale', true);
|
||||
}
|
||||
if (
|
||||
core.getLocalStorage('autoScale') &&
|
||||
!core.domStyle.isVertical
|
||||
) {
|
||||
try {
|
||||
if (main.core) {
|
||||
var index =
|
||||
main.core.domStyle.availableScale.indexOf(
|
||||
core.domStyle.scale
|
||||
);
|
||||
main.core.control.setDisplayScale(
|
||||
main.core.domStyle.availableScale.length -
|
||||
1 -
|
||||
index
|
||||
);
|
||||
if (
|
||||
!main.core.isPlaying() &&
|
||||
main.core.flags.enableHDCanvas
|
||||
) {
|
||||
main.core.domStyle.ratio = Math.max(
|
||||
window.devicePixelRatio || 1,
|
||||
main.core.domStyle.scale
|
||||
);
|
||||
main.core.resize();
|
||||
}
|
||||
requestAnimationFrame(function () {
|
||||
var style = getComputedStyle(
|
||||
main.dom.gameGroup
|
||||
);
|
||||
var height = parseFloat(style.height);
|
||||
if (height > window.innerHeight * 0.95) {
|
||||
main.core.control.setDisplayScale(-1);
|
||||
if (
|
||||
!main.core.isPlaying() &&
|
||||
main.core.flags.enableHDCanvas
|
||||
) {
|
||||
main.core.domStyle.ratio = Math.max(
|
||||
window.devicePixelRatio || 1,
|
||||
main.core.domStyle.scale
|
||||
);
|
||||
main.core.resize();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
////// 动态加载所有核心JS文件 //////
|
||||
main.prototype.loadJs = function (dir, loadList, callback) {
|
||||
// 加载js
|
||||
main.setMainTipsText('正在加载核心js文件...');
|
||||
|
||||
if (this.useCompress) {
|
||||
main.loadMod(dir, dir, function () {
|
||||
callback();
|
||||
});
|
||||
} else {
|
||||
var instanceNum = 0;
|
||||
for (var i = 0; i < loadList.length; i++) {
|
||||
main.loadMod(dir, loadList[i], function (modName) {
|
||||
main.setMainTipsText(modName + '.js 加载完毕');
|
||||
instanceNum++;
|
||||
if (instanceNum === loadList.length) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
////// 加载某一个JS文件 //////
|
||||
main.prototype.loadMod = function (dir, modName, callback, onerror) {
|
||||
var script = document.createElement('script');
|
||||
var name = modName;
|
||||
script.src =
|
||||
dir +
|
||||
'/' +
|
||||
modName +
|
||||
(this.useCompress ? '.min' : '') +
|
||||
'.js?v=' +
|
||||
this.version;
|
||||
script.onload = function () {
|
||||
callback(name);
|
||||
};
|
||||
main.dom.body.appendChild(script);
|
||||
};
|
||||
|
||||
////// 动态加载所有楼层(剧本) //////
|
||||
main.prototype.loadFloors = function (callback) {
|
||||
// 加载js
|
||||
main.setMainTipsText('正在加载楼层文件...');
|
||||
if (this.useCompress) {
|
||||
// 读取压缩文件
|
||||
var script = document.createElement('script');
|
||||
script.src = 'project/floors.min.js?v=' + this.version;
|
||||
main.dom.body.appendChild(script);
|
||||
script.onload = function () {
|
||||
main.dom.mainTips.style.display = 'none';
|
||||
callback();
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// 高层塔优化
|
||||
var script = document.createElement('script');
|
||||
script.src =
|
||||
'__all_floors__.js?v=' +
|
||||
this.version +
|
||||
'&id=' +
|
||||
main.floorIds.join(',');
|
||||
script.onload = function () {
|
||||
main.dom.mainTips.style.display = 'none';
|
||||
main.supportBunch = true;
|
||||
callback();
|
||||
};
|
||||
script.onerror =
|
||||
script.onabort =
|
||||
script.ontimeout =
|
||||
function (e) {
|
||||
// console.clear();
|
||||
for (var i = 0; i < main.floorIds.length; i++) {
|
||||
main.loadFloor(main.floorIds[i], function (modName) {
|
||||
main.setMainTipsText(
|
||||
'楼层 ' + modName + '.js 加载完毕'
|
||||
);
|
||||
if (
|
||||
Object.keys(main.floors).length ===
|
||||
main.floorIds.length
|
||||
) {
|
||||
main.dom.mainTips.style.display = 'none';
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
main.dom.body.appendChild(script);
|
||||
};
|
||||
|
||||
////// 加载某一个楼层 //////
|
||||
main.prototype.loadFloor = function (floorId, callback) {
|
||||
var script = document.createElement('script');
|
||||
script.src = 'project/floors/' + floorId + '.js?v=' + this.version;
|
||||
main.dom.body.appendChild(script);
|
||||
script.onload = function () {
|
||||
callback(floorId);
|
||||
};
|
||||
};
|
||||
|
||||
////// 加载过程提示 //////
|
||||
main.prototype.setMainTipsText = function (text) {
|
||||
main.dom.mainTips.innerHTML = text;
|
||||
};
|
||||
|
||||
main.prototype.log = function (e, error) {
|
||||
if (e) {
|
||||
if (error) return console.error(e);
|
||||
if (main.core && main.core.platform && !main.core.platform.isPC) {
|
||||
console.log(e.stack || e.toString());
|
||||
} else {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
main.prototype.createOnChoiceAnimation = function () {
|
||||
var borderColor =
|
||||
main.dom.startButtonGroup.style.caretColor || 'rgb(255, 215, 0)';
|
||||
// get rgb value
|
||||
var rgb =
|
||||
/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*\d+\s*)?\)$/.exec(
|
||||
borderColor
|
||||
);
|
||||
if (rgb != null) {
|
||||
var value = rgb[1] + ', ' + rgb[2] + ', ' + rgb[3];
|
||||
var style = document.createElement('style');
|
||||
style.type = 'text/css';
|
||||
var keyFrames =
|
||||
'onChoice { ' +
|
||||
'0% { border-color: rgba(' +
|
||||
value +
|
||||
', 0.9); } ' +
|
||||
'50% { border-color: rgba(' +
|
||||
value +
|
||||
', 0.3); } ' +
|
||||
'100% { border-color: rgba(' +
|
||||
value +
|
||||
', 0.9); } ' +
|
||||
'}';
|
||||
style.innerHTML =
|
||||
'@-webkit-keyframes ' + keyFrames + ' @keyframes ' + keyFrames;
|
||||
document.body.appendChild(style);
|
||||
}
|
||||
};
|
||||
|
||||
////// 选项 //////
|
||||
main.prototype.selectButton = function (index) {
|
||||
var select = function (children) {
|
||||
index = (index + children.length) % children.length;
|
||||
for (var i = 0; i < children.length; ++i) {
|
||||
children[i].classList.remove('onChoiceAnimate');
|
||||
}
|
||||
children[index].classList.add('onChoiceAnimate');
|
||||
if (main.selectedButton == index) {
|
||||
children[index].click();
|
||||
} else {
|
||||
main.selectedButton = index;
|
||||
}
|
||||
};
|
||||
|
||||
if (core.dom.startPanel.style.display != 'block') return;
|
||||
|
||||
if (main.dom.startButtons.style.display == 'block') {
|
||||
select(main.dom.startButtons.children);
|
||||
} else if (main.dom.levelChooseButtons.style.display == 'block') {
|
||||
select(main.dom.levelChooseButtons.children);
|
||||
}
|
||||
};
|
||||
|
||||
////// 创建字体 //////
|
||||
main.prototype.importFonts = function (fonts) {
|
||||
if (!(fonts instanceof Array) || fonts.length == 0) return;
|
||||
var style = document.createElement('style');
|
||||
style.type = 'text/css';
|
||||
var html = '';
|
||||
fonts.forEach(function (font) {
|
||||
html +=
|
||||
'@font-face { font-family: "' +
|
||||
font +
|
||||
'"; src: url("project/fonts/' +
|
||||
font +
|
||||
'.ttf") format("truetype"); }';
|
||||
});
|
||||
style.innerHTML = html;
|
||||
document.body.appendChild(style);
|
||||
};
|
||||
|
||||
main.prototype.listen = function () {
|
||||
////// 窗口大小变化时 //////
|
||||
window.onresize = function () {
|
||||
try {
|
||||
main.core.resize();
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
////// 在界面上按下某按键时 //////
|
||||
main.dom.body.onkeydown = function (e) {
|
||||
if (main.editorOpened) return;
|
||||
try {
|
||||
if (main.dom.inputDiv.style.display == 'block') return;
|
||||
if (
|
||||
main.core &&
|
||||
(main.core.isPlaying() || main.core.status.lockControl)
|
||||
)
|
||||
main.core.onkeyDown(e);
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
////// 在界面上放开某按键时 //////
|
||||
main.dom.body.onkeyup = function (e) {
|
||||
if (main.editorOpened) return;
|
||||
try {
|
||||
if (
|
||||
main.dom.startPanel.style.display == 'block' &&
|
||||
(main.dom.startButtons.style.display == 'block' ||
|
||||
main.dom.levelChooseButtons.style.display == 'block')
|
||||
) {
|
||||
if (e.keyCode == 38 || e.keyCode == 33)
|
||||
// up/pgup
|
||||
main.selectButton((main.selectedButton || 0) - 1);
|
||||
else if (e.keyCode == 40 || e.keyCode == 34)
|
||||
// down/pgdn
|
||||
main.selectButton((main.selectedButton || 0) + 1);
|
||||
else if (e.keyCode == 67 || e.keyCode == 13 || e.keyCode == 32)
|
||||
// C/Enter/Space
|
||||
main.selectButton(main.selectedButton);
|
||||
else if (
|
||||
e.keyCode == 27 &&
|
||||
main.dom.levelChooseButtons.style.display == 'block'
|
||||
) {
|
||||
// ESC
|
||||
main.core.showStartAnimate(true);
|
||||
}
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
if (main.dom.inputDiv.style.display == 'block') {
|
||||
if (e.keyCode == 13) {
|
||||
setTimeout(function () {
|
||||
main.dom.inputYes.click();
|
||||
}, 50);
|
||||
} else if (e.keyCode == 27) {
|
||||
setTimeout(function () {
|
||||
main.dom.inputNo.click();
|
||||
}, 50);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (
|
||||
main.core &&
|
||||
main.core.isPlaying &&
|
||||
main.core.status &&
|
||||
(main.core.isPlaying() || main.core.status.lockControl)
|
||||
)
|
||||
main.core.onkeyUp(e);
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
[main.dom.startButtons, main.dom.levelChooseButtons].forEach(function (
|
||||
dom
|
||||
) {
|
||||
dom.onmousemove = function (e) {
|
||||
for (var i = 0; i < dom.children.length; ++i) {
|
||||
if (
|
||||
dom.children[i] == e.target &&
|
||||
i != (main.selectedButton || 0)
|
||||
) {
|
||||
main.selectButton(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
////// 开始选择时 //////
|
||||
main.dom.body.onselectstart = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
////// 鼠标按下时 //////
|
||||
main.dom.data.onmousedown = function (e) {
|
||||
try {
|
||||
e.stopPropagation();
|
||||
var loc = main.core.actions._getClickLoc(e.clientX, e.clientY);
|
||||
if (loc == null) return;
|
||||
main.core.ondown(loc);
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
////// 鼠标移动时 //////
|
||||
main.dom.data.onmousemove = function (e) {
|
||||
try {
|
||||
e.stopPropagation();
|
||||
var loc = main.core.actions._getClickLoc(e.clientX, e.clientY);
|
||||
if (loc == null) return;
|
||||
main.core.onmove(loc);
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
////// 鼠标放开时 //////
|
||||
main.dom.data.onmouseup = function (e) {
|
||||
try {
|
||||
e.stopPropagation();
|
||||
var loc = main.core.actions._getClickLoc(e.clientX, e.clientY);
|
||||
if (loc == null) return;
|
||||
main.core.onup(loc);
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
////// 鼠标滑轮滚动时 //////
|
||||
main.dom.data.onmousewheel = function (e) {
|
||||
try {
|
||||
if (e.wheelDelta) main.core.onmousewheel(Math.sign(e.wheelDelta));
|
||||
else if (e.detail) main.core.onmousewheel(Math.sign(e.detail));
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
////// 手指在触摸屏开始触摸时 //////
|
||||
main.dom.data.ontouchstart = function (e) {
|
||||
try {
|
||||
e.preventDefault();
|
||||
var loc = main.core.actions._getClickLoc(
|
||||
e.targetTouches[0].clientX,
|
||||
e.targetTouches[0].clientY
|
||||
);
|
||||
if (loc == null) return;
|
||||
main.lastTouchLoc = loc;
|
||||
main.core.ondown(loc);
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
////// 手指在触摸屏上移动时 //////
|
||||
main.dom.data.ontouchmove = function (e) {
|
||||
try {
|
||||
e.preventDefault();
|
||||
var loc = main.core.actions._getClickLoc(
|
||||
e.targetTouches[0].clientX,
|
||||
e.targetTouches[0].clientY
|
||||
);
|
||||
if (loc == null) return;
|
||||
main.lastTouchLoc = loc;
|
||||
main.core.onmove(loc);
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
////// 手指离开触摸屏时 //////
|
||||
main.dom.data.ontouchend = function (e) {
|
||||
try {
|
||||
e.preventDefault();
|
||||
if (main.lastTouchLoc == null) return;
|
||||
var loc = main.lastTouchLoc;
|
||||
delete main.lastTouchLoc;
|
||||
main.core.onup(loc);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
main.dom.statusCanvas.onclick = function (e) {
|
||||
try {
|
||||
e.preventDefault();
|
||||
main.core.onStatusBarClick(e);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
////// 点击状态栏中的怪物手册时 //////
|
||||
main.statusBar.image.book.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (core.isReplaying()) {
|
||||
core.triggerReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying()) main.core.openBook(true);
|
||||
};
|
||||
|
||||
////// 点击状态栏中的楼层传送器/装备栏时 //////
|
||||
main.statusBar.image.fly.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
// 播放录像时
|
||||
if (core.isReplaying()) {
|
||||
core.stopReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying()) {
|
||||
if (!main.core.flags.equipboxButton) {
|
||||
main.core.useFly(true);
|
||||
} else {
|
||||
main.core.openEquipbox(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
////// 点击状态栏中的工具箱时 //////
|
||||
main.statusBar.image.toolbox.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (core.isReplaying()) {
|
||||
core.rewindReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying()) {
|
||||
main.core.openToolbox(core.status.event.id != 'equipbox');
|
||||
}
|
||||
};
|
||||
|
||||
////// 双击状态栏中的工具箱时 //////
|
||||
main.statusBar.image.toolbox.ondblclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (core.isReplaying()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying()) main.core.openEquipbox(true);
|
||||
};
|
||||
|
||||
////// 点击状态栏中的虚拟键盘时 //////
|
||||
main.statusBar.image.keyboard.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (core.isReplaying()) {
|
||||
core.control._replay_book();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying()) main.core.openKeyBoard(true);
|
||||
};
|
||||
|
||||
////// 点击状态栏中的快捷商店时 //////
|
||||
main.statusBar.image.shop.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (core.isReplaying()) {
|
||||
core.control._replay_viewMap();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying()) main.core.openQuickShop(true);
|
||||
};
|
||||
|
||||
////// 点击金币时也可以开启快捷商店 //////
|
||||
main.statusBar.image.money.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (main.core.isPlaying()) main.core.openQuickShop(true);
|
||||
};
|
||||
|
||||
////// 点击楼梯图标也可以浏览地图 //////
|
||||
main.statusBar.image.floor.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (
|
||||
main.core &&
|
||||
main.core.isPlaying() &&
|
||||
!core.isMoving() &&
|
||||
!core.status.lockControl
|
||||
) {
|
||||
core.ui._drawViewMaps();
|
||||
}
|
||||
};
|
||||
|
||||
////// 点击状态栏中的存档按钮时 //////
|
||||
main.statusBar.image.save.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (core.isReplaying()) {
|
||||
core.speedDownReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying()) main.core.save(true);
|
||||
};
|
||||
|
||||
////// 点击状态栏中的读档按钮时 //////
|
||||
main.statusBar.image.load.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (core.isReplaying()) {
|
||||
core.speedUpReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying()) main.core.load(true);
|
||||
};
|
||||
|
||||
////// 点击状态栏中的系统菜单时 //////
|
||||
main.statusBar.image.settings.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (core.isReplaying()) {
|
||||
core.control._replay_SL();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying()) main.core.openSettings(true);
|
||||
};
|
||||
|
||||
////// 点击工具栏时 //////
|
||||
main.dom.hard.onclick = function () {
|
||||
main.core.control.setToolbarButton(!core.domStyle.toolbarBtn);
|
||||
};
|
||||
|
||||
////// 手机端的按钮1-7 //////
|
||||
main.statusBar.image.btn1.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
main.core.onkeyUp({
|
||||
keyCode: 49,
|
||||
altKey: core.getLocalStorage('altKey')
|
||||
});
|
||||
};
|
||||
|
||||
main.statusBar.image.btn2.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
main.core.onkeyUp({
|
||||
keyCode: 50,
|
||||
altKey: core.getLocalStorage('altKey')
|
||||
});
|
||||
};
|
||||
|
||||
main.statusBar.image.btn3.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
main.core.onkeyUp({
|
||||
keyCode: 51,
|
||||
altKey: core.getLocalStorage('altKey')
|
||||
});
|
||||
};
|
||||
|
||||
main.statusBar.image.btn4.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
main.core.onkeyUp({
|
||||
keyCode: 52,
|
||||
altKey: core.getLocalStorage('altKey')
|
||||
});
|
||||
};
|
||||
|
||||
main.statusBar.image.btn5.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
main.core.onkeyUp({
|
||||
keyCode: 53,
|
||||
altKey: core.getLocalStorage('altKey')
|
||||
});
|
||||
};
|
||||
|
||||
main.statusBar.image.btn6.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
main.core.onkeyUp({
|
||||
keyCode: 54,
|
||||
altKey: core.getLocalStorage('altKey')
|
||||
});
|
||||
};
|
||||
|
||||
main.statusBar.image.btn7.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
main.core.onkeyUp({
|
||||
keyCode: 55,
|
||||
altKey: core.getLocalStorage('altKey')
|
||||
});
|
||||
};
|
||||
|
||||
main.statusBar.image.btn8.onclick = function (e) {
|
||||
e.stopPropagation();
|
||||
if (core.getLocalStorage('altKey')) {
|
||||
core.removeLocalStorage('altKey');
|
||||
core.drawTip('Alt模式已关闭。');
|
||||
main.statusBar.image.btn8.style.filter = '';
|
||||
} else {
|
||||
core.setLocalStorage('altKey', true);
|
||||
core.drawTip('Alt模式已开启;此模式下1~7按钮视为Alt+1~7。');
|
||||
main.statusBar.image.btn8.style.filter = 'sepia(1) contrast(1.5)';
|
||||
}
|
||||
};
|
||||
|
||||
////// 点击“开始游戏”时 //////
|
||||
main.dom.playGame.onclick = function () {
|
||||
main.dom.startButtons.style.display = 'none';
|
||||
main.core.control.checkBgm();
|
||||
|
||||
if (main.levelChoose.length == 0) {
|
||||
core.events.startGame('');
|
||||
} else {
|
||||
main.dom.levelChooseButtons.style.display = 'block';
|
||||
main.selectedButton = null;
|
||||
main.selectButton(0);
|
||||
}
|
||||
};
|
||||
|
||||
////// 点击“载入游戏”时 //////
|
||||
main.dom.loadGame.onclick = function () {
|
||||
main.core.control.checkBgm();
|
||||
main.core.load();
|
||||
};
|
||||
|
||||
////// 点击“录像回放”时 //////
|
||||
main.dom.replayGame.onclick = function () {
|
||||
main.core.control.checkBgm();
|
||||
main.core.chooseReplayFile();
|
||||
};
|
||||
|
||||
main.dom.musicBtn.onclick = function () {
|
||||
try {
|
||||
if (main.core) main.core.triggerBgm();
|
||||
} catch (ee) {
|
||||
console.error(ee);
|
||||
}
|
||||
};
|
||||
|
||||
window.onblur = function () {
|
||||
if (main.core && main.core.control) {
|
||||
try {
|
||||
main.core.control.checkAutosave();
|
||||
} catch (e) {}
|
||||
}
|
||||
};
|
||||
|
||||
main.dom.inputYes.onclick = function () {
|
||||
main.dom.inputDiv.style.display = 'none';
|
||||
var func = core.platform.successCallback;
|
||||
core.platform.successCallback = core.platform.errorCallback = null;
|
||||
if (func) func(main.dom.inputBox.value);
|
||||
};
|
||||
|
||||
main.dom.inputNo.onclick = function () {
|
||||
main.dom.inputDiv.style.display = 'none';
|
||||
var func = core.platform.errorCallback;
|
||||
core.platform.successCallback = core.platform.errorCallback = null;
|
||||
if (func) func(null);
|
||||
};
|
||||
}; //listen end
|
||||
|
||||
var main = new main();
|
3052
runtime.d.ts
vendored
Normal file
3052
runtime.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
runtime.min.d.ts
vendored
Normal file
1
runtime.min.d.ts
vendored
Normal file
File diff suppressed because one or more lines are too long
651
server.js
Normal file
651
server.js
Normal file
@ -0,0 +1,651 @@
|
||||
const http = require('http');
|
||||
const fs = require('fs/promises');
|
||||
const fss = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const name = (() => {
|
||||
const data = fss.readFileSync('./project/data.js', 'utf-8');
|
||||
const json = JSON.parse(
|
||||
data
|
||||
.split(/(\n|\r\n)/)
|
||||
.slice(1)
|
||||
.join('\n')
|
||||
);
|
||||
return json.firstData.name;
|
||||
})();
|
||||
|
||||
/** 核心服务器 */
|
||||
const server = http.createServer();
|
||||
|
||||
/** 是否需要重新加载浏览器 */
|
||||
let needReload = true;
|
||||
|
||||
/** 热重载信息 */
|
||||
let hotReloadData = '';
|
||||
|
||||
/** 是否已经启动了热重载模块 */
|
||||
let watched = false;
|
||||
|
||||
/** 是否已经启动了录像调试模块 */
|
||||
let replayed = false;
|
||||
|
||||
/** 监听端口 */
|
||||
let port = 3000;
|
||||
const next = () => {
|
||||
server.listen(port, '127.0.0.1');
|
||||
server.on('error', () => {
|
||||
console.log(`${port}端口已被占用`);
|
||||
port++;
|
||||
next();
|
||||
});
|
||||
};
|
||||
next();
|
||||
|
||||
let repStart;
|
||||
|
||||
const listenedFloors = [];
|
||||
|
||||
// ----- GET file
|
||||
|
||||
/**
|
||||
* 请求文件
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
* @param {string} path
|
||||
*/
|
||||
async function getFile(req, res, path) {
|
||||
try {
|
||||
const data = await fs.readFile(path);
|
||||
if (path.endsWith('.js'))
|
||||
res.writeHead(200, { 'Content-type': 'text/javascript' });
|
||||
if (path.endsWith('.css'))
|
||||
res.writeHead(200, { 'Content-type': 'text/css' });
|
||||
if (path.endsWith('.html'))
|
||||
res.writeHead(200, { 'Content-type': 'text/html' });
|
||||
return res.end(data), true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 高层塔优化及动画加载
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
* @param {string[]} ids
|
||||
* @param {string} suffix 后缀名
|
||||
* @param {string} dir 文件夹路径
|
||||
* @param {string} join 分隔符
|
||||
*/
|
||||
async function getAll(req, res, ids, suffix, dir, join) {
|
||||
let data = {};
|
||||
const tasks = ids.map(v => {
|
||||
return new Promise(res => {
|
||||
const d = path.resolve(__dirname, `${dir}${v}${suffix}`);
|
||||
try {
|
||||
fs.readFile(d).then(vv => {
|
||||
data[v] = vv;
|
||||
res(`${v} pack success.`);
|
||||
});
|
||||
} catch {
|
||||
throw new ReferenceError(`The file ${d} does not exists.`);
|
||||
}
|
||||
});
|
||||
});
|
||||
await Promise.all(tasks);
|
||||
const result = ids.map(v => data[v]);
|
||||
return res.end(result.join(join)), true;
|
||||
}
|
||||
|
||||
// ----- 样板的fs功能
|
||||
|
||||
/**
|
||||
* 获取POST的数据
|
||||
* @param {http.IncomingMessage} req
|
||||
*/
|
||||
async function getPostData(req) {
|
||||
let data = '';
|
||||
await new Promise(res => {
|
||||
req.on('data', chunk => {
|
||||
data += chunk.toString();
|
||||
});
|
||||
req.on('end', res);
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function readDir(req, res) {
|
||||
const data = await getPostData(req);
|
||||
const dir = path.resolve(__dirname, data.toString().slice(5));
|
||||
try {
|
||||
const info = await fs.readdir(dir);
|
||||
res.end(JSON.stringify(info));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
res.end(`error: Read dir ${dir} fail. Does the dir exists?`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function mkdir(req, res) {
|
||||
const data = await getPostData(req);
|
||||
const dir = path.resolve(__dirname, data.toString().slice(5));
|
||||
try {
|
||||
await fs.mkdir(dir);
|
||||
} catch (e) {}
|
||||
res.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function readFile(req, res) {
|
||||
const data = (await getPostData(req)).toString();
|
||||
const dir = path.resolve(__dirname, data.split('&name=')[1]);
|
||||
try {
|
||||
const type = /^type=(utf8|base64)/.exec(data)[0];
|
||||
const info = await fs.readFile(dir, { encoding: type.slice(5) });
|
||||
res.end(info);
|
||||
} catch (e) {
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function writeFile(req, res) {
|
||||
const data = (await getPostData(req)).toString();
|
||||
const name = data.split('&name=')[1].split('&value=')[0];
|
||||
const dir = path.resolve(__dirname, name);
|
||||
try {
|
||||
const type = /^type=(utf8|base64)/.exec(data)[0].slice(5);
|
||||
const value = /&value=[^]+/.exec(data)[0].slice(7);
|
||||
await fs.writeFile(dir, value, { encoding: type });
|
||||
testWatchFloor(name);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
res.end(
|
||||
`error: Write file ${dir} fail. Does the parent folder exists?`
|
||||
);
|
||||
}
|
||||
res.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function rm(req, res) {
|
||||
const data = (await getPostData(req)).toString();
|
||||
const dir = path.resolve(__dirname, data.slice(5));
|
||||
try {
|
||||
await fs.rm(dir);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
res.end(`error: Remove file ${dir} fail. Does this file exists?`);
|
||||
}
|
||||
res.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function moveFile(req, res) {
|
||||
const data = (await getPostData(req)).toString();
|
||||
const info = data.split('&dest=');
|
||||
const src = path.resolve(__dirname, info[0].slice(4));
|
||||
const dest = info[1];
|
||||
try {
|
||||
const data = await fs.readFile(src);
|
||||
await fs.writeFile(path.resolve(__dirname, dest), data);
|
||||
await fs.rm(src);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
res.end(`error: Move file ${dir} fail.`);
|
||||
}
|
||||
res.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function writeMultiFiles(req, res) {
|
||||
const data = (await getPostData(req)).toString();
|
||||
const names = /name=[^]+&value=/.exec(data)[0].slice(5, -7).split(';');
|
||||
const value = /&value=[^]+/.exec(data)[0].slice(7).split(';');
|
||||
|
||||
const tasks = names.map((v, i) => {
|
||||
try {
|
||||
return new Promise(res => {
|
||||
fs.writeFile(
|
||||
path.resolve(__dirname, v),
|
||||
value[i],
|
||||
'base64' // 多文件是base64写入的
|
||||
).then(v => {
|
||||
testWatchFloor(v);
|
||||
res(`write ${v} success.`);
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
console.error(e);
|
||||
res.end(`error: Write multi files fail.`);
|
||||
}
|
||||
});
|
||||
await Promise.all(tasks);
|
||||
res.end();
|
||||
}
|
||||
|
||||
// ----- extract path & utils
|
||||
|
||||
/**
|
||||
* 解析路径
|
||||
* @param {...string} dirs
|
||||
* @returns {Promise<string[]>}
|
||||
*/
|
||||
async function extract(...dirs) {
|
||||
const res = [];
|
||||
const tasks = dirs.map(v => {
|
||||
return new Promise(resolve => {
|
||||
if (v.endsWith('/')) {
|
||||
// 匹配路径
|
||||
const dir = path.resolve(__dirname, v.slice(0, -1));
|
||||
fs.readdir(dir).then(files => {
|
||||
const all = files
|
||||
.filter(v => v !== 'thirdparty') // 排除第三方库
|
||||
.map(vv => v + vv);
|
||||
|
||||
res.push(...all);
|
||||
resolve('success');
|
||||
});
|
||||
} else if (/\/\*.\w+$/.test(v)) {
|
||||
// 匹配文件夹中的后缀名
|
||||
const suffix = /\.\w+$/.exec(v)[0];
|
||||
const d = v.split(`/*${suffix}`)[0];
|
||||
const dir = path.resolve(__dirname, d);
|
||||
fs.readdir(dir).then(files => {
|
||||
const all = files
|
||||
.filter(v => v.endsWith(suffix))
|
||||
.map(v => `${d === '' ? '' : d + '/'}${v}`);
|
||||
|
||||
res.push(...all);
|
||||
resolve('success');
|
||||
});
|
||||
} else {
|
||||
res.push(v);
|
||||
resolve('success');
|
||||
}
|
||||
});
|
||||
});
|
||||
await Promise.all(tasks);
|
||||
return res;
|
||||
}
|
||||
|
||||
// ----- hot reload
|
||||
|
||||
/**
|
||||
* 监听文件变化
|
||||
*/
|
||||
async function watch() {
|
||||
// 需要重新加载的文件
|
||||
const refresh = await extract('main.js', 'index.html', 'libs/');
|
||||
const option = {
|
||||
interval: 1000
|
||||
};
|
||||
refresh.forEach(v => {
|
||||
const dir = path.resolve(__dirname, v);
|
||||
fss.watchFile(dir, option, () => {
|
||||
needReload = true;
|
||||
console.log(`change: ${v}`);
|
||||
});
|
||||
});
|
||||
|
||||
// css 热重载
|
||||
const css = await extract('/*.css');
|
||||
css.forEach(v => {
|
||||
const dir = path.resolve(__dirname, v);
|
||||
fss.watchFile(dir, option, () => {
|
||||
hotReloadData += `@@css:${v}`;
|
||||
console.log(`css hot reload: ${v}`);
|
||||
});
|
||||
});
|
||||
|
||||
// 楼层 热重载
|
||||
// 注意这里要逐个监听,并通过创建文件来监听文件改变
|
||||
const floors = await extract('project/floors/*.js');
|
||||
floors.forEach(v => {
|
||||
watchOneFloor(v.slice(15));
|
||||
});
|
||||
|
||||
// 脚本编辑 及 插件 热重载
|
||||
const scripts = await extract('project/functions.js', 'project/plugins.js');
|
||||
scripts.forEach(v => {
|
||||
const dir = path.resolve(__dirname, v);
|
||||
const type = v.split('/').at(-1).slice(0, -3);
|
||||
fss.watchFile(dir, option, () => {
|
||||
hotReloadData += `@@script:${type}`;
|
||||
console.log(`script hot reload: ${type}.js`);
|
||||
});
|
||||
});
|
||||
|
||||
// 数据热重载
|
||||
const datas = (await extract('project/*.js')).filter(
|
||||
v => !v.endsWith('functions.js') && !v.endsWith('plugins.js')
|
||||
);
|
||||
datas.forEach(v => {
|
||||
const dir = path.resolve(__dirname, v);
|
||||
const type = v.split('/').at(-1).slice(0, -3);
|
||||
fss.watchFile(dir, option, () => {
|
||||
hotReloadData += `@@data:${type}`;
|
||||
console.log(`data hot reload: ${type}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否是楼层文件并进行监听
|
||||
* @param {string} url 要测试的路径
|
||||
*/
|
||||
function testWatchFloor(url) {
|
||||
if (/project(\/|\\)floors(\/|\\).*\.js/.test(url)) {
|
||||
const f = url.slice(15);
|
||||
if (!listenedFloors.includes(f.slice(0, -3))) {
|
||||
watchOneFloor(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听一个楼层文件
|
||||
* @param {string} file 要监听的文件
|
||||
*/
|
||||
function watchOneFloor(file) {
|
||||
if (!/.*\.js/.test(file)) return;
|
||||
const f = file.slice(0, -3);
|
||||
listenedFloors.push(file.slice(0, -3));
|
||||
fss.watchFile(`project/floors/${file}`, { interval: 1000 }, () => {
|
||||
const floorId = f;
|
||||
if (hotReloadData.includes(`@@floor:${floorId}`)) return;
|
||||
hotReloadData += `@@floor:${floorId}`;
|
||||
console.log(`floor hot reload: ${floorId}`);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改部分文件后重新加载及热重载
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
function reload(req, res, hot = false) {
|
||||
req.on('data', chunk => {
|
||||
if (chunk.toString() === 'test' && !watched) {
|
||||
watch();
|
||||
watched = true;
|
||||
console.log(`服务器热重载模块已开始服务`);
|
||||
}
|
||||
});
|
||||
|
||||
req.on('end', () => {
|
||||
if (!hot) {
|
||||
res.end(`${needReload}`);
|
||||
needReload = false;
|
||||
} else {
|
||||
res.end(hotReloadData);
|
||||
hotReloadData = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ----- replay debugger
|
||||
|
||||
/**
|
||||
* 录像调试
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
function replay(req, res) {
|
||||
req.on('data', async chunk => {
|
||||
if (chunk.toString() === 'test' && !replayed) {
|
||||
replayed = true;
|
||||
try {
|
||||
await fs.mkdir(path.resolve(__dirname, '_replay'));
|
||||
await fs.mkdir(path.resolve(__dirname, '_replay/status'));
|
||||
await fs.mkdir(path.resolve(__dirname, '_replay/save'));
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
await fs.readFile(
|
||||
path.resolve(__dirname, '_replay/.info'),
|
||||
'utf-8'
|
||||
);
|
||||
} catch {
|
||||
await fs.writeFile(
|
||||
path.resolve(__dirname, '_replay/.info'),
|
||||
`{
|
||||
"cnt": 0
|
||||
}`,
|
||||
'utf-8'
|
||||
);
|
||||
}
|
||||
const data = fss.readFileSync(
|
||||
path.resolve(__dirname, '_replay/.info'),
|
||||
'utf-8'
|
||||
);
|
||||
repStart = Number(JSON.parse(data).cnt);
|
||||
console.log(`服务器录像调试模块已开始服务`);
|
||||
}
|
||||
});
|
||||
|
||||
req.on('end', () => {
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未占用的状态栏位
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function replayCnt() {
|
||||
const data = `{
|
||||
"cnt": ${++repStart}
|
||||
}`;
|
||||
fss.writeFileSync(path.resolve(__dirname, '_replay/.info'), data, 'utf-8');
|
||||
|
||||
return repStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function replayWrite(req, res) {
|
||||
const data = await getPostData(req);
|
||||
const n = await replayCnt();
|
||||
|
||||
if (isNaN(n)) res.end('@error');
|
||||
|
||||
await Promise.all([
|
||||
fs.writeFile(
|
||||
path.resolve(__dirname, '_replay/.info'),
|
||||
`{
|
||||
"cnt": ${n + 1}
|
||||
}`,
|
||||
'utf-8'
|
||||
),
|
||||
fs.writeFile(
|
||||
path.resolve(__dirname, `_replay/status/${n}.rep`),
|
||||
data,
|
||||
'utf-8'
|
||||
)
|
||||
]);
|
||||
|
||||
res.end(n.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 比对录像与本地数据
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function replayCheck(req, res) {
|
||||
const ans = await getPostData(req);
|
||||
const [n, data] = ans.split('@-|-@');
|
||||
|
||||
const local = (
|
||||
await fs.readFile(
|
||||
path.resolve(__dirname, `_replay/status/${n}.rep`),
|
||||
'utf-8'
|
||||
)
|
||||
)
|
||||
.split('@---@')
|
||||
.map(v => JSON.parse(v));
|
||||
const rep = data.split('@---@').map(v => JSON.parse(v));
|
||||
|
||||
if (local.length !== rep.length) return res.end('false');
|
||||
|
||||
const check = (a, b) => {
|
||||
if (a === b) return true;
|
||||
if (typeof a !== typeof b) return false;
|
||||
if (typeof a === 'object' && a !== null) {
|
||||
for (const j in a) {
|
||||
if (j === 'statistics' || j === 'timeout') continue; // 忽略统计信息
|
||||
const aa = a[j];
|
||||
const bb = b[j];
|
||||
if (!check(aa, bb)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
typeof a === 'boolean' ||
|
||||
typeof a === 'number' ||
|
||||
typeof a === 'string' ||
|
||||
typeof a === 'symbol' ||
|
||||
typeof a === 'undefined' ||
|
||||
typeof a === 'bigint' ||
|
||||
a === null
|
||||
) {
|
||||
return a === b;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
for (let i = 0; i < local.length; i++) {
|
||||
const a = local[i];
|
||||
const b = rep[i];
|
||||
if (!check(a, b)) return res.end('false');
|
||||
}
|
||||
|
||||
res.end('true');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地属性
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function replayGet(req, res, dir) {
|
||||
const ans = Number(await getPostData(req));
|
||||
|
||||
const data = await fs.readFile(
|
||||
path.resolve(__dirname, `_replay/${dir}/${ans}.rep`)
|
||||
);
|
||||
res.end(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 录像回放存档
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
||||
*/
|
||||
async function replaySave(req, res) {
|
||||
const data = await getPostData(req);
|
||||
const [cnt, save] = data.split('@-|-@');
|
||||
|
||||
if (isNaN(Number(cnt))) {
|
||||
console.log('Invalid input of save cnt');
|
||||
res.end('@error: 不合法的录像存档信息');
|
||||
}
|
||||
|
||||
await fs.writeFile(
|
||||
path.resolve(__dirname, `_replay/save/${cnt}.rep`),
|
||||
save,
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
res.end('success');
|
||||
}
|
||||
|
||||
// ----- server
|
||||
|
||||
server.on('listening', () => {
|
||||
console.log(`服务已启动,编辑器地址:http://127.0.0.1:${port}/editor.html`);
|
||||
console.log(`游戏地址:http://127.0.0.1:${port}`);
|
||||
});
|
||||
|
||||
// 处理请求
|
||||
server.on('request', async (req, res) => {
|
||||
/** @type {string} */
|
||||
const p = req.url.replace(`/games/${name}`, '').replace('/all/', '/');
|
||||
|
||||
if (req.method === 'GET') {
|
||||
const dir = path
|
||||
.resolve(__dirname, p === '/' ? 'index.html' : p.slice(1))
|
||||
.split('?v=')[0];
|
||||
|
||||
if (await getFile(req, res, dir)) return;
|
||||
|
||||
if (p.startsWith('/__all_floors__.js')) {
|
||||
const all = p.split('&id=')[1].split(',');
|
||||
res.writeHead(200, { 'Content-type': 'text/javascript' });
|
||||
return await getAll(req, res, all, '.js', 'project/floors/', '\n');
|
||||
}
|
||||
|
||||
if (p.startsWith('/__all_animates__')) {
|
||||
const all = p.split('&id=')[1].split(',');
|
||||
return await getAll(
|
||||
req,
|
||||
res,
|
||||
all,
|
||||
'.animate',
|
||||
'project/animates/',
|
||||
'@@@~~~###~~~@@@'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (req.method === 'POST') {
|
||||
if (p === '/listFile') return await readDir(req, res);
|
||||
if (p === '/makeDir') return await mkdir(req, res);
|
||||
if (p === '/readFile') return await readFile(req, res);
|
||||
if (p === '/writeFile') return await writeFile(req, res);
|
||||
if (p === '/deleteFile') return await rm(req, res);
|
||||
if (p === '/moveFile') return await moveFile(req, res);
|
||||
if (p === '/writeMultiFiles') return await writeMultiFiles(req, res);
|
||||
if (p === '/reload') return reload(req, res);
|
||||
if (p === '/hotReload') return reload(req, res, true);
|
||||
if (p === '/replay') return replay(req, res);
|
||||
if (p === '/replayWrite') return await replayWrite(req, res);
|
||||
if (p === '/replayCheck') return await replayCheck(req, res);
|
||||
if (p === '/replayGet') return await replayGet(req, res, 'status');
|
||||
if (p === '/replaySave') return await replaySave(req, res);
|
||||
if (p === '/replayGetSave') return await replayGet(req, res, 'save');
|
||||
}
|
||||
|
||||
res.statusCode = 404;
|
||||
res.end();
|
||||
});
|
243
server.py
Normal file
243
server.py
Normal file
@ -0,0 +1,243 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# HTML5魔塔样板,启动服务Python版
|
||||
# 需要安装Python环境,并 pip install flask 安装Flask库
|
||||
# 运行方式:python server.py 或 python3 server.py
|
||||
|
||||
import sys
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import base64
|
||||
|
||||
isPy3 = sys.version_info > (3, 0)
|
||||
|
||||
def p(s): # s is unicode in py2 and str in py3
|
||||
if isPy3: print(s)
|
||||
else: print(s.decode('utf-8'))
|
||||
p("")
|
||||
|
||||
try:
|
||||
from flask import Flask, request, Response, abort
|
||||
import mimetypes
|
||||
import socket
|
||||
except:
|
||||
p("需要flask才可使用本服务。\n安装方式:%s install flask" % ("pip3" if isPy3 else "pip"))
|
||||
exit(1)
|
||||
|
||||
app = Flask(__name__, static_folder='__static__')
|
||||
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
|
||||
|
||||
@app.after_request
|
||||
def add_header(r):
|
||||
r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
||||
r.headers["Pragma"] = "no-cache"
|
||||
r.headers["Expires"] = "0"
|
||||
r.headers['Cache-Control'] = 'public, max-age=0'
|
||||
return r
|
||||
|
||||
def is_sub(filename):
|
||||
try:
|
||||
return (os.path.realpath(filename) + os.sep).startswith(os.path.realpath(".") + os.sep)
|
||||
except:
|
||||
return True
|
||||
|
||||
def get_mimetype(path):
|
||||
return mimetypes.guess_type(path)[0] or 'application/octet-stream'
|
||||
|
||||
def get_file(path):
|
||||
if not os.path.isfile(path):
|
||||
if path.startswith('_saves/'):
|
||||
return ''
|
||||
abort(404)
|
||||
return None
|
||||
if not is_sub(path):
|
||||
abort(403)
|
||||
with open(path, 'rb') as f:
|
||||
content = f.read() # str in py2 and bytes in py3
|
||||
return content
|
||||
|
||||
@app.route('/', methods=['GET'])
|
||||
def root():
|
||||
return static_file('index.html')
|
||||
|
||||
@app.route('/__all_floors__.js', methods=['GET'])
|
||||
def all_floors():
|
||||
ids = request.args.get('id', '').split(',')
|
||||
if len(ids) == 0:
|
||||
abort(404)
|
||||
return None
|
||||
content = []
|
||||
for id in ids:
|
||||
v = get_file('project/floors/%s.js' % id)
|
||||
if isPy3: v = str(v, encoding = 'utf-8')
|
||||
content.append(v)
|
||||
return Response('\n'.join(content), mimetype = 'text/javascript')
|
||||
|
||||
@app.route('/__all_animates__', methods=['GET'])
|
||||
def all_animates():
|
||||
ids = request.args.get('id', '').split(',')
|
||||
if len(ids) == 0:
|
||||
abort(404)
|
||||
return None
|
||||
content = []
|
||||
for id in ids:
|
||||
animate = 'project/animates/%s.animate' % id
|
||||
if os.path.exists(animate):
|
||||
v = get_file(animate)
|
||||
if isPy3: v = str(v, encoding = 'utf-8')
|
||||
content.append(v)
|
||||
else: content.append('')
|
||||
return '@@@~~~###~~~@@@'.join(content)
|
||||
|
||||
@app.route('/favicon.ico', methods=['GET'])
|
||||
def favicon():
|
||||
return ''
|
||||
|
||||
@app.route('/<path:path>', methods=['GET'])
|
||||
def static_file(path):
|
||||
if os.path.isdir(path):
|
||||
if not path.endswith('/'): path += '/'
|
||||
path += 'index.html'
|
||||
if not os.path.isfile(path):
|
||||
abort(404)
|
||||
return None
|
||||
mimetype = get_mimetype(path)
|
||||
response = Response(get_file(path), mimetype = mimetype)
|
||||
if mimetype.startswith('audio/'): response.headers["Accept-Ranges"] = "bytes"
|
||||
return response
|
||||
|
||||
def process_request():
|
||||
data = request.get_data() # str in py2 and bytes in py3
|
||||
if isPy3: data = str(data, encoding = 'utf-8')
|
||||
params = data.split("&")
|
||||
d = {}
|
||||
for one in params:
|
||||
index = one.find("=")
|
||||
if index >= 0:
|
||||
d[one[:index]] = one[index+1:]
|
||||
return d # str in py2 & py3
|
||||
|
||||
@app.route('/readFile', methods=['POST'])
|
||||
def readFile():
|
||||
data = process_request()
|
||||
tp = data.get('type', 'base64')
|
||||
filename = data.get('name', None)
|
||||
content = get_file(filename)
|
||||
return content if tp == 'utf8' or content is None else base64.b64encode(content)
|
||||
|
||||
@app.route('/writeFile', methods=['POST'])
|
||||
def writeFile():
|
||||
data = process_request()
|
||||
tp = data.get('type', 'base64')
|
||||
filename = data.get('name', None)
|
||||
if not is_sub(filename):
|
||||
abort(403)
|
||||
return
|
||||
value = data.get('value', '')
|
||||
if isPy3: value = value.encode('utf-8')
|
||||
if tp == 'base64': value = base64.b64decode(value)
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(value) # str in py2 and bytes in py3
|
||||
return str(len(value))
|
||||
|
||||
@app.route('/writeMultiFiles', methods=['POST'])
|
||||
def writeMultiFiles():
|
||||
data = process_request()
|
||||
filenames = data.get('name', '').split(';')
|
||||
values = data.get('value', '').split(';')
|
||||
l = 0
|
||||
for i in range(len(filenames)):
|
||||
if i >= len(values):
|
||||
break
|
||||
filename = filenames[i]
|
||||
value = values[i].encode('utf-8') if isPy3 else values[i]
|
||||
value = base64.b64decode(value)
|
||||
if not is_sub(filename):
|
||||
abort(403)
|
||||
return
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(value)
|
||||
l += len(value)
|
||||
return str(l)
|
||||
|
||||
@app.route('/listFile', methods=['POST'])
|
||||
def listFile():
|
||||
data = process_request()
|
||||
filename = data.get('name', None)
|
||||
if filename is None or not os.path.isdir(filename):
|
||||
abort(404)
|
||||
return
|
||||
if not is_sub(filename):
|
||||
abort(403)
|
||||
return
|
||||
files = [f
|
||||
for f in os.listdir(filename)
|
||||
if os.path.isfile(os.path.join(filename, f))]
|
||||
return "[" + ", ".join(['"'+f+'"' for f in files]) + "]"
|
||||
|
||||
@app.route('/makeDir', methods=['POST'])
|
||||
def makeDir():
|
||||
data = process_request()
|
||||
filename = data.get('name', None)
|
||||
if filename is None or not is_sub(filename):
|
||||
abort(403)
|
||||
return
|
||||
if not os.path.exists(filename):
|
||||
os.makedirs(filename)
|
||||
return 'Success'
|
||||
|
||||
@app.route('/moveFile', methods=['POST'])
|
||||
def moveFile():
|
||||
data = process_request()
|
||||
src = data.get('src', None)
|
||||
dest = data.get('dest', None)
|
||||
if src is None or dest is None or not is_sub(src) or not is_sub(dest):
|
||||
abort(403)
|
||||
return
|
||||
if not os.path.exists(src):
|
||||
abort(404)
|
||||
return
|
||||
if src == dest:
|
||||
return 'Success'
|
||||
if os.path.exists(dest):
|
||||
os.remove(dest)
|
||||
os.rename(src, dest)
|
||||
return 'Success'
|
||||
|
||||
@app.route('/deleteFile', methods=['POST'])
|
||||
def deleteFile():
|
||||
data = process_request()
|
||||
name = data.get('name', None)
|
||||
if name is None or not is_sub(name):
|
||||
abort(403)
|
||||
return
|
||||
if os.path.isfile(name):
|
||||
os.remove(name)
|
||||
elif os.path.isdir(name):
|
||||
shutil.rmtree(name)
|
||||
return 'Success'
|
||||
|
||||
@app.route('/games/upload.php', methods=['POST'])
|
||||
def upload():
|
||||
return ''
|
||||
|
||||
def port_used(port):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
result = True
|
||||
try:
|
||||
sock.bind(("0.0.0.0", port))
|
||||
result = False
|
||||
except:
|
||||
pass
|
||||
sock.close()
|
||||
return result
|
||||
|
||||
if __name__ == '__main__':
|
||||
port = 1055
|
||||
while port_used(port):
|
||||
port += 1
|
||||
if port > 1055:
|
||||
p("默认的1055端口已被占用,自动选择%d端口。请注意,不同端口下的存档等信息都是不共用的。\n" % port)
|
||||
p("服务已启动...\n游戏地址:http://127.0.0.1:%d/\n编辑器地址:http://127.0.0.1:%d/editor.html\n" % (port, port))
|
||||
app.run(host = '0.0.0.0', port = port, debug = False)
|
507
styles.css
Normal file
507
styles.css
Normal file
@ -0,0 +1,507 @@
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#gameGroup {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
#mainTips {
|
||||
color: #fff;
|
||||
font-size: 0.8em;
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 370;
|
||||
}
|
||||
|
||||
#musicBtn {
|
||||
position: fixed;
|
||||
bottom: 3px;
|
||||
right: 3px;
|
||||
cursor: pointer;
|
||||
z-index: 400;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#startPanel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
z-index: 300;
|
||||
}
|
||||
|
||||
#startTop {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #000000;
|
||||
z-index: 350;
|
||||
}
|
||||
|
||||
#startTopProgressBar {
|
||||
width: 90%;
|
||||
height: 5%;
|
||||
margin: 0 5%;
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
background-color: #fff;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
#startTopProgress {
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
#startTopLoadTips {
|
||||
color: #fff;
|
||||
font-size: 0.6em;
|
||||
position: absolute;
|
||||
top: 10%;
|
||||
left: 5%;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
#startTopHint {
|
||||
color: #66CCFF;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 5%;
|
||||
z-index: 15;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
#startBackground {
|
||||
position:absolute;
|
||||
top:50%;
|
||||
left:50%;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
transform:translate(-50%,-50%);
|
||||
z-index: 260;
|
||||
}
|
||||
|
||||
#startLogo {
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
z-index: 290;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 8%;
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
font: bold 4em STXingkai;
|
||||
}
|
||||
|
||||
#startTitle {
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
z-index: 280;
|
||||
}
|
||||
|
||||
#startButtonGroup {
|
||||
width: auto;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
font-size: 1.4em;
|
||||
display: none;
|
||||
z-index: 310;
|
||||
bottom: 0;
|
||||
margin-bottom: 5%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 15px 25px;
|
||||
min-width: 20%;
|
||||
/* default value */
|
||||
background-color: #32369F;
|
||||
opacity: 0.85;
|
||||
color: #FFFFFF;
|
||||
border: #FFFFFF 2px solid;
|
||||
caret-color: #FFD700;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
#startButtons {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#levelChooseButtons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.startButton {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
padding: 4px 0;
|
||||
border-color: transparent;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.onChoiceAnimate {
|
||||
animation: onChoice 2s ease-in-out 0s infinite normal none running;
|
||||
}
|
||||
|
||||
#floorMsgGroup {
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
display: none;
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
z-index: 230;
|
||||
}
|
||||
|
||||
#logoLabel {
|
||||
margin-top: 8%;
|
||||
font: bold 3em STXingkai;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#versionLabel {
|
||||
margin-top: -3%;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#floorNameLabel {
|
||||
margin-top: 30px;
|
||||
font-size: 1.6em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#statusBar {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
background: url(project/materials/ground.png) repeat;
|
||||
z-index: 185;
|
||||
display: none;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 3px;
|
||||
}
|
||||
#statusBar .status{
|
||||
user-select: none;
|
||||
position: relative;
|
||||
display: block;
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
.status img{
|
||||
vertical-align: middle;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
max-height: 1.6em;
|
||||
}
|
||||
#statusBar span{
|
||||
user-select: none;
|
||||
font: bold italic 1.1em Verdana;
|
||||
display: inline;
|
||||
}
|
||||
#statusBar p {
|
||||
user-select: none;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 60%;
|
||||
margin: 0;
|
||||
color: white;
|
||||
font: bold italic 1.1em Verdana;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#toolBar {
|
||||
position: absolute;
|
||||
background: url(project/materials/ground.png) repeat;
|
||||
z-index: 210;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
display: none;
|
||||
padding: 3px;
|
||||
}
|
||||
#toolBar .tools{
|
||||
position: relative;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
p#hard {
|
||||
user-select: none;
|
||||
width: 6em;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
color: red;
|
||||
font: bold normal 1.1em "Arial Black";
|
||||
text-align: center;
|
||||
margin: 0 6px 6px 0;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
span#poison, span#weak, span#curse, span#pickaxe, span#bomb, span#fly {
|
||||
user-select: none;
|
||||
font-style: normal;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
p#name {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.gameCanvas {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
|
||||
#gif {
|
||||
z-index: 20;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#gif2 {
|
||||
z-index: 90;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#gameDraw {
|
||||
position: absolute;
|
||||
background: #000000;
|
||||
overflow: hidden;
|
||||
z-index: 185;
|
||||
}
|
||||
|
||||
#bg {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
#event {
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
#hero {
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
#event2 {
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
#fg {
|
||||
z-index: 60;
|
||||
}
|
||||
|
||||
#damage {
|
||||
z-index: 65;
|
||||
}
|
||||
|
||||
#animate {
|
||||
z-index: 70;
|
||||
}
|
||||
|
||||
#curtain {
|
||||
z-index: 125;
|
||||
}
|
||||
|
||||
#ui {
|
||||
z-index: 140;
|
||||
}
|
||||
|
||||
#data {
|
||||
z-index: 170;
|
||||
}
|
||||
|
||||
#inputDiv {
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: rgba(127,127,127,0.6);
|
||||
z-index: 2000
|
||||
}
|
||||
|
||||
#inputDialog {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -55%);
|
||||
background: white;
|
||||
width: 250px;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
#inputMessage {
|
||||
word-wrap: break-word;
|
||||
text-align: left;
|
||||
margin-left: 8%;
|
||||
margin-right: 5%;
|
||||
}
|
||||
|
||||
#inputBox {
|
||||
margin-left: 8%;
|
||||
width: 80%;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px 3px;
|
||||
border: 1px solid;
|
||||
background: #F0F0F0;
|
||||
}
|
||||
|
||||
#inputYes {
|
||||
margin-bottom: 15px;
|
||||
margin-left: 8%;
|
||||
}
|
||||
|
||||
#inputNo {
|
||||
float:right;
|
||||
margin-right: 10%;
|
||||
}
|
||||
|
||||
#_selector, ._uievent_selector {
|
||||
animation: selector 2s ease-in-out 0s infinite normal none running;
|
||||
}
|
||||
|
||||
@-webkit-keyframes selector {
|
||||
0% { opacity: 0.95; }
|
||||
50% { opacity: 0.55; }
|
||||
100% { opacity: 0.95; }
|
||||
}
|
||||
|
||||
@keyframes selector {
|
||||
0% { opacity: 0.95; }
|
||||
50% { opacity: 0.55; }
|
||||
100% { opacity: 0.95; }
|
||||
}
|
||||
|
||||
#next {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
display: none;
|
||||
position: absolute;
|
||||
transform: rotate(45deg);
|
||||
border-bottom-width: 4px;
|
||||
border-bottom-style: solid;
|
||||
border-right-width: 4px;
|
||||
border-right-style: solid;
|
||||
-webkit-animation: next .5s ease-in-out alternate infinite;
|
||||
animation: next .5s ease-in-out alternate infinite;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0.7;
|
||||
z-index: 169;
|
||||
}
|
||||
|
||||
@-webkit-keyframes next {
|
||||
100% {
|
||||
transform: rotate(45deg) translate(-3px, -3px);
|
||||
}
|
||||
}
|
||||
@keyframes next {
|
||||
100% {
|
||||
transform: rotate(45deg) translate(-3px, -3px);
|
||||
}
|
||||
}
|
||||
|
||||
#startImageBackgroundDiv {
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
#startImageDiv {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
background: black;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#startImageLogo {
|
||||
opacity: 0;
|
||||
max-width: 60%;
|
||||
max-height: 60%;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.startImageAnimation {
|
||||
-webkit-animation: startImage 4s ease-in-out 1s alternate 1;
|
||||
animation: startImage 4s ease-in-out 1s alternate 1;
|
||||
}
|
||||
|
||||
@-webkit-keyframes startImage {
|
||||
0% { opacity: 0; }
|
||||
60% { opacity: 1; }
|
||||
100% { opacity: 0; }
|
||||
}
|
||||
|
||||
@keyframes startImage {
|
||||
0% { opacity: 0; }
|
||||
60% { opacity: 1; }
|
||||
100% { opacity: 0; }
|
||||
}
|
||||
|
||||
.startImageDivAnimation {
|
||||
-webkit-animation: startImageDivDisappear 2s ease-in-out 5s alternate 1;
|
||||
animation: startImageDivDisappear 2s ease-in-out 5s alternate 1;
|
||||
}
|
||||
|
||||
@-webkit-keyframes startImageDivDisappear {
|
||||
0% { opacity: 1 }
|
||||
100% { opacity: 0 }
|
||||
}
|
||||
|
||||
@keyframes startImageDivDisappear {
|
||||
0% { opacity: 1 }
|
||||
100% { opacity: 0 }
|
||||
}
|
||||
|
||||
#ui-editor {
|
||||
z-index: 9999;
|
||||
position: absolute;
|
||||
overflow: visible;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Fira Code;
|
||||
src: url(../src/fonts/FiraCode-Regular.ttf);
|
||||
}
|
||||
|
||||
/* 注释下面这三行以开启抗锯齿 */
|
||||
.anti-aliasing {
|
||||
image-rendering: pixelated;
|
||||
}
|
Loading…
Reference in New Issue
Block a user