Add polish to the game

I added polish to the game. Hooray.
This commit is contained in:
zeno 2024-02-28 11:59:54 -05:00
parent 6bbfbd60d0
commit e4584d0669
18 changed files with 651 additions and 86 deletions

View file

@ -1,6 +1,4 @@
# altboxels # altboxels
A sandbox game inspired by https://sandboxels.r74n.com/, with a cleaner codebase and secure/simple modding support in mind. A sandbox game inspired by https://sandboxels.r74n.com/, with a cleaner codebase and secure/simple modding support in mind.
Some of the elements are derived from other games in the falling sand genre, especially Sandboxels. However, the physics engine and other backend code are custom and independently developed. Some of the elements are derived from other games in the falling sand genre, especially Sandboxels. However, the physics engine and other backend code are custom and independently developed.
Recreated to remove private information from commit logs.

View file

@ -1,10 +1,13 @@
@import url("./fonts.css");
body { body {
font-family: monospace; font-family: "Ubuntu Mono";
padding: 10px; padding: 10px;
margin: 0; margin: 0;
background: rgb(21, 21, 22); background: rgb(21, 21, 22);
color: white; color: white;
text-align: center; text-align: center;
user-select: none;
} }
#no-overflow { #no-overflow {
@ -16,6 +19,7 @@ canvas {
display: block; display: block;
background: rgb(181, 204, 253); background: rgb(181, 204, 253);
image-rendering: pixelated; image-rendering: pixelated;
border-radius: 10px;
} }
#main2 { #main2 {
@ -27,7 +31,7 @@ canvas {
} }
button, a, textarea { button, a, textarea {
padding: 5px; padding: 5px 10px;
border: none; border: none;
margin: 6px 3px 0px 3px; margin: 6px 3px 0px 3px;
@ -36,9 +40,254 @@ button, a, textarea {
background: rgb(44, 142, 255); background: rgb(44, 142, 255);
color: white; color: white;
font-family: monospace; font-family: inherit;
border-radius: 6px;
font-size: 17px;
cursor: pointer;
} }
section:target button, .menu2 button, a, textarea { section.selected-group button, .menu2 button, a, textarea {
display: inline-block; display: inline-block;
} }
div#header-title {
font-size: 23px;
}
#header-links a {
margin-top: 0;
background: none;
}
#header {
padding: 0 8px;
margin-bottom: 32px;
}
#header {
display: flex;
justify-content: space-between;
align-content: center;
align-items: center;
font-size: 16px;
}
.menu, .menu2, .buttons > .selected-group {
position: relative;
left: 50%;
transform: translateX(-50%);
width: var(--canvasWidth);
display: flex;
justify-content: space-evenly;
}
.buttons {
background: #7b7b7b;
border-radius: 0 0 5px 5px;
overflow-y: auto;
}
.buttons > .selected-group {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
height: 100px;
padding: 10px;
overflow-y: auto;
}
.menu a,
.menu2 a {
width: 100%;
text-decoration: none;
}
.buttons button {
width: calc(25% - 6px);
}
.tab-bar > * {
background: #616161;
margin: 0;
margin-top: 8px;
border-radius: 10px 10px 0 0;
padding: 8px 10px;
width: 100%;
cursor: pointer;
}
.tab-bar > .selected-group {
background: #7b7b7b;
}
#game {
position: relative;
left: 50vw;
transform: translateX(-50%);
}
.info {
height: 20px;
display: block;
}
/* Mod Loader */
#mod-loader-modal {
position: fixed;
left: 0;
top: 0;
background: #000a;
width: 100vw;
height: 100vh;
z-index: 100;
opacity: 1;
transition: opacity 0.25s ease-in-out;
}
#mod-loader-modal-box {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: min(800px, 75vw);
background: #7b7b7b;
border-radius: 10px;
font-size: 0;
transition: transform 0.25s ease-in-out;
overflow: hidden;
}
#mod-loader-modal:not(.opened) {
opacity: 0;
pointer-events: none;
}
#mod-loader-modal:not(.opened) #mod-loader-modal-box {
transform: translate(-50%, -50%) scaleY(0);
}
#mod-loader-modal-header {
display: flex;
justify-content: space-between;
padding: 10px;
height: 28px;
align-items: center;
position: relative;
background: #3b3b3b;
}
.tab-bar {
display: flex;
flex-direction: row;
justify-content: space-evenly;
width: 100%;
}
#mod-loader-modal-title {
flex: none;
}
#mod-loader-modal-close-button {
background: gray;
padding: 6px;
border-radius: 7px;
cursor: pointer;
}
.mod-loader-tab-content:not(.selected-group) {
display: none;
}
#mod-form {
position: absolute;
left: 50%;
top: 50%;
width: 100%;
transform: translate(-50%, -50%);
}
#mod-loader-modal-content {
height: min(500px, 75vh);
overflow-y: auto;
}
#mod-loader-modal-box > * > * {
font-size: 16px;
}
#mod-loader-modal-tabs {
/* margin: 0 29px; */
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60%;
}
/* Mods */
.mods-list {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: flex-start;
align-content: flex-start;
flex-direction: row;
}
.mod {
display: inline-flex;
--margin: 10px;
width: calc(50% - (var(--margin) * 2));
height: 96px;
box-sizing: border-box;
border: 5px solid darkgray;
background: lightgray;
color: #555;
padding: 8px;
margin: 10px;
justify-content: space-between;
}
.mod-icon {
aspect-ratio: 1 / 1;
flex: none;
height: 100%;
image-rendering: pixelated;
}
.mod-details > * {
text-align: left;
margin: 0 5px;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
display: -webkit-box;
}
.mod-loader-tab-content {
/* padding: 10px; */
box-sizing: border-box;
}
.mod-details {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 68%;
overflow: hidden;
}
.mod-name {
color: #111;
font-size: 20px;
/* white-space: nowrap; */
max-width: 100%;
text-overflow: ellipsis;
overflow: hidden;
-webkit-line-clamp: 1;
}
.mod-options {
flex: none;
display: flex;
flex-direction: column;
}

40
css/fonts.css Normal file
View file

@ -0,0 +1,40 @@
@font-face {
font-family: 'Ubuntu Mono';
src: local('Ubuntu Mono'), local('UbuntuMono-Regular'),
url('fonts/UbuntuMono-Regular.woff2') format('woff2'),
url('fonts/UbuntuMono-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Ubuntu Mono';
src: local('Ubuntu Mono Italic'), local('UbuntuMono-Italic'),
url('fonts/UbuntuMono-Italic.woff2') format('woff2'),
url('fonts/UbuntuMono-Italic.woff') format('woff');
font-weight: normal;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Ubuntu Mono';
src: local('Ubuntu Mono Bold Italic'), local('UbuntuMono-BoldItalic'),
url('fonts/UbuntuMono-BoldItalic.woff2') format('woff2'),
url('fonts/UbuntuMono-BoldItalic.woff') format('woff');
font-weight: bold;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Ubuntu Mono';
src: local('Ubuntu Mono Bold'), local('UbuntuMono-Bold'),
url('fonts/UbuntuMono-Bold.woff2') format('woff2'),
url('fonts/UbuntuMono-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}

96
css/fonts/UFL.txt Normal file
View file

@ -0,0 +1,96 @@
-------------------------------
UBUNTU FONT LICENCE Version 1.0
-------------------------------
PREAMBLE
This licence allows the licensed fonts to be used, studied, modified and
redistributed freely. The fonts, including any derivative works, can be
bundled, embedded, and redistributed provided the terms of this licence
are met. The fonts and derivatives, however, cannot be released under
any other licence. The requirement for fonts to remain under this
licence does not require any document created using the fonts or their
derivatives to be published under this licence, as long as the primary
purpose of the document is not to be a vehicle for the distribution of
the fonts.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this licence and clearly marked as such. This may
include source files, build scripts and documentation.
"Original Version" refers to the collection of Font Software components
as received under this licence.
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to
a new environment.
"Copyright Holder(s)" refers to all individuals and companies who have a
copyright ownership of the Font Software.
"Substantially Changed" refers to Modified Versions which can be easily
identified as dissimilar to the Font Software by users of the Font
Software comparing the Original Version with the Modified Version.
To "Propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification and with or without charging
a redistribution fee), making available to the public, and in some
countries other activities as well.
PERMISSION & CONDITIONS
This licence does not grant any rights under trademark law and all such
rights are reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of the Font Software, to propagate the Font Software, subject to
the below conditions:
1) Each copy of the Font Software must contain the above copyright
notice and this licence. These can be included either as stand-alone
text files, human-readable headers or in the appropriate machine-
readable metadata fields within text or binary files as long as those
fields can be easily viewed by the user.
2) The font name complies with the following:
(a) The Original Version must retain its name, unmodified.
(b) Modified Versions which are Substantially Changed must be renamed to
avoid use of the name of the Original Version or similar names entirely.
(c) Modified Versions which are not Substantially Changed must be
renamed to both (i) retain the name of the Original Version and (ii) add
additional naming elements to distinguish the Modified Version from the
Original Version. The name of such Modified Versions must be the name of
the Original Version, with "derivative X" where X represents the name of
the new work, appended to that name.
3) The name(s) of the Copyright Holder(s) and any contributor to the
Font Software shall not be used to promote, endorse or advertise any
Modified Version, except (i) as required by this licence, (ii) to
acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
their explicit written permission.
4) The Font Software, modified or unmodified, in part or in whole, must
be distributed entirely under this licence, and must not be distributed
under any other licence. The requirement for fonts to remain under this
licence does not affect any document created using the Font Software,
except any version of the Font Software extracted from a document
created using the Font Software may only be distributed under this
licence.
TERMINATION
This licence becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

16
css/icons/open-link.svg Normal file
View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg height="800px" width="800px" version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 512 512" xml:space="preserve">
<style type="text/css">
.st0{fill:#000000;}
</style>
<g>
<path class="st0" d="M96,0v416h416V0H96z M472,376H136V40h336V376z"/>
<polygon class="st0" points="40,472 40,296 40,136 40,96 0,96 0,512 416,512 416,472 376,472 "/>
<polygon class="st0" points="232.812,312.829 350.671,194.969 350.671,279.766 390.671,279.766 390.671,126.688 237.594,126.688
237.594,166.688 322.39,166.688 204.531,284.547 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 837 B

View file

@ -15,41 +15,85 @@
</head> </head>
<body> <body>
<h1>Altboxels</h1> <div id="header">
<canvas id='main' style=""></canvas> <div id="header-title">Altboxels</div>
<canvas id='alt' style='display: none;'></canvas>
<div id="header-links">
<span class='info'>
N/A
</span>
<div class='menu2'>
<section>
<a href='https://discord.gg/wtBVte4Syu'>Chat</a> <a href='https://discord.gg/wtBVte4Syu'>Chat</a>
<a href='https://github.com/qazox/altboxels'>Source</a> <a href='https://github.com/qazox/altboxels'>Source</a>
<a href='https://altboxels.qazox.dev/'>Website</a> <a href='https://altboxels.qazox.dev/'>Website</a>
<a href='https://abc.qazox.dev/'>Community</a> <a href='https://abc.qazox.dev/'>Community</a>
</section> </div>
<section>
<button onclick="handler.noTick = !handler.noTick">Pause</button>
<button onclick="openMods()">Mods</button>
<button onclick="save()">Save</button>
<button onclick="load()">Load</button>
<button onclick="canvas.radius++;">+Rad</button>
<button onclick="canvas.radius = Math.max(canvas.radius - 1,0);">-Rad</button>
</section>
</div> </div>
<div id="mod-loader-modal">
<div class='menu'> <div id="mod-loader-modal-box">
<div id="mod-loader-modal-header">
<div id="mod-loader-modal-title">Mods (Alpha!)</div>
<div id="mod-loader-modal-tabs" class="tab-bar">
<div class="mod-loader-tab">Load Online</div>
<div class="mod-loader-tab selected-group">Load from URL</div>
<div class="mod-loader-tab">Manage</div>
</div>
<div id="mod-loader-modal-close-button" onclick="closeMods()">X</div>
</div>
<div id="mod-loader-modal-content">
<div class="mod-loader-tab-content">uploaded mods go here</div>
<div class="mod-loader-tab-content selected-group">
<form id="mod-form" onsubmit="loadModFromForm(); return false">
<p>Paste a link to a mod you've found, and put it here!</p>
<input type="url" />
<input type="submit" value="Load" />
</form>
</div>
<div class="mod-loader-tab-content mods-list">
<div class="mod example-mod">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAYJJREFUOE9NU9thwjAMlPYgMwAfCbMl+W6zCizQzkD4iFkC/toR1N6dZciH48f5JJ3Obt8/4eFmFoafG+ZYvq9DWxx0rhtm7l+/gVUIowMPA6kI8yLhucJNzv3y7CICHI4cuE+yiiWOCQmhKPUwzPz83DHXllKCKjwzUnFBcmcUVePnx07cTLuyC6UaoUULqrKwwcRw5/LYqXztvAkkQkbR0ITUtGp0fnQx3w72OWxEM5MmeSqd6lOlqpZIqMG0gqBoI8LG9ai1ajKcL/0m8SJsQsC+iIwE16N9ngojj+velqHYiL2h2LTu6x+YzYBdho0kH/0dInYxVxDikX0oNldSEd5tRJa9LiL6dDva0heI2AWihLvSDpHgME2JEuAVEOFjyadNgqcPZAS1j21ytU+Dv0hlt1cbQUDbymPpx7oIm68HZoe609tvL0MaMBrslI3nw0JHKiujZhOAq+1tVk4czaU3kZ6XE+uDyOSbw0wi8jXS3NWN7SG1FNKSkimL/Z/8AVDdA77BS/1YAAAAAElFTkSuQmCC" class="mod-icon">
<div class="mod-details">
<div class="mod-name">Sample Mod</div>
<div class="mod-description">This mod has a 16x16 icon. It's just a sample mod, this menu isn't finished yet.</div>
</div>
<div class="mod-options">
<input type="checkbox" class="mod-check" disabled checked />
</div>
</div>
</div>
</div>
</div>
</div> </div>
<div id="game">
<span class='info'>
N/A
</span>
<canvas id='main' style=""></canvas>
<canvas id='alt' style='display: none;'></canvas> <!-- why -->
<div class='buttons'>
<div class='menu2'>
<section>
<button onclick="handler.noTick = !handler.noTick">Pause/Play</button>
<button onclick="openMods()">Mods</button>
<button onclick="save()">Save</button>
<button onclick="load()">Load</button>
<!-- <button onclick="upload()">Upload (TODO)</button> - HEY! Please add this. Prompt() for title, I dunno. For a site like this, I feel like allowing anonymous posting is a good idea. -->
<label for="tile-radius">Radius:</label>
<input type="range" min="1" max="20"
oninput="canvas.radius = Number(this.value);"
onmousedown="canvas.forceShowTilePlacement = true; canvas.radius = Number(this.value)"
onmouseup="canvas.forceShowTilePlacement = false"/> <!-- TODO: automatically change range value -->
<button onclick="clearEverything()">Clear</button> <!-- TODO: add clear function (i do not know how to do that) -->
</section>
</div>
<div class='menu tab-bar'>
</div>
<div class='buttons'>
</div>
</div> </div>
<textarea id='code'>
(save data here)
</textarea>
<!-- Core code --> <!-- Core code -->
<script src="js/tile.js"></script> <script src="js/tile.js"></script>
<script src="js/event.js"></script> <script src="js/event.js"></script>

View file

@ -35,10 +35,17 @@ function Canvas(width, height, upscale) {
that.pageX = e.pageX; that.pageX = e.pageX;
that.pageY = e.pageY; that.pageY = e.pageY;
}) })
this.elem.addEventListener('mouseover', function (e) {
that.isMouseOver = true;
})
this.elem.addEventListener('mouseout', function (e) {
that.isMouseOver = false;
})
this.elem.addEventListener('wheel', function (e) { this.elem.addEventListener('wheel', function (e) {
that.radius += Math.sign(e.deltaY); that.radius += Math.sign(e.deltaY);
if (that.radius < 0) that.radius = 0; if (that.radius < 0) that.radius = 0;
e.preventDefault();
}) })
this.elem.addEventListener('mouseup', function (e) { this.elem.addEventListener('mouseup', function (e) {
@ -72,10 +79,16 @@ Canvas.prototype.setBlock = function (x, y, block, doTemp) {
Canvas.prototype.resize = function () { Canvas.prototype.resize = function () {
this.elem.style.width = this.width * this.upscale + 'px'; this.elem.style.width = this.width * this.upscale + 'px';
this.elem.style.height = this.height * this.upscale + 'px'; this.elem.style.height = this.height * this.upscale + 'px';
this.elem.width = this.width; this.elem.width = this.width;
this.elem.height = this.height; this.elem.height = this.height;
if(document.querySelector("#game") !== null)
document.querySelector("#game").setAttribute("style", `
width: ${this.width * this.upscale}px;
height: ${this.height * this.upscale}px;
`);
this.render(); this.render();
} }
@ -130,16 +143,21 @@ Canvas.prototype.render = function () {
document.querySelector('body').id = 'no-overflow'; document.querySelector('body').id = 'no-overflow';
return; return;
} }
let x = (this.pageX - this.elem.getBoundingClientRect().x - scrollX + this.x) - 0.5 - this.radius * this.upscale; if(this.forceShowTilePlacement == true) {
let y = (this.pageY - this.elem.getBoundingClientRect().y - scrollY + this.y) - 0.5 - this.radius * this.upscale; var x = (this.width / 2 - this.radius) * this.upscale;
var y = (this.height / 2 - this.radius) * this.upscale;
} else {
var x = (this.pageX - this.elem.getBoundingClientRect().x - scrollX + this.x) - 0.5 - this.radius * this.upscale;
var y = (this.pageY - this.elem.getBoundingClientRect().y - scrollY + this.y) - 0.5 - this.radius * this.upscale;
}
this.ctx.globalAlpha = 1; this.ctx.globalAlpha = 1;
this.ctx.strokeStyle = 'rgb(255,255,255)'; this.ctx.strokeStyle = 'rgb(255,255,255)';
this.ctx.lineWidth = 2; this.ctx.lineWidth = 2;
this.ctx.strokeRect(x / this.upscale, y / this.upscale, this.radius * 2 + 2, this.radius * 2 + 2); if(this.isMouseOver || this.forceShowTilePlacement)
this.ctx.strokeRect(x / this.upscale, y / this.upscale, this.radius * 2 + 2, this.radius * 2 + 2);
let theX = Math.floor(x/this.upscale + this.radius + 1); let theX = Math.floor(x/this.upscale + this.radius + 1);
let theY = Math.floor(y/this.upscale + this.radius + 1); let theY = Math.floor(y/this.upscale + this.radius + 1);
@ -149,10 +167,11 @@ Canvas.prototype.render = function () {
let blok = mainTiles.tiles[this.getBlock(theX, theY)]; let blok = mainTiles.tiles[this.getBlock(theX, theY)];
let temp = this.getBlock(theX,theY, true); let temp = this.getBlock(theX,theY, true);
if (blok) { if (blok && this.isMouseOver) {
document.querySelector('.info').textContent = `${blok.namespace}; ${blok.id}; ${Math.round(temp+23)}deg Celsius` document.querySelector('.info').textContent = `
Looking at ${blok.id} from ${blok.namespace}. Temperature at tile: ${Math.round(temp+23)}deg Celsius`
} else { } else {
document.querySelector('.info').textContent = `Unknown` document.querySelector('.info').textContent = ``
} }
} }

View file

@ -13,6 +13,8 @@
decent basis for modding in the future. decent basis for modding in the future.
*/ */
mods = [];
legalFuncs = [ legalFuncs = [
"gravity", "gravity",
"cohesion", "cohesion",
@ -47,9 +49,53 @@ function loadMod(stuff) {
) )
} }
} }
/*
async function openMods(stuff) { async function openMods(stuff) {
// TODO: don't use prompt // TODO: don't use prompt
let url = prompt('Type in the URL to the JSON of the mod you want to load.'); let url = prompt('Type in the URL to the JSON of the mod you want to load.');
loadMod(await (await fetch(url)).json()) loadMod(await (await fetch(url)).json())
}*/
function openMods() {
document.querySelector("#mod-loader-modal").classList.add("opened")
} }
function closeMods() {
document.querySelector("#mod-loader-modal").classList.remove("opened")
}
async function loadModFromForm() {
document.querySelector("#mod-form input").disabled = true;
let url = document.querySelector("#mod-form input").value;
try {
var mod = await fetch(url).then(e => e.json());
// do stuff here, check if mod is ok, etc...
alert("Mod loaded!")
mods.push(mod)
} catch(err) {
alert("That mod isn't valid. Check the mod, and try again.")
}
document.querySelector("#mod-form input").disabled = false;
}
document.querySelectorAll(".mod-loader-tab").forEach(function(element, index){
element.onclick = function() {
document.querySelectorAll("#mod-loader-modal .selected-group").forEach(function(e) {e.classList.remove("selected-group")})
element.classList.add("selected-group");
document.querySelector(".mod-loader-tab-content:nth-child("+(index+1)+")").classList.add("selected-group");
}
})

View file

@ -4,6 +4,47 @@
Features a somewhat efficient compression algorithm. Features a somewhat efficient compression algorithm.
*/ */
function download_file(data, filename) {
// ONLY works with ascii/latin1 characters. if you'd like to be able to download UTF-16 data (for compression, etc), please find a base64-encoding library for UTF-16, and replace "btoa".
let a = document.createElement("a");
a.href = "data:text/plain;base64,"+(btoa(data));
a.setAttribute("download", filename);
a.click();
a.remove();
}
function upload_file(options = {}) {
base64_output = Boolean(options.useBase64);
textEncoding = options.textEncoding ? options.textEncoding : "UTF-8";
return new Promise(function(res) {
var input = document.createElement('input');
input.type = 'file';
input.onchange = e => {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = readerEvent => {
res(readerEvent.target.result); // this is the content!
input.remove();
}
if(base64_output)
reader.readAsDataURL(file);
else
reader.readAsText(file, textEncoding);
}
input.click();
});
}
function save() { function save() {
let jason = { let jason = {
'pal': [], 'pal': [],
@ -48,53 +89,59 @@ function save() {
'dat': otherArray ? new TextDecoder('ascii').decode(otherArray) : undefined 'dat': otherArray ? new TextDecoder('ascii').decode(otherArray) : undefined
}; };
} }
document.querySelector('#code').value = JSON.stringify(jason); download_file(JSON.stringify(jason), "game-data.json");
} }
function load() { function load() {
let jason = JSON.parse(document.querySelector('#code').value); upload_file().then((text_data) => {
try {
let jason = JSON.parse(text_data);
let json = jason.data; let json = jason.data;
canvas.width = jason.width; canvas.width = jason.width;
canvas.height = jason.height; canvas.height = jason.height;
canvas.resize(); canvas.resize();
let mainPal = jason.pal.map(x => mainTiles.resolveID(x[0],x[1]));
console.log(mainPal);
for (let i in json) {
let data = json[i];
let pal = data.pal;
let dat = new TextEncoder('ascii').encode(data.dat);
let otherArray = new Uint16Array(128);
if (pal.length < 2) {
for (let i in otherArray) {
otherArray[i] = mainPal[(pal[0])];
}
} else if (pal.length < 9) { let mainPal = jason.pal.map(x => mainTiles.resolveID(x[0],x[1]));
for (let i in dat) {
otherArray[i*2] = mainPal[pal[((dat[i] - 'A'.charCodeAt()) & 0x38) / 8]]; console.log(mainPal);
otherArray[i*2+1] = mainPal[pal[(dat[i] - 'A'.charCodeAt()) & 0x7]];
for (let i in json) {
let data = json[i];
let pal = data.pal;
let dat = new TextEncoder('ascii').encode(data.dat);
let otherArray = new Uint16Array(128);
if (pal.length < 2) {
for (let i in otherArray) {
otherArray[i] = mainPal[(pal[0])];
}
} else if (pal.length < 9) {
for (let i in dat) {
otherArray[i*2] = mainPal[pal[((dat[i] - 'A'.charCodeAt()) & 0x38) / 8]];
otherArray[i*2+1] = mainPal[pal[(dat[i] - 'A'.charCodeAt()) & 0x7]];
}
} else {
for (let i in dat) {
otherArray[i] = mainPal[pal[(dat[i] - 'A'.charCodeAt()) & 0x7F]];
}
}
canvas.blocks.set(otherArray,Math.min(i*128,canvas.blocks.length - 128));
} }
} else { for (let i in canvas.temp) {
for (let i in dat) { canvas.temp[i] = mainTiles.tiles[canvas.blocks[i]].attributes.temperature;
otherArray[i] = mainPal[pal[(dat[i] - 'A'.charCodeAt()) & 0x7F]];
} }
} catch(err) {
alert("This save file is invalid! Please provide a JSON file, with Altboxels save data.")
} }
})
canvas.blocks.set(otherArray,Math.min(i*128,canvas.blocks.length - 128));
}
for (let i in canvas.temp) {
canvas.temp[i] = mainTiles.tiles[canvas.blocks[i]].attributes.temperature;
}
} }
var loc3 = new URL(window.location).searchParams; var loc3 = new URL(window.location).searchParams;

View file

@ -55,13 +55,23 @@ TileManager.prototype.loadSet = function (namespace, tiles) {
let elem = document.createElement('a'); let elem = document.createElement('a');
elem.textContent = namespace; elem.textContent = namespace;
elem.href = `#${namespace}` //elem.href = `#${namespace}`
//elem.id = namespace
this.row.appendChild(elem); this.row.appendChild(elem);
let elem2 = document.createElement('section'); let elem2 = document.createElement('section');
elem2.id = namespace elem2.id = namespace
this.row2.appendChild(elem2); this.row2.appendChild(elem2);
elem.onclick = function(e) {
document.querySelectorAll("#game .selected-group").forEach(function(e) {e.classList.remove("selected-group")})
e.target.classList.add("selected-group");
elem2.classList.add("selected-group");
}
for (let tile of tiles) { for (let tile of tiles) {
tile.namespace = namespace; tile.namespace = namespace;