mirror of
https://gitlab.com/skysthelimit.dev/selenite.git
synced 2025-06-15 18:12:08 -05:00
1383 lines
42 KiB
JavaScript
1383 lines
42 KiB
JavaScript
/* Editor.js */
|
|
// Contains all the functions needed to load and use the editor
|
|
// Gives a UI for selecting Things and their options
|
|
// When done, it makes map based off what's still placed
|
|
|
|
/* Stuff to do:
|
|
---------------
|
|
* Add platforms back in (and a few other missing Things)
|
|
* Give options for different areas
|
|
|
|
*/
|
|
|
|
|
|
function loadEditor(noreset) {
|
|
// Make sure there aren't any other instances of this
|
|
editorClose();
|
|
|
|
// If you want to clear the current map
|
|
if(!noreset) {
|
|
window.canedit = true;
|
|
setMap(["Special", "Blank"]);
|
|
window.canedit = false;
|
|
}
|
|
|
|
// Set the library and controls
|
|
setEditorLibrary();
|
|
setEditorHTML();
|
|
setEditorControls();
|
|
setEditorTriggers();
|
|
setEditorLocalRetrieval();
|
|
|
|
// Visually update
|
|
classAdd(body, "editor");
|
|
classAdd(editor.sidebar, "expanded");
|
|
TimeHandler.addEvent(classRemove, 35, editor.sidebar, "expanded");
|
|
|
|
// Let the rest of the game know what's going on
|
|
map.shifting = false;
|
|
window.editing = true;
|
|
}
|
|
|
|
// To do: Merge this into the main library,
|
|
// and make Things.js use it for constructors
|
|
function setEditorLibrary() {
|
|
// The editor contains the placeable solids and characters
|
|
window.editor = {
|
|
xloc: 0,
|
|
yloc: 0,
|
|
playing: false,
|
|
canplace: true,
|
|
offset: { x: unitsizet2 }, // max is set upon running, if actually needed
|
|
settings: {
|
|
night: false,
|
|
setting: "Overworld",
|
|
alt: false
|
|
},
|
|
defaults: {
|
|
width: 8,
|
|
height: 8,
|
|
widthoff: 0,
|
|
heightoff: 0,
|
|
minimum: 1,
|
|
followerUpdate: editorFollowerUpdateStandard,
|
|
prefunc: pushPreThing,
|
|
outerok: true
|
|
},
|
|
placed: [],
|
|
characters: {
|
|
Goomba: {},
|
|
Koopa: {
|
|
height: 12,
|
|
arguments: {
|
|
smart: Boolean,
|
|
movement: ["moveSimple", "moveJumping", "moveFloating"]
|
|
},
|
|
followerUpdate: function(reference, pairs) {
|
|
var smart = pairs.smart == "True",
|
|
fname = pairs.movement,
|
|
func = fname == "moveJumping";
|
|
if(fname == "moveFloating") func = [8,72];
|
|
return [smart, func];
|
|
},
|
|
onadds: { nocollide: false }
|
|
},
|
|
Beetle: {
|
|
width: 8.5,
|
|
height: 8.5
|
|
},
|
|
HammerBro: { height: 12 },
|
|
CheepCheep: {
|
|
arguments: {
|
|
smart: Boolean
|
|
},
|
|
attributes: {
|
|
nofall: true
|
|
}
|
|
},
|
|
Lakitu: { height: 12 },
|
|
Podoboo: { width: 7 },
|
|
Blooper: {
|
|
height: 12,
|
|
onadds: {
|
|
nofall: true
|
|
}
|
|
},
|
|
Bowser: {
|
|
width: 16,
|
|
height: 16
|
|
}
|
|
},
|
|
solids: {
|
|
Floor: {
|
|
arguments: { width: 8 },
|
|
mydefaults: { width: 8 },
|
|
prefunc_custom: function(prestatement, placer, reference, args) {
|
|
var output = "Floor, " + prestatement.xloc + ", " + (prestatement.yloc);
|
|
if(args[1]) output += ", " + args[1];
|
|
return output;
|
|
}
|
|
},
|
|
Brick: {
|
|
arguments: {
|
|
contents: ["false", "Coins", "Star"]
|
|
},
|
|
followerUpdate: function(reference, pairs) {
|
|
var output = [],
|
|
content = pairs.contents;
|
|
output.push(window[pairs.contents]);
|
|
|
|
return output;
|
|
},
|
|
prefunc_custom: function(prestatement, placer, reference, args) {
|
|
var output = "Brick, ";
|
|
output += prestatement.xloc + ", " + (prestatement.yloc) + ", ";
|
|
output += placer.contents[0].name;
|
|
return output;
|
|
}
|
|
},
|
|
Block: {
|
|
arguments: {
|
|
contents: ["Coin", "Mushroom", "Star", "1Up Mushroom"],
|
|
hidden: Boolean
|
|
},
|
|
followerUpdate: function(reference, pairs) {
|
|
var output = [],
|
|
content = pairs.contents;
|
|
if(content == "1Up Mushroom") output.push([Mushroom, 1]);
|
|
else output.push(window[pairs.contents]);
|
|
|
|
if(pairs.hidden == "True") {
|
|
TimeHandler.addEvent(function() { editor.follower.hidden = true; });
|
|
output.push(1);
|
|
}
|
|
return output;
|
|
},
|
|
prefunc_custom: function(prestatement, placer, reference, args) {
|
|
var output = "Block, ",
|
|
contents = placer.contents,
|
|
contained = contents[0].name;
|
|
output += prestatement.xloc + ", " + prestatement.yloc;
|
|
|
|
// If it's got unusal contents, mark them
|
|
if(contained != "Coin") {
|
|
// Contents are generally just the function name (Coins by default), with 1Up and Death mushrooms being the exception
|
|
if(contained == "Mushroom" && contents[1]) {
|
|
output += ", [Mushroom, " + String(contents[1]) + "]";
|
|
}
|
|
else output += ", " + contained;
|
|
// Hidden is simply a bool
|
|
if(placer.hidden) output += ", true";
|
|
}
|
|
// Otherwise only add more if it's hidden
|
|
else if(placer.hidden) output += ", false, true";
|
|
|
|
return output;
|
|
}
|
|
},
|
|
Cannon: {
|
|
arguments: { height: 8 },
|
|
sprite_source: "top"
|
|
},
|
|
Pipe: {
|
|
width: 16,
|
|
prefunc: pushPrePipe,
|
|
prefunc_solo: true,
|
|
arguments: {
|
|
height: 8,
|
|
Pirhana: Boolean
|
|
},
|
|
followerUpdate: function(reference, pairs) {
|
|
var output = [];
|
|
output.push(Number(pairs.height));
|
|
output.push(Boolean(pairs.Pirhana));
|
|
return output;
|
|
},
|
|
sprite_source: "top"
|
|
},
|
|
Stone: {
|
|
arguments: {
|
|
width: 8,
|
|
height: 8
|
|
},
|
|
prefunc_custom: function(prestatement, placer, reference, args) {
|
|
var output = "Stone, " + prestatement.xloc + ", " + (prestatement.yloc);
|
|
output += ", " + args[1] + ", " + args[2];
|
|
return output;
|
|
}
|
|
},
|
|
Coral: {
|
|
arguments: { height: 8 }
|
|
},
|
|
CastleBlock: {
|
|
arguments: {
|
|
fireballs: 2,
|
|
direction: ["CW", "CCW"],
|
|
hidden: Boolean
|
|
},
|
|
followerUpdate: function(reference, pairs) {
|
|
var length = Number(pairs.fireballs),
|
|
dt = pairs.direction == "CW",
|
|
hidden = pairs.hidden == "True";
|
|
return [[length, dt], hidden];
|
|
}
|
|
},
|
|
// Disabled because of super glitches, but I really want to put it back in!!
|
|
/*Platform: {
|
|
height: 4,
|
|
arguments: {
|
|
width: 2,
|
|
movement: ["false", "Falling", "Floating", "Sliding", "Transport"]
|
|
},
|
|
mydefaults: { width: 4 },
|
|
previewsize: true,
|
|
followerUpdate: function(reference, pairs) {
|
|
var output = [],
|
|
movement = pairs.movement;
|
|
output.push(pairs.width);
|
|
switch(movement) {
|
|
case "Falling": output.push(moveFalling); break;
|
|
case "Floating": output.push(moveFloating); break;
|
|
case "Sliding": output.push(moveSliding); break;
|
|
case "Transport": output.push(collideTransport); break;
|
|
}
|
|
return output;
|
|
},
|
|
prefunc_custom: function(prestatement, placer, reference, args) {
|
|
var output = "Platform, " + prestatement.xloc + ", " + (prestatement.yloc),
|
|
movement = args[2];
|
|
switch(movement) {
|
|
case moveFalling: output += ", moveFalling"; break;
|
|
case moveFloating: output += ", [moveFloating, 8, 72]"; break;
|
|
case moveSliding:
|
|
var xloc = prestatement.xloc || 0;
|
|
output += ", [moveSliding";
|
|
output += ", " + (xloc - 24);
|
|
output += ", " + (xloc + 24);
|
|
output += "]";
|
|
break;
|
|
case collideTransport:
|
|
output += ", collideTransport";
|
|
break;
|
|
}
|
|
return output;
|
|
}
|
|
},*/
|
|
Springboard: {
|
|
height: 14.5,
|
|
heightoff: 1.5
|
|
}
|
|
},
|
|
scenery: {
|
|
Bush1: {width: 16},
|
|
Bush2: {width: 24},
|
|
Bush3: {width: 32},
|
|
Cloud1: {width: 16, height: 12},
|
|
Cloud2: {width: 24, height: 12},
|
|
Cloud3: {width: 32, height: 12},
|
|
HillSmall: {width: 24, height: 9.5, heightoff: -1.5},
|
|
HillLarge: {width: 40, height: 17.5, heightoff: -1.5},
|
|
PlantSmall: {width: 7, height: 15, heightoff: 1},
|
|
PlantLarge: {height: 23, heightoff: 1},
|
|
Fence: {},
|
|
Water: {
|
|
width: 4,
|
|
height: 4,
|
|
prefunc: fillPreWater,
|
|
prefunc_solo: true,
|
|
prefunc_custom: function(prestatement, placer, reference, args) {
|
|
return prestatement.xloc + ", " + (prestatement.yloc)/* + ", " + args[0]*/;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Unfilled required properties are placed here
|
|
var load_paths = {},
|
|
defaults = editor.defaults,
|
|
group, me, locj, i, j;
|
|
// For each group in editor...
|
|
for(i in editor) {
|
|
group = editor[i];
|
|
// For each thing in that group...
|
|
for(j in editor[i]) {
|
|
me = group[j];
|
|
// Proliferate the defaults that don't exist
|
|
proliferate(me, editor.defaults, true);
|
|
}
|
|
}
|
|
|
|
// Note that everything in scenery is actually pushPreScenery(name, ...)
|
|
group = editor.scenery;
|
|
for(i in group) {
|
|
me = group[i];
|
|
// These are the secondary defaults
|
|
proliferate(me, {
|
|
createfunc: function(me) { return ThingCreate(Sprite, me.spritename); },
|
|
spritename: i,
|
|
prefunc_custom: function(prestatement, placer, reference, args) {
|
|
return "'" + reference.spritename + "', " + prestatement.xloc + ", " + (prestatement.yloc - reference.height);
|
|
}
|
|
}, true);
|
|
// These must happen
|
|
if(me.prefunc == pushPreThing) me.prefunc = pushPreScenery;
|
|
}
|
|
}
|
|
|
|
/* Initial HTML setup
|
|
*/
|
|
function setEditorHTML() {
|
|
createEditorGuideLines();
|
|
createEditorSidebar();
|
|
createEditorBottomBar();
|
|
createEditorScrollers();
|
|
|
|
// Set the bottom bar initially
|
|
editor.sectionselect.onchange();
|
|
}
|
|
|
|
// The sidebar contains the main options for placing thing
|
|
function createEditorSidebar() {
|
|
var optionNames = ["Solids", "Characters", "Scenery", "Settings"],
|
|
// The main elements
|
|
sidebar = editor.sidebar = createElement("div", {
|
|
id: "sidebar"
|
|
}),
|
|
category = editor.category = createElement("div", {
|
|
id: "category",
|
|
className: "group first"
|
|
}),
|
|
sectionselect = editor.sectionselect = createElement("select", {
|
|
id: "sectionselect",
|
|
className: "options big",
|
|
onchange: editorSelectSection
|
|
}),
|
|
options = editor.options = createElement("div", {
|
|
id: "options",
|
|
className: "options big"
|
|
}),
|
|
i;
|
|
|
|
// Dat element structure
|
|
sidebar.appendChild(category);
|
|
category.appendChild(sectionselect);
|
|
for(i in optionNames) {
|
|
sectionselect.appendChild(createElement("option", {
|
|
innerText: optionNames[i]
|
|
}));
|
|
}
|
|
sidebar.appendChild(options);
|
|
|
|
// With it initially set, add the sidebar
|
|
body.appendChild(window.sidebar = sidebar);
|
|
}
|
|
|
|
// Lets the user choose which Thing to place
|
|
function createEditorBottomBar() {
|
|
var bar = editor.bottombar = createElement("div", {
|
|
id: "bottombar",
|
|
things: {}
|
|
});
|
|
|
|
sidebar.appendChild(bar);
|
|
}
|
|
|
|
|
|
function createEditorScrollers() {
|
|
var names = ["right", "left"],
|
|
scrollers = {},
|
|
name, i, parent, div, top;
|
|
|
|
// Set the parent #scrollers to hold them
|
|
parent = createElement("div", {
|
|
id: "scrollers",
|
|
style: {
|
|
zIndex: 7,
|
|
width: (innerWidth - 32) + "px"
|
|
}
|
|
});
|
|
|
|
// Create the two scrollers
|
|
settings = {
|
|
className: "scroller",
|
|
style: {
|
|
zIndex: 7,
|
|
marginTop: innerHeight / 2 + "px"
|
|
},
|
|
onmouseover: editorFollowerHide,
|
|
onmouseout: editorFollowerShow,
|
|
onmousedown: editorScrollingStart,
|
|
onmouseup: editorScrollingStop
|
|
};
|
|
|
|
// Create each div
|
|
for(i = names.length - 1; i >= 0; --i) {
|
|
name = names[i];
|
|
div = scrollers[names[i]] = createElement("div", settings);
|
|
parent.appendChild(div);
|
|
}
|
|
// The left one should start hidden
|
|
proliferate(scrollers["left"], {
|
|
id: "left",
|
|
className: "scroller flipped off",
|
|
dx: -7
|
|
});
|
|
// The right one is at the right of the screen
|
|
proliferate(scrollers["right"], {
|
|
id: "right",
|
|
style: { right: "21px" },
|
|
dx: 7
|
|
});
|
|
|
|
editor.scrollers = scrollers;
|
|
|
|
body.appendChild(parent);
|
|
}
|
|
|
|
function editorFollowerHide() {
|
|
var follower = editor.follower;
|
|
follower.hiddenOld = follower.hidden;
|
|
follower.hidden = true;
|
|
}
|
|
function editorFollowerShow() {
|
|
var follower = editor.follower;
|
|
follower.hidden = follower.hiddenOld;
|
|
}
|
|
|
|
function editorScrollingStart(event) {
|
|
var scroller = event.target,
|
|
dx = scroller.dx;
|
|
editorPreventClicks();
|
|
editor.scrolling = TimeHandler.addEventInterval(editorScrolling, 1, Infinity, -dx);
|
|
classRemove(editor.scrollers["left"], "off");
|
|
}
|
|
function editorScrollingStop() {
|
|
TimeHandler.addEvent(editorClickOff, 3);
|
|
TimeHandler.clearEvent(editor.scrolling);
|
|
}
|
|
function editorScrolling(dx) {
|
|
scrollEditor(dx);
|
|
if(editor.xloc >= 0) {
|
|
scrollEditor(-editor.xloc);
|
|
editorScrollingStop();
|
|
classAdd(editor.scrollers["left"], "off");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
// Guidelines display helpful boundaries
|
|
function createEditorGuideLines() {
|
|
var lines = {
|
|
floor: 0,
|
|
ceiling: ceillev,
|
|
jumplev1: jumplev1,
|
|
jumplev2: jumplev2
|
|
},
|
|
left = 16 * unitsize + "px",
|
|
floor = map.floor,
|
|
i, parent, line;
|
|
|
|
// The parent holds them and provides the marginLeft
|
|
window.maplines = parent = document.createElement("div");
|
|
parent.style.marginLeft = left;
|
|
parent.id = "maplines";
|
|
|
|
// Create each line and put it in the parent
|
|
for(i in lines) {
|
|
line = createElement("div", {
|
|
innerText: i,
|
|
className: "mapline",
|
|
id: i + "_line",
|
|
style: {
|
|
marginTop: (floor - lines[i]) * unitsize + "px",
|
|
marginLeft: "-" + left,
|
|
paddingLeft: left
|
|
}
|
|
});
|
|
parent.appendChild(line);
|
|
}
|
|
body.appendChild(parent);
|
|
}
|
|
|
|
// The controls supply typical ops like undo and save
|
|
function setEditorControls(names) {
|
|
names = names || ["load", "save", "reset", "undo"/*, "erase"*/];
|
|
var previous = document.getElementById("controls"),
|
|
container = createElement("div", {id: "controls"}),
|
|
controls = editor.controls = {container: container},
|
|
name, div, i;
|
|
|
|
// Clear anything previously existing
|
|
if(previous) previous.innerHTML = "";
|
|
|
|
// For each name, add a div
|
|
for(i in names) {
|
|
name = names[i];
|
|
div = createElement("div", {
|
|
id: name,
|
|
alt: name,
|
|
className: "control",
|
|
style: { backgroundImage: "url(Theme/" + name + ".gif)" },
|
|
innerHTML: "<div class='controltext'>" + name + "</div>",
|
|
onclick: editorClickControl
|
|
});
|
|
|
|
container.appendChild(div);
|
|
controls[name] = div;
|
|
}
|
|
|
|
sidebar.appendChild(container);
|
|
}
|
|
|
|
// What happens on mouse down/click/etc
|
|
function setEditorTriggers() {
|
|
// Everything that allows mouse triggers
|
|
var activators = [maplines, canvas],
|
|
me, i;
|
|
for(i = activators.length - 1; i >= 0; --i) {
|
|
me = activators[i];
|
|
me.onclick = editorMouseClick;
|
|
}
|
|
|
|
// Make sure the follower's position is updated!
|
|
document.onmousemove = editorFollowerFollowsCursor;
|
|
}
|
|
|
|
// Place a new thing at the editor's location
|
|
function editorMouseClick(event) {
|
|
if(!window.editing || editor.clicking) return;
|
|
editorPreventClicks();
|
|
|
|
// If erasing, do that instead
|
|
if(editor.erasing) return editorPlaceEraser(event);
|
|
|
|
// Don't do anything if you're in settings, or just clicked a control
|
|
if(editor.in_settings || !editor.canplace) return;
|
|
|
|
var section_name = editor.section_name,
|
|
current_section = window[section_name],
|
|
thing_name = editor.current_selected,
|
|
follower_old = editor.follower;
|
|
|
|
// Record this past follower in editor.placed
|
|
editor.placed.push(follower_old);
|
|
|
|
// To visualize, simply unattach the follower from the editor and make a new one
|
|
editor.follower = false;
|
|
editorSetCurrentThingFromName(null, true);
|
|
// (when paused, this doesn't happen otherwise)
|
|
if(paused) refillCanvas();
|
|
|
|
// No more follower manipulation is needed, because each Thing stores its own arguments
|
|
// Enabling .was_follower lets the eventual save function know this is a key Thing
|
|
follower_old.was_follower = true;
|
|
delete follower_old.onclick;
|
|
// If it's a live run-though, enable velocity & movement stuff
|
|
if(editor.playing) {
|
|
thingRetrieveVelocity(follower_old);
|
|
proliferate(follower_old, follower_old.reference.attributes);
|
|
}
|
|
}
|
|
|
|
// Selects solids or characters or etc.
|
|
function editorSelectSection() {
|
|
var selected = (this || editor.sectionselect).value.toLowerCase();
|
|
// Clear & load the bottom bar
|
|
// If it's settings, do something
|
|
if(editor.in_settings = selected == "settings") {
|
|
editorSetSection(selected, true);
|
|
editorSetSectionSettings();
|
|
}
|
|
else editorSetSection(selected);
|
|
}
|
|
function editorSetSection(name, nothing) {
|
|
var section = editor.section = editor[name],
|
|
bottombar = editor.bottombar,
|
|
num_kids = 0,
|
|
canv_sel, canv,
|
|
first, name;
|
|
editor.section_name = name;
|
|
|
|
// Clear and reset the bottom bar
|
|
bottombar.innerHTML = "";
|
|
if(!nothing) {
|
|
for(name in section) {
|
|
++num_kids;
|
|
canv = editorAddBottomPreview(bottombar, name, section[name]);
|
|
if(!canv_sel) // This makes it grab the first canvas (comment to get the last)
|
|
canv_sel = canv;
|
|
}
|
|
}
|
|
// Only show the bottom bar if there weren't any settings
|
|
if(num_kids) {
|
|
bottombar.style.visibility = "visible";
|
|
editorSetCurrentThingFromCanvas(canv_sel);
|
|
}
|
|
else bottombar.style.visibility = "hidden";
|
|
}
|
|
// Adds an equivalent object to the bottom bar
|
|
function editorAddBottomPreview(bottombar, name, ref) {
|
|
// Create a canvas based off name & ref
|
|
var width = ref.width,
|
|
height = ref.height,
|
|
thingfunc = window[name],
|
|
// The Thing is used for image drawing
|
|
// If the name doesn't exist as a member of window, it's a Scenery sprite
|
|
thing = thingfunc ? ThingCreate(thingfunc, ref.previewargs) : new Thing(Sprite, name),
|
|
// The holder holds the canvas for positioning reasons
|
|
holder = createElement("div", {
|
|
width: width * unitsize + "px",
|
|
height: height * unitsize + "px",
|
|
name: name,
|
|
className: "holder " + name,
|
|
onclick: editorSetCurrentThing
|
|
}),
|
|
maxWidth = { maxWidth: "100%" },
|
|
maxHeight = { maxHeight: "100%" },
|
|
canvas = proliferate(getCanvas(width * unitsizet2, height * unitsizet2), {
|
|
name: name,
|
|
reference: ref,
|
|
style: { marginLeft: -roundDigit(width / 2, scale) + "px" },
|
|
onclick: editorSetCurrentThing
|
|
}),
|
|
things = bottombar.things,
|
|
sizewidth = width * unitsizet2,
|
|
sizeheight = height * unitsizet2,
|
|
context = canvas.getContext("2d"),
|
|
csource;
|
|
|
|
// For superior sharpness
|
|
canvasDisableSmoothing(canvas);
|
|
|
|
// Update it visually
|
|
editor.bottombar.things[name] = canvas.thing = thing;
|
|
addClass(thing, "editor"); // Ones that need to know this is different get that here
|
|
|
|
// Know where to take from (multiple sprites need to be specified)
|
|
csource = thing.canvas;
|
|
if(thing.canvases) csource = thing.canvases[ref.sprite_source || "middle"].canvas;
|
|
|
|
// If there's a previewsize, pattern it on the canvas
|
|
if(ref.previewsize) {
|
|
context.fillStyle = context.createPattern(csource, "repeat");
|
|
context.fillRect(0, 0, sizewidth, sizeheight);
|
|
}
|
|
// Otherwise just draw it normally...
|
|
else {
|
|
context.drawImage(csource, 0, 0, sizewidth, sizeheight);
|
|
}
|
|
|
|
// Add the canvas to the holder, which is added to bottom bar
|
|
holder.appendChild(holder.canvas = canvas);
|
|
bottombar.appendChild(holder);
|
|
bottombar[name] = holder;
|
|
|
|
// Return the canvas (the last one will be set as the current)
|
|
return canvas;
|
|
}
|
|
|
|
// Displays the editor settings instead of Thing arguments
|
|
function editorSetSectionSettings() {
|
|
var settings = editor.settings,
|
|
html = "<table>",
|
|
rows;
|
|
|
|
html += "<h3 class='title'>Settings</h3>";
|
|
|
|
// Add the options, some of which are non-standard
|
|
html += addArgumentOption("night", Boolean, settings.night);
|
|
html += addArgumentOption("setting", ["Overworld", "Underworld", "Underwater", "Castle", "Sky"], settings.setting);
|
|
html += addArgumentOption("alt", Boolean, settings.alt);
|
|
html += "</table>";
|
|
|
|
// Apply this to options
|
|
options.innerHTML = html;
|
|
|
|
// Make these valid, and call the setting supdate function
|
|
ensureOptionsAboveZero(editorUpdateSettingsOption);
|
|
|
|
// Knowing these options, reference them
|
|
rows = editor.sidebar.getElementsByTagName("table")[0].rows;
|
|
editor.settings.night_elem = rows[0].cells[1].firstChild;
|
|
editor.settings.setting_elem = rows[1].cells[1].firstChild;
|
|
editor.settings.alt_elem = rows[2].cells[1].firstChild;
|
|
|
|
// There's no follower here
|
|
if(editor.follower) killNormal(editor.follower);
|
|
editor.follower = false;
|
|
}
|
|
|
|
// Called instead of editorUpdateFollower for settings
|
|
function editorUpdateSettingsOption(event) {
|
|
var settings = editor.settings,
|
|
night = settings.night = settings.night_elem.value == "True",
|
|
alt = settings.alt = settings.alt_elem.value == "True",
|
|
setting = settings.setting = settings.setting_elem.value,
|
|
// // Get the new area setting from the editor settings elemes
|
|
newsetting = setting + (night ? " Night" : "") + (alt ? " " + alt : "");
|
|
setAreaSetting(area, newsetting, newsetting != area.setting);
|
|
}
|
|
|
|
// Called when something in the bottom bar is clicked
|
|
function editorSetCurrentThing(event, sameargs) {
|
|
// Set this as selected for the editor
|
|
var self = event.target,
|
|
name = editor.current_thing_name = self.name,
|
|
refs = editor.current_thing = editor.section[name];
|
|
if(!sameargs) updateCurrentArguments(name, refs);
|
|
editorUpdateFollower();
|
|
}
|
|
// Manually makes a fake event for editorSetCurrentThing using a bottom bar's canvas
|
|
function editorSetCurrentThingFromCanvas(canv, sameargs) {
|
|
editorSetCurrentThing({target: canv}, sameargs);
|
|
}
|
|
// Manually makes a fake event for editorSetCurrentThing using just a name
|
|
function editorSetCurrentThingFromName(name, sameargs) {
|
|
editorSetCurrentThing({target: {name: name || editor.current_thing_name}}, sameargs);
|
|
}
|
|
|
|
// Displays arguments of the selected Thing
|
|
function updateCurrentArguments(name, reference) {
|
|
reference = reference || {};
|
|
var options = editor.options,
|
|
html = "<table>",
|
|
mydefaults = reference.mydefaults || {},
|
|
arguments = reference.arguments || {},
|
|
i;
|
|
|
|
// Add this thing's name
|
|
html += "<h3 class='title'>" + name + "</h3>";
|
|
|
|
// Size must be there, with or without the arguments
|
|
if(!arguments.width) html += addStaticOption("width", reference.width);
|
|
if(!arguments.height) html += addStaticOption("height", reference.height);
|
|
|
|
// Add any other arguments
|
|
for(i in arguments) {
|
|
html += addArgumentOption(i.replace("_", "-"), arguments[i], null, mydefaults);
|
|
}
|
|
|
|
// Submit the HTML
|
|
html += "</table>";
|
|
options.innerHTML = html;
|
|
|
|
ensureOptionsAboveZero();
|
|
}
|
|
// An option that can't be changed
|
|
function addStaticOption(name, value) {
|
|
if(value == Infinity) value = "Inf.";
|
|
return "<tr id='option_" + name + "' class='auto'><td>" + name + ": </td><td class='auto'>" + value + "</td></tr>";
|
|
}
|
|
// An option that can be changed (as an argument)
|
|
function addArgumentOption(name, value, ref, mydefaults) {
|
|
mydefaults = mydefaults || {};
|
|
var text = "<tr name='" + name + "' id='option_" + name + "'><td>" + name + ": </td><td>";
|
|
|
|
switch(value) {
|
|
case Infinity: text += "Inf"; break;
|
|
case Boolean:
|
|
text += "<select name='" + name + "' value='" + (value ? "true" : "false") + "'><option>False</option><option>True</select>";
|
|
break;
|
|
case Number:
|
|
text += "<input name='" + name + "' value='" + String(value || 0) + "' type='Number'>";
|
|
break;
|
|
default:
|
|
switch(typeof(value)) {
|
|
case "number": text += "<span class='optspan'>" + value + "x</span><input name='" + name + "' type='Number' class='text' value='" + (mydefaults[name] || 1) + "'>"; break;
|
|
case "string": text += "<input name='" + name + "' type='text' class='text wide' value='" + value + "'>"; break;
|
|
case "object":
|
|
text += "<select name='" + name + "'>";
|
|
for(i in value) text += "<option>" + value[i] + "</option>";
|
|
text += "<select>";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return text + "</td></tr>";
|
|
}
|
|
|
|
// Ensures input & select elements are valid, and update when needed
|
|
function ensureOptionsAboveZero(updatefunc) {
|
|
updatefunc = updatefunc || editorUpdateFollower;
|
|
// For each input element, don't let it go below 0
|
|
var elements = editor.options.getElementsByTagName("input"),
|
|
element;
|
|
for(i = elements.length - 1; i >= 0; --i) {
|
|
element = elements[i];
|
|
element.onchange = element.onclick = element.onkeypress = editorInputEnsureAboveZero;
|
|
}
|
|
|
|
// Select elements also need to update the follower on change
|
|
elements = options.getElementsByTagName("select");
|
|
for(i = elements.length - 1; i >= 0; --i) {
|
|
element = elements[i];
|
|
element.onchange = element.onclick = element.onkeypress = editorUpdateFollower;
|
|
}
|
|
}
|
|
|
|
function editorInputEnsureAboveZero(event) {
|
|
// var me = event.target,
|
|
// min = editor.current_thing.minimum || 0,
|
|
// value = me.value = Number(me.value) || min;
|
|
// setTimeout(function() { if(value < me.min) me.value = min; }, 35);
|
|
|
|
editorUpdateFollower(event);
|
|
}
|
|
|
|
/* The Follower */
|
|
function editorUpdateFollower(event) {
|
|
// If settings are chosen, do that instead
|
|
if(editor.in_settings) return editorUpdateSettingsOption(event);
|
|
|
|
var current_thing = editor.current_thing,
|
|
args, follower;
|
|
|
|
// If there's already one, kill it
|
|
if(follower = editor.follower) {
|
|
follower.id = "";
|
|
killNormal(follower);
|
|
}
|
|
|
|
// If it has its own function (e.g. a Sprite currier), use that
|
|
if(current_thing.createfunc) {
|
|
follower = current_thing.createfunc(editor.current_thing, editorGetArguments());
|
|
}
|
|
// Otherwise pass it to ThingCreate with arguments
|
|
else follower = ThingCreate(
|
|
window[editor.current_thing_name],
|
|
current_thing.followerUpdate(editor.current_thing, editorGetArguments())
|
|
);
|
|
// Arguments set things such as size and adding
|
|
|
|
editor.follower = follower;
|
|
// Also give it things like the CSS ID and the onclick
|
|
proliferate(follower, {
|
|
id: "follower",
|
|
libtype: editor.section_name, // just in case (for scenery)
|
|
lookleft: true, // just in case (for HammerBro throwing)
|
|
nocollide: true,
|
|
reference: current_thing,
|
|
onclick: editorMouseClick
|
|
}, true);
|
|
|
|
// Add it, and give it the 'editor' class
|
|
addThing(follower);
|
|
addClass(follower, "editor");
|
|
|
|
// Don't let it do anything, unless this is a live run-through!
|
|
thingRetrieveVelocity(follower);
|
|
thingStoreVelocity(follower);
|
|
|
|
// Make sure it has a position
|
|
editorSetFollowerPosition(follower);
|
|
|
|
// Hide it if there's it's eraser
|
|
if(editor.erasing) follower.hidden = true;
|
|
}
|
|
// Grabs the inputs and their values from #options
|
|
function editorGetArguments() {
|
|
var inputs = arrayMake(editor.options.getElementsByTagName("input")),
|
|
selects = arrayMake(editor.options.getElementsByTagName("select")),
|
|
combined = inputs.concat(selects);
|
|
pairs = generateInputNameValuePairs(combined);
|
|
return pairs;
|
|
}
|
|
function generateInputNameValuePairs(inputs) {
|
|
var output = {}, i;
|
|
for(i in inputs) {
|
|
output[inputs[i].name] = inputs[i].value;
|
|
}
|
|
return output;
|
|
}
|
|
|
|
// Whenever the cursor moves, put it on that location
|
|
function editorFollowerFollowsCursor(event) {
|
|
var follower = editor.follower;
|
|
if(!follower) return;
|
|
var xloc = roundFollowerDigit(event.x) + (editor.current_thing.widthoff - editor.offset.x) * unitsize,
|
|
yloc = roundFollowerDigit(event.y) + editor.current_thing.heightoff * unitsize;
|
|
|
|
editorSetFollowerPosition(follower, xloc, yloc);
|
|
}
|
|
function editorSetFollowerPosition(follower, xloc, yloc) {
|
|
xloc = xloc || editor.xloc_old || 0;
|
|
yloc = yloc || editor.yloc_old || 0;
|
|
|
|
setLeft(follower, xloc);
|
|
setTop(follower, yloc);
|
|
|
|
editor.xloc_old = xloc;
|
|
editor.yloc_old = yloc;
|
|
}
|
|
|
|
// Because Things are placed based on a grid, despite the ability to be free-form.
|
|
function roundFollowerDigit(num) {
|
|
// var diff = 4;
|
|
var diff = editor.section_name == "solids" ? 8 : 4;
|
|
// switch(editor.section_name) {
|
|
// case "solids": diff = 8; break;
|
|
// case "characters": diff = 4; break;
|
|
// case "scenery": diff = 2; break;
|
|
// }
|
|
return unitsize * diff * round(num / (unitsize * diff));
|
|
}
|
|
function roundFollowerPosition(me, num) {
|
|
editorSetFollowerPosition(me,
|
|
roundFollowerDigit(me.left),
|
|
roundFollowerDigit(me.top)
|
|
);
|
|
}
|
|
|
|
/* Follower Update Methods */
|
|
|
|
// The default argument generator
|
|
// Passes in width and height, in that order, if they're in the arguments
|
|
function editorFollowerUpdateStandard(reference, pairs) {
|
|
// Hidden is a necessary check
|
|
if(pairs.hidden == "True") {
|
|
// This is an event because these are set before the new follower is made
|
|
TimeHandler.addEvent(function() { editor.follower.hidden = true; });
|
|
}
|
|
|
|
// More importantly, check for width and height
|
|
var output = [];
|
|
if(pairs.width) output.push(Number(pairs.width));
|
|
if(pairs.height) output.push(Number(pairs.height));
|
|
return output;
|
|
}
|
|
|
|
|
|
/* Editor Controls */
|
|
|
|
// Launches editorControlXXX, where X is what's clicked
|
|
function editorClickControl(event) {
|
|
// So the editor knows not to place anything
|
|
editorPreventClicks();
|
|
// This can either be the control or the control's firstChild
|
|
var target = event.target;
|
|
if(!target.id) target = target.parentNode;
|
|
window["editorControl" + capitalizeFirst(target.id)]();
|
|
// This should stop it from causing a placement
|
|
event.preventDefault();
|
|
}
|
|
function editorPreventClicks() {
|
|
editor.clicking = true;
|
|
TimeHandler.addEvent(editorClickOff, 3);
|
|
}
|
|
function editorClickOff() {
|
|
if(window.editor) editor.clicking = false;
|
|
}
|
|
|
|
// Deletes and pops the last thing in placed
|
|
function editorControlUndo() {
|
|
var placed = editor.placed,
|
|
last = placed.pop();
|
|
|
|
if(last && !last.mario) {
|
|
killNormal(last);
|
|
}
|
|
}
|
|
|
|
// Continuously undos until placed is empty
|
|
function editorControlReset() {
|
|
var placed = editor.placed,
|
|
len = placed.length,
|
|
timer = roundDigit(35 / len, 21);
|
|
|
|
TimeHandler.addEventInterval(editorControlUndo, timer, len);
|
|
}
|
|
|
|
// Creates the function and displays the submission window to the user
|
|
function editorControlSave() {
|
|
// if(editor.playing || editor.placed.length == 0) return;
|
|
|
|
// Display the input/submission window to the user
|
|
var rawfunc = editor.rawfunc = editorGetRawFunc(),
|
|
title = "<span style='font-size:1.4em;'>Hit Submit below to start playing!</span>",
|
|
p = "<p style='font-size:.7em;line-height:140%'>This map will be resumed automatically the next time you use the editor on this computer.<br>Alternately, you may copy this text to work on again later using Load (the button next to Save). </p>",
|
|
menu = editorCreateInputWindow(title + "<br>" + p, rawfunc, editorSubmitGameFuncPlay);
|
|
|
|
return rawfunc;
|
|
}
|
|
|
|
// Stops playing (really just calls loadEditor)
|
|
function editorControlCancel() {
|
|
loadEditor();
|
|
}
|
|
|
|
// Gets the string version of the editor function
|
|
function editorGetRawFunc() {
|
|
var placed = editor.placed,
|
|
lenm1 = placed.length - 1,
|
|
statements = new Array(i),
|
|
// Using the simple Function constructor, the map is the first argument
|
|
rawfunc = " var map = arguments[0] || new Map();\n",
|
|
i;
|
|
|
|
// Start the raw func off with the time, location, and area
|
|
rawfunc += "\n map.time = " + data.time.amount + ";";
|
|
rawfunc += "\n map.locs = [ new Location(0, true) ];";
|
|
rawfunc += "\n map.areas = [";
|
|
rawfunc += "\n new Area('" + area.setting + "', function() {";
|
|
rawfunc += "\n setLocationGeneration(0);\n\n";
|
|
|
|
// Generate the pre-statements based on what's placed
|
|
for(i = lenm1; i >= 0; --i) {
|
|
// Manipulations are done by the editorPreStatement object
|
|
statements[i] = new editorPreStatement(placed[i]);
|
|
}
|
|
|
|
// Sort the pre-statements, for cleanliness
|
|
statements.sort(prethingsorter);
|
|
|
|
// With them sorted, turn them all into strings (with the 6 spaces in front)
|
|
for(i = lenm1; i >= 0; --i) {
|
|
// Manipulations are done by the editorPreStatement object
|
|
statements[i] = " " + statements[i].statement;
|
|
}
|
|
|
|
// So that annoying loading glitch doesn't happen
|
|
statements = removeDuplicates(statements);
|
|
|
|
// Add these statements to the raw function
|
|
rawfunc += statements.join("\n");
|
|
|
|
// Finish off the area function
|
|
rawfunc += "\n })";
|
|
rawfunc += "\n ];";
|
|
rawfunc += "\n return map;"
|
|
|
|
return rawfunc;
|
|
}
|
|
|
|
// Generates a prestatement based off a placed object
|
|
function editorPreStatement(placer) {
|
|
this.placer = placer;
|
|
|
|
// Positioning is important
|
|
this.xloc = (gamescreen.left + placer.left) / unitsize;
|
|
this.yloc = map.floor - placer.top / unitsize;
|
|
|
|
// Reference and arguments are used to make the statement
|
|
// Using them, get the statement
|
|
this.statement = editorGetStatement(this, placer, placer.reference, placer.args);
|
|
}
|
|
|
|
// Given a prestatement, this returns the string
|
|
function editorGetStatement(prestatement, placer, reference, args) {
|
|
// If there isn't a reference, try to get it from the library
|
|
if(!reference) {
|
|
reference = editor[placer.libtype][placer.title];
|
|
// If it's still not there, ignore this thing (like ScrollBlocker)
|
|
if(!reference) return "";
|
|
}
|
|
|
|
// The statement always starts with the reference's pre-function
|
|
var statement = (reference.prefunc || pushPreThing).name,
|
|
numargs = args.length,
|
|
argstrings, arg;
|
|
|
|
// If it has a custom prefunction creator (like scenery), do that
|
|
if(reference.prefunc_custom) {
|
|
statement += "(" + reference.prefunc_custom(prestatement, placer, reference, args) + ");";
|
|
}
|
|
// Otherwise generate the arguments
|
|
else {
|
|
argstrings = [];
|
|
|
|
// Unless reference specifies not to, add the placer's title
|
|
if(!reference.prefunc_solo) argstrings.push(placer.title);
|
|
// else argstrings.push(placer.prefunc);
|
|
|
|
// Start the argstrings off with the xloc and yloc
|
|
argstrings.push(String(prestatement.xloc));
|
|
argstrings.push(String(prestatement.yloc));
|
|
|
|
// For each argument (0 is the thing, so 1 onward), add it to the array of strings
|
|
for(var i = 1; i < numargs; ++i) {
|
|
// Add it, giving the thing apostrophes if needed
|
|
switch(typeof(arg = args[i])) {
|
|
case "undefined": break;
|
|
case "number": arg = String(round(arg)); break;
|
|
default: arg = String(arg); break;
|
|
}
|
|
// Don't add it if it's undefined
|
|
if(typeof(arg) != "undefined")
|
|
argstrings.push(arg);
|
|
}
|
|
|
|
// Make the statement use the arguments, joined by commas
|
|
statement += "(" + argstrings.join(", ") + ");";
|
|
}
|
|
|
|
return statement;
|
|
}
|
|
|
|
/* Erasing */
|
|
function editorControlErase() {
|
|
!editor.erasing ? editorControlEraseOn() : editorControlEraseOff();
|
|
}
|
|
function editorControlEraseOn() {
|
|
editor.erasing = editor.follower.hidden = true;
|
|
classAdd(body, "erasing");
|
|
classAdd(editor.controls.erase, "enabled");
|
|
}
|
|
function editorControlEraseOff() {
|
|
editor.erasing = editor.follower.hidden = false;
|
|
classRemove(body, "erasing");
|
|
classRemove(editor.controls.erase, "enabled");
|
|
}
|
|
|
|
function editorPlaceEraser(event) {
|
|
addThing(Eraser, event.x, event.y);
|
|
}
|
|
|
|
function Eraser(me) {
|
|
me.width = me.height = 2;
|
|
me.nocollide = me.nofall = true;
|
|
me.movement = eraserErases;
|
|
setCharacter(me, "eraser");
|
|
}
|
|
// Checks everything for collision (necessary because sceneries don't collide)
|
|
function eraserErases(me) {
|
|
if(!window.editor) return;
|
|
var placed = editor.placed,
|
|
arr = placed.concat(solids).concat(characters).concat(scenery),
|
|
other, i;
|
|
|
|
// If this touches anything in placed
|
|
for(i = arr.length - 1; i >= 0; --i) {
|
|
other = arr[i];
|
|
if(other.mario || other == editor.follower) continue;
|
|
// These ones touch:
|
|
if(objectsTouch(me, other)) {
|
|
// Kill the other
|
|
killNormal(other);
|
|
// Remove it from placed
|
|
placed.splice(placed.indexOf(other), 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ...and finally, kill me
|
|
killNormal(me);
|
|
}
|
|
|
|
/* Loading Previous Maps */
|
|
|
|
// Prompts the user to give part of a function
|
|
function editorControlLoad() {
|
|
var blurb = "Paste your work in progress here, and click Submit to continue it.";
|
|
editorCreateInputWindow(blurb, "", editorSubmitLoad);
|
|
}
|
|
|
|
// Takes solids, characters, and scenery, and puts them int oplaced
|
|
function addThingsToPlaced() {
|
|
var placed = editor.placed;
|
|
// Grab all the Things, and sort them
|
|
editor.placed = (editor.placed || []).concat(characters).concat(solids).concat(scenery);
|
|
placed.sort(prethingsorter);
|
|
// (don't include Mario in this)
|
|
placed.splice(placed.indexOf(mario), 1);
|
|
|
|
// Make the new placed all know their reference
|
|
for(i = placed.length - 1; i >= 0; --i) {
|
|
placer = placed[i];
|
|
placer.reference = editor[placer.libtype][placer.title];
|
|
}
|
|
}
|
|
|
|
/* Editor Input/Submission Window */
|
|
|
|
function editorCreateInputWindow(blurb, value, callback) {
|
|
// Create the elements
|
|
var bigwidth = gamescreen.unitwidth,
|
|
div = editor.input_window = createElement("div", {
|
|
id: "input_window",
|
|
innerHTML: blurb || "",
|
|
style: { width: bigwidth + "px" }
|
|
}),
|
|
input = div.input = editor.window_input = createElement("textarea", {
|
|
id: "window_input",
|
|
value: value || "",
|
|
style: { width: (bigwidth - 49) + "px" }
|
|
}),
|
|
submit = div.submit = createElement("div", {
|
|
id: "window_submit",
|
|
className: "window_button",
|
|
innerText: "Submit",
|
|
onclick: callback
|
|
}),
|
|
cancel = div.cancel = createElement("div", {
|
|
id: "window_cancel",
|
|
className: "window_button",
|
|
innerText: "Cancel",
|
|
onclick: editorCloseInputWindow
|
|
});
|
|
|
|
// Add them to each other, and the body
|
|
div.appendChild(input);
|
|
div.appendChild(submit);
|
|
div.appendChild(cancel);
|
|
body.appendChild(div);
|
|
|
|
// Remove the follower
|
|
killNormal(editor.follower = false);
|
|
editor.follower = false;
|
|
|
|
return div;
|
|
}
|
|
|
|
function editorCloseInputWindow(noedit) {
|
|
editorPreventClicks();
|
|
// Delete the input window
|
|
removeChildSafe(window.input_window, body);
|
|
|
|
if(!noedit) {
|
|
// Recreate the current thing
|
|
editorSetCurrentThingFromName();
|
|
|
|
// Pretty sure this is necessary.
|
|
window.editing = true;
|
|
}
|
|
|
|
editorUpdateFollower();
|
|
}
|
|
|
|
// It's as if it never happened.
|
|
function editorClose(inmap) {
|
|
if(!window.editor) return;
|
|
|
|
// Clear any visual changes
|
|
classRemove(body, "editor");
|
|
classRemove(body, "erasing");
|
|
|
|
// Remove the follower
|
|
// if(window.editor) {
|
|
killNormal(editor.follower);
|
|
editor.follower = false;
|
|
delete window.editor;
|
|
// }
|
|
|
|
// Remove the editor elements (safely)
|
|
var ids = ["maplines", "sidebar", "bottombar", "scrollers"], i;
|
|
for(i in ids) removeChildSafe(document.getElementById(ids[i]), body);
|
|
|
|
// Stop the mouse triggers
|
|
document.onmousemove = null;
|
|
|
|
window.editing = false;
|
|
// Unless this is being called by setMap, stop shifting
|
|
if(inmap && window.map) map.shifting = false;
|
|
}
|
|
|
|
// Called by scrollWindow while editing to update the follower
|
|
function scrollEditor(xinv, yinv) {
|
|
if(!window.editor) return;
|
|
|
|
var follower = editor.follower;
|
|
if(!follower) return;
|
|
|
|
xinv = xinv || 0;
|
|
yinv = yinv || 0;
|
|
// shiftBoth(follower, xinv, yinv);
|
|
shiftAll(scenery, xinv, yinv);
|
|
shiftAll(solids, xinv, yinv);
|
|
shiftAll(characters, xinv, yinv);
|
|
editor.xloc += xinv;
|
|
editor.yloc += yinv;
|
|
}
|
|
|
|
function editorStoreLocally() {
|
|
// Record this in localStorage
|
|
localStorage.editorLastFunc = editor.rawfunc;
|
|
}
|
|
|
|
// Checks for a previously saved function, and loads if found
|
|
function setEditorLocalRetrieval() {
|
|
var found = localStorage.editorLastFunc;
|
|
if(!found) return;
|
|
editor.rawfunc = round;
|
|
editorSubmitGameFunc();
|
|
}
|
|
|
|
// Starts the editor with a particular function from editor.rawfunc
|
|
function editorSubmitGameFunc() {
|
|
// If there's no raw function known, don't do anything
|
|
if(!window.editor || !editor.rawfunc) return loadEditor();
|
|
|
|
var rawfunc = editor.rawfunc,
|
|
mapfunc = window.custommapfunc = new Function(editor.rawfunc);
|
|
|
|
// Start the map
|
|
mapfuncs.Custom = { Map: mapfunc };
|
|
window.canedit = true;
|
|
setMap(["Custom", "Map"]);
|
|
window.canedit = editor.playing = false;
|
|
|
|
// Load mario and all things
|
|
entryBlank(mario);
|
|
addThingsToPlaced();
|
|
|
|
// Save and close
|
|
editorStoreLocally();
|
|
editorCloseInputWindow();
|
|
}
|
|
|
|
// Submits the game function, and starts playing
|
|
function editorSubmitGameFuncPlay() {
|
|
editorPreventClicks();
|
|
editorSubmitGameFunc();
|
|
editorStartPlaying();
|
|
}
|
|
|
|
// Grabs the raw function from the input window
|
|
function editorSubmitLoad() {
|
|
if(!window.editor || !editor.window_input) return;
|
|
editorPreventClicks();
|
|
var rawfunc = editor.window_input.value;
|
|
loadEditor();
|
|
editor.rawfunc = rawfunc;
|
|
editorSubmitGameFunc();
|
|
}
|
|
|
|
// Allows Mario to roam the world
|
|
function editorStartPlaying() {
|
|
editorPreventClicks();
|
|
editor.playing = true;
|
|
// Place a Mario normally
|
|
placeMario();
|
|
entryPlain(mario);
|
|
nokeys = false;
|
|
// Retrieve each thing
|
|
var placed = editor.placed,
|
|
placer, ref, i;
|
|
for(i in placed) {
|
|
placer = placed[i];
|
|
thingRetrieveVelocity(placer);
|
|
// If it needs, give it back some defaults
|
|
ref = editor[placer.libtype][placer.title];
|
|
if(ref)
|
|
proliferate(placer, ref.onadds);
|
|
}
|
|
// Only have the cancel option now
|
|
setEditorControls(["Cancel"]);
|
|
}
|
|
|
|
// Checks for a rawfunc in localStorage, and loads it if possible
|
|
function setEditorLocalRetrieval() {
|
|
var found = localStorage.editorLastFunc;
|
|
if(!found) return;
|
|
editor.rawfunc = found;
|
|
editorSubmitGameFunc();
|
|
editorStoreLocally();
|
|
|
|
// For each thing now placed:
|
|
var placed = editor.placed, i;
|
|
for(i in placed) {
|
|
// thingRetrieveVelocity(placed[i]);
|
|
thingStoreVelocity(placed[i]);
|
|
}
|
|
}
|