Files
d1kt/public/tower-defense/td.html

389 lines
13 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=1.0, user-scalable=yes">
<style>
html, body {
margin: 0;
padding: 0;
font-size: 12px;
line-height: 20px;
font-family: Verdana, "Times New Roman", serif;
background: #1A74BA;
}
h1 {
padding: 0;
margin: 0;
line-height: 48px;
font-size: 18px;
font-weight: bold;
font-family: Verdana, "Times New Roman", serif;
letter-spacing: 0.12em;
}
#wrapper {
margin: 0 auto;
max-width: 980px;
}
#td-wrapper {
padding: 8px 24px 24px 24px;
background: #E0F4FC;
}
#td-board {
display: none;
font-size: 16px;
}
#td-board canvas#td-canvas {
position: relative;
background: #fff;
border: solid 1px #cdf;
}
#td-loading {
font-size: 18px;
line-height: 48px;
padding: 60px 0 120px 0;
font-style: italic;
}
</style>
</head>
<body id="tower-defense">
<div id="wrapper">
<div id="td-wrapper">
<div id="td-loading">加载中...</div>
<div id="td-board">
<canvas id="td-canvas">抱歉,您的浏览器不支持 HTML 5 Canvas 标签,请使用 Chrome / Edge 等现代浏览器打开。</canvas>
</div>
</div>
</div>
<script src="td-pkg-zh.js"></script>
<script>
window.onload = function () {
console.log('[init] window.onload called');
// 原站点的初始化方式_TD.init('td-board', true)
_TD.init('td-board', true);
document.getElementById('td-loading').style.display = 'none';
document.getElementById('td-board').style.display = 'block';
};
// --- Monster save/load enhancement ---
(function() {
setTimeout(function() {
if (typeof TD === 'undefined') {
console.error('[MonsterSaveLoad] TD is still undefined after 500ms');
return;
}
console.log('[MonsterSaveLoad] Applying monster save/load enhancement...');
window.__TD_getState = function () {
try {
console.log('[__TD_getState] ===== START SAVING STATE =====');
var scene = TD.stage && TD.stage.current_act && TD.stage.current_act.current_scene;
var map = scene && scene.map;
var buildings = [];
if (map && map.buildings && map.buildings.length) {
for (var i = 0; i < map.buildings.length; i++) {
var b = map.buildings[i];
if (!b || !b.grid) continue;
buildings.push({
type: b.type,
mx: b.grid.mx,
my: b.grid.my,
level: b.level,
money: b.money,
killed: b.killed,
damage: b.damage,
range: b.range,
speed: b.speed,
life: b.life,
shield: b.shield,
upgrade_records: b._upgrade_records || null
});
}
}
var monsters_data = [];
if (map && map.monsters && map.monsters.length) {
console.log('[__TD_getState] Found ' + map.monsters.length + ' monsters');
for (var i = 0; i < map.monsters.length; i++) {
var m = map.monsters[i];
if (!m || !m.is_valid || !m.grid) continue;
var monster_data = {
idx: m.idx,
difficulty: m.difficulty,
life: m.life,
life0: m.life0,
shield: m.shield,
speed: m.speed,
damage: m.damage,
money: m.money,
mx: m.grid.mx,
my: m.grid.my,
cx: m.cx,
cy: m.cy,
r: m.r,
color: m.color,
toward: m.toward,
way: m.way || [],
next_grid_mx: m.next_grid ? m.next_grid.mx : null,
next_grid_my: m.next_grid ? m.next_grid.my : null,
_dx: m._dx || 0,
_dy: m._dy || 0,
step_level: m.step_level,
render_level: m.render_level,
is_paused: m.is_paused,
is_blocked: m.is_blocked
};
monsters_data.push(monster_data);
}
console.log('[__TD_getState] Gathered ' + monsters_data.length + ' valid monsters data:', monsters_data);
}
var state = {
money: TD.money,
life: TD.life,
score: TD.score,
difficulty: TD.difficulty,
wave_damage: TD.wave_damage,
wave: (scene && scene.wave) || 0,
map_step_level: (map && map.step_level) || 1,
map_render_level: (map && map.render_level) || 2,
buildings: buildings,
monsters: monsters_data
};
console.log('[__TD_getState] Returning state:', state);
return state;
} catch (e) {
console.error('[__TD_getState] error', e);
return null;
}
};
window.__TD_loadState = function (s) {
try {
console.log('[__TD_loadState] ===== START LOADING STATE =====', s);
if (!s) return;
var scene = TD.stage && TD.stage.current_act && TD.stage.current_act.current_scene;
var map = scene && scene.map;
if (!map) return;
// clear existing
for (var i = 0; i < map.grids.length; i++) {
var g = map.grids[i];
if (g && g.building) g.removeBuilding();
}
if (map.monsters && map.monsters.length) {
for (var mi = 0; mi < map.monsters.length; mi++) {
if (map.monsters[mi]) {
map.monsters[mi].pause();
map.monsters[mi].del();
}
}
map.monsters = [];
}
// restore buildings
if (s.buildings) {
for (var j = 0; j < s.buildings.length; j++) {
var bi = s.buildings[j];
var grid = map.getGrid(bi.mx, bi.my);
if (grid) {
grid.addBuilding(bi.type);
var b = grid.building;
if (b) {
var hasSavedBuildingAttrs = (
typeof bi.damage !== 'undefined' ||
typeof bi.range !== 'undefined' ||
typeof bi.speed !== 'undefined' ||
typeof bi.life !== 'undefined' ||
typeof bi.shield !== 'undefined'
);
if (!hasSavedBuildingAttrs && typeof bi.level !== 'undefined' && bi.level > 0 && typeof b.upgrade === 'function') {
for (var ul = 0; ul < bi.level; ul++) b.upgrade();
} else if (typeof bi.level !== 'undefined') {
b.level = bi.level;
}
if (typeof bi.damage !== 'undefined') b.damage = bi.damage;
if (typeof bi.range !== 'undefined') b.range = bi.range;
if (typeof bi.speed !== 'undefined') b.speed = bi.speed;
if (typeof bi.life !== 'undefined') b.life = bi.life;
if (typeof bi.shield !== 'undefined') b.shield = bi.shield;
if (typeof bi.money !== 'undefined') b.money = bi.money;
if (typeof bi.killed !== 'undefined') b.killed = bi.killed;
if (bi.upgrade_records) {
b._upgrade_records = {};
for (var rk in bi.upgrade_records) {
if (Object.prototype.hasOwnProperty.call(bi.upgrade_records, rk)) {
b._upgrade_records[rk] = bi.upgrade_records[rk];
}
}
}
b.range_px = b.range * TD.grid_size;
b.updateBtnDesc && b.updateBtnDesc();
}
}
}
}
// restore monsters
if (s.monsters) {
for (var mj = 0; mj < s.monsters.length; mj++) {
var md = s.monsters[mj];
if (md.life <= 0) continue;
var m_grid = map.getGrid(md.mx, md.my);
if (!m_grid || m_grid === map.exit) continue;
var monster = new TD.Monster(null, {
idx: md.idx,
difficulty: md.difficulty,
step_level: md.step_level,
render_level: md.render_level
});
monster.life = md.life;
monster.life0 = md.life0;
monster.shield = md.shield;
monster.speed = md.speed;
monster.damage = md.damage;
monster.money = md.money;
monster.r = md.r;
monster.color = md.color;
monster.toward = md.toward;
monster._dx = md._dx;
monster._dy = md._dy;
monster.beAddToGrid(m_grid);
monster.cx = md.cx;
monster.cy = md.cy;
monster.caculatePos();
if (md.next_grid_mx !== null && md.next_grid_my !== null) {
monster.next_grid = map.getGrid(md.next_grid_mx, md.next_grid_my);
}
monster.way = md.way || [];
m_grid.scene.addElement(monster, monster.step_level, monster.render_level);
map.monsters.push(monster);
if (!monster.is_paused) monster.start();
}
}
if (typeof s.money !== 'undefined') TD.money = s.money;
if (typeof s.life !== 'undefined') TD.life = s.life;
if (typeof s.score !== 'undefined') TD.score = s.score;
if (typeof s.difficulty !== 'undefined') TD.difficulty = s.difficulty;
if (typeof s.wave_damage !== 'undefined') TD.wave_damage = s.wave_damage;
if (typeof s.wave !== 'undefined' && scene) {
scene.wave = s.wave;
// 补偿逻辑:如果难度系数过低,根据波数自动修正
var min_difficulty = Math.pow(1.05, scene.wave - 1);
if (TD.difficulty < min_difficulty) {
TD.difficulty = min_difficulty;
}
}
if (typeof s.map_step_level !== 'undefined' && map) map.step_level = s.map_step_level;
if (typeof s.map_render_level !== 'undefined' && map) map.render_level = s.map_render_level;
console.log('[__TD_loadState] Load completed');
} catch (e) {
console.error('[__TD_loadState] error', e);
}
};
console.log('[MonsterSaveLoad] Enhancement applied successfully!');
}, 500);
})();
// Bridge: respond to parent requests for game state (debug-friendly)
window.addEventListener('message', function (e) {
try {
console.debug('td.html received postMessage', e.origin, e.data);
if (!e.data || !e.data.type) return;
// only accept same-origin or allow if parent is our host during dev
if (e.origin !== window.location.origin && !e.origin.startsWith('http://localhost')) {
console.debug('Ignoring postMessage from', e.origin);
return;
}
if (e.data.type === 'tower-defense:request-state') {
// Try several possible getters
var state = null;
try {
if (typeof window.__TD_getState === 'function') {
console.log('[request-state] Using window.__TD_getState()');
state = window.__TD_getState();
console.log('[request-state] State from __TD_getState:', state);
} else {
console.log('[request-state] No TD getter available');
}
} catch (err) {
console.error('state getter threw', err);
}
e.source.postMessage({ type: 'tower-defense:state', state: state }, e.origin);
console.debug('Replied with tower-defense:state', state);
} else if (e.data.type === 'tower-defense:load') {
// Forward load to any exposed loader
try {
if (typeof window.__TD_loadState === 'function') {
window.__TD_loadState(e.data.state);
console.debug('Invoked __TD_loadState');
} else {
console.debug('No load API available');
}
} catch (err) {
console.error('load handling error', err);
}
}
} catch (err) {
console.error('postMessage bridge error', err);
}
}, false);
// --- Shortcut keys enhancement ---
window.addEventListener('keydown', function (e) {
if (typeof TD === 'undefined' || !TD.stage || !TD.stage.current_act || !TD.stage.current_act.current_scene) return;
var map = TD.stage.current_act.current_scene.map;
if (!map) return;
var key = e.key.toLowerCase();
if (key === 's') {
// S: Sell selected building
if (map.selected_building) {
console.log('[Shortcut] Selling building:', map.selected_building.id);
map.selected_building.tryToSell();
}
} else if (key === 'w') {
// W: Select Wall (路障)
if (!map.selected_building) {
console.log('[Shortcut] Pre-building Wall');
map.preBuild('wall');
}
} else if (key === 'e') {
// E: Select Laser Gun (激光枪)
if (!map.selected_building) {
console.log('[Shortcut] Pre-building Laser Gun');
map.preBuild('laser_gun');
}
} else if (key === 'r') {
// R: Select Heavy Machine Gun (重机枪)
if (!map.selected_building) {
console.log('[Shortcut] Pre-building HMG');
map.preBuild('HMG');
}
}
});
</script>
</body>
</html>