<!DOCTYPE html>
<html lang="en_US" style='background-color:#858590;'>
<meta charset="UTF-8">
<title>ThePixelWorld</title>
<!-- Login -->
<style type="text/css">
.chat-tab{
margin-left: 2px;
margin-right: 2px;
padding-left: 3px;
padding-right: 3px;
float: left;
color: #858590;
background-color: #555555;
border-radius: 4px;
}
#active{
color: lime;
}
</style>
<div id="signDiv" style='text-align:center;'>
Username: <input id="signDiv-username" type="text"></input><br>
Password: <input id="signDiv-password" type="password"></input><br>
<button id="signDiv-signIn">Sign In</button>
<button id="signDiv-signUp">Sign Up</button>
<hr>
<div>
<h3 style='color:red;'>Dev-Note:</h3>
ThePixelWorld requires to load some huge map files, in case u have trouble:<br>
Firefox dev tools network inspector truncates responses to 1MB by default.<br>
You can change or disable the limit by navigating to <b>about:config</b><br>
and changing <b>devtools.netmonitor.responseBodyLimit</b>.<br>
To disable the limit, set it to <b>0</b>.
<hr>
<h3>News:</h3>
tmx maps loading and rendering nearly done, beside collision system.<br>
basic chat system (guild/party/... wip) {may also implement an api for irc usage?}<br>
every player has a name drawn above there head now.<br>
<h3>ToDo</h3>
to much, and to lazy to write it down *blush*
</div>
</div>
<!-- Game -->
<div id="gameDiv" style="display:none;">
<div id="game">
<canvas id="ctx" width="500" height="500" tabindex="1" style="position:absolute; border:1px solid #000000;"></canvas>
<div id="ui" tabindex="2" style="position:absolute; width:502px; height:502px; display:none;">
<div id="ui-statusbar" style="position:absolute; border:1px solid #000000; top:50px; left:0px; width:450px; height: 40px;">
Status Bar
</div>
<div id="ui-navigation" style="position:absolute; border:1px solid #000000; top:0px; left:0px; width:450px; height: 40px;">
Navigation Bar
</div>
<div id="ui-menu" style="position:absolute; border:1px solid #000000; top:0px; right:0px; width:40px; height: 40px;">
Menu
</div>
<div id="ui-shortcuts" style="position:absolute; border:1px solid #000000; bottom:0px; right:0px; height:450px; width: 40px;">
Shortcut Bar
</div>
<div id="ui-hook" style="position:absolute; border:1px solid #000000; bottom:210px; left:0px; width:240px; height: 190px;">
Storage/NPC(HOOKS)
</div>
<div id="ui-inventory" style="position:absolute; border:1px solid #000000; bottom:0px; left:0px; width:240px; height: 200px;">
Inventory
</div>
<div id="ui-equip" style="position:absolute; border:1px solid #000000; bottom:0px; left:250px; width:100px; height: 200px;">
Equip
</div>
<div id="ui-spells-quests" style="position:absolute; border:1px solid #000000; bottom:210px; left:250px; width:100px; height: 190px;">
Spells/<br>Quests
</div>
<div id="ui-undefined" style="position:absolute; border:1px solid #000000; bottom:0px; left:360px; width:90px; height: 400px;">
???
</div>
</div>
</div>
<div id="chat" style="margin-top:520px;">
<div id="chat-wrapper" style="width:500px; height:20px; overflow: hidden; white-space: nowrap;">
<div class="chat-tab" id='active' onclick="setActiveChatTab('world', this)" >WORLD</div>
<!-- TODO only show up on permission to use the GM tab.
<div class="chat-tab" onclick="setActiveChatTab('gm', this)"> GM</div> -->
<div class="chat-tab" onclick="setActiveChatTab('guild', this)">[#] Guild (WIP)</div>
<div class="chat-tab" onclick="setActiveChatTab('party', this)">[.] Party (WIP)</div>
</div>
<div id="chat-text" style="width:500px; height:100px; overflow-y:scroll;"></div>
<form id="chat-form">
<input id="chat-input" type="text" style="width:500px;"></input>
</form>
</div>
</div>
</div>
<!-- loading socket.io library -->
<script src="https://cdn.socket.io/4.2.0/socket.io.js"></script>
<script src="client/consts.js"></script>
<script src="client/tmxloader.js"></script>
<script>
var socket = io();
var errno = 0;
socket.on('disconnect', function(){
errno = CONNECTION_LOST;
alert("Connection lost..." + errno);
});
// Login
var signDiv = document.getElementById("signDiv");
var signDivUsername = document.getElementById("signDiv-username");
var signDivPassword = document.getElementById("signDiv-password");
var signDivSignIn = document.getElementById("signDiv-signIn");
var signDivSignUp = document.getElementById("signDiv-signUp");
signDivSignIn.onclick = function(){
socket.emit('signIn', {username:signDivUsername.value, password:signDivPassword.value})
}
signDivSignUp.onclick = function(){
socket.emit('signUp', {username:signDivUsername.value, password:signDivPassword.value})
}
socket.on('signInResponse', function(data){
if(data.success){
signDiv.style.display = 'none';
gameDiv.style.display = 'inline-block';
}
else
alert("Sign in unsuccessful.");
});
socket.on('signUpResponse', function(data){
if(data.success){
alert("Sign up successful.");
}
else
alert("Sign up unsuccessful.");
});
// Chat
var activeChatTab = "world"; // default tab on join.
var chatContents = [];
chatContents[activeChatTab] = "";
var chatText = document.getElementById("chat-text");
var chatInput = document.getElementById("chat-input");
var chatForm = document.getElementById("chat-form");
socket.on('addToChat', function(data){
if(data.tab === "any")
data.tab = activeChatTab;
if (chatContents[data.tab] === undefined)
document.getElementById("chat-wrapper").innerHTML += "<div class=\"chat-tab\" onclick=\"setActiveChatTab('" + data.tab + "', this)\">" + data.tab + "</div>";
if(!chatContents[data.tab])
chatContents[data.tab] = "<div title=\"" + data.ctimestamp + "\">" + data.content + "</div>"
else
chatContents[data.tab] += "<div title=\"" + data.ctimestamp + "\">" + data.content + "</div>"
if (activeChatTab === data.tab){
chatText.innerHTML = chatContents[activeChatTab];
//scroll down
chatText.scrollTop = chatText.scrollHeight;
}
});
socket.on('evalAnswer', function(data){
console.log(data);
});
chatForm.onsubmit = function(e){
e.preventDefault();
if (chatInput.value[0] === "*")
socket.emit("evalServer", chatInput.value.slice(1));
else if (chatInput.value[0] === "@" || chatInput.value[0] === "/"
|| chatInput.value[0] === "." || chatInput.value[0] === "#")
socket.emit("command", chatInput.value);
else if(activeChatTab !== "world")
socket.emit("command", "/w " + activeChatTab + " " + chatInput.value);
else
socket.emit("sendMsgToServer", chatInput.value);
chatInput.value = "";
}
// Game
var Img = {};
Img.player = new Image();
Img.player.src = '/client/assets/sprites/races/human-female.png';
Img.bullet = new Image();
Img.bullet.src = '/client/assets/sprites/blaze.png';
var ctx = document.getElementById("ctx").getContext("2d");
ctx.font = '16px Arial';
var Player = function(initPack){
var self = {};
self.id = initPack.id;
self.playerName = initPack.playerName;
self.x = initPack.x;
self.y = initPack.y;
self.map = initPack.map;
self.hp = initPack.hp;
self.hpMax = initPack.hpMax;
self.score = initPack.score;
self.dir = initPack.dir;
self.shift = false;
self.sit = false;
self.inInventory = false;
self.ignorePlayerAttack = initPack.ignorePlayerAttacky;
self.drawPlayer = function(){
var x = self.x - Player.list[selfId].x + WIDTH/2;
var y = self.y - Player.list[selfId].y + HEIGHT/2;
// 'player'
var width = 64;
var height = 64;
if (self.sit){
finalWidth = width * self.dir;
finalHeight = height * 4;
} else {
finalWidth = 0;
finalHeight = height * self.dir;
}
ctx.drawImage(Img.player,
finalWidth /* base sprite */, finalHeight,
width, height,
x-width/2, y-height/2,
width, height);
}
self.drawPlayerName = function(){
var x = self.x - Player.list[selfId].x + WIDTH/2;
var y = self.y - Player.list[selfId].y + HEIGHT/2;
var hpWidth = 30 * self.hp / self.hpMax;
// hp-bar
ctx.fillStyle="rgba(255,0,0,0.8)";
ctx.fillRect(x - hpWidth/2, y - 40, hpWidth, 4);
ctx.fillStyle="rgba(75,75,75,0.8)";
var metrics = ctx.measureText(Player.list[self.id].playerName);
ctx.fillText(Player.list[self.id].playerName,
x - metrics.width/2, y - 45, metrics.width, 4);
}
Player.list[self.id] = self;
return self;
};
Player.list = {};
tmxmap=null;
var Bullet = function(initPack){
var self = {};
self.id = initPack.id;
self.x = initPack.x;
self.y = initPack.y;
self.map = initPack.map;
self.dir = initPack.dir;
self.draw = function(){
var width = Img.bullet.width;
var height = Img.bullet.height;
var x = self.x - Player.list[selfId].x + WIDTH/2;
var y = self.y - Player.list[selfId].y + HEIGHT/2;
ctx.drawImage(Img.bullet,
0,0,
width, height,
x-width/2, y-height/2,
width, height);
}
Bullet.list[self.id] = self;
return self;
};
Bullet.list = {};
// init (all)
var selfId = null;
socket.on('init', function(data){
for(var i = 0; i < data.player.length; i++){
new Player(data.player[i]);
}
for(var i = 0; i < data.bullet.length; i++){
new Bullet(data.bullet[i]);
}
if(data.selfId){
selfId = data.selfId;
tmxmap = new TMXLoader(Player.list[selfId].map);
}
});
// update (diff)
socket.on('update', function(data){
for(var i = 0; i < data.player.length; i++){
var pack = data.player[i];
var p = Player.list[pack.id];
if(p){
if(pack.x !== undefined)
p.x = pack.x;
if(pack.y !== undefined)
p.y = pack.y;
if(pack.hp !== undefined)
p.hp = pack.hp;
if(pack.score !== undefined)
p.score = pack.score;
if(pack.dir !== undefined)
p.dir = pack.dir;
if(pack.playerName !== undefined)
p.playerName = pack.playerName;
if(pack.sit !== undefined)
p.sit = pack.sit;
if (pack.inInventory !== undefined)
p.inInventory = pack.inInventory;
if (pack.ignorePlayerAttack != undefined)
p.ignorePlayerAttack = pack.ignorePlayerAttack;
}
}
for(var i = 0; i < data.bullet.length; i++){
var pack = data.bullet[i];
var b = Bullet.list[pack.id];
if(b){
if(pack.x !== undefined)
b.x = pack.x;
if(pack.y !== undefined)
b.y = pack.y;
if(pack.dir !== undefined)
b.dir = pack.dir;
}
}
});
// remove
socket.on('remove', function(data){
for(var i = 0; i < data.player.length; i++){
delete Player.list[data.player[i]];
}
for(var i = 0; i < data.bullet.length; i++){
delete Bullet.list[data.bullet[i]];
}
});
setActiveChatTab = function(tabName, tab){
if (!chatContents[tabName])
chatContents[tabName] = "";
activeChatTab = tabName;
chatText.innerHTML = chatContents[activeChatTab];
Array.from(document.getElementsByClassName("chat-tab")).forEach(function(element, index, array) {
element.setAttribute("id", "");
})
tab.setAttribute("id", "active");
chatText.scrollTop = chatText.scrollHeight;
}
setInterval(function(){
if(!selfId || errno != 0)
return;
ctx.clearRect(0,0,500,500);
drawMapGround();
drawGFXGround();
drawEntities();
drawMapOver();
drawPlayerNames();
drawGFXOver();
drawInventory();
//drawScore();
}, 1000/25);
var drawMapGround = function(){
var x = WIDTH/2 - Player.list[selfId].x;
var y = HEIGHT/2 - Player.list[selfId].y;
tmxmap.drawLayer("ground",x,y);
}
var drawPlayerNames = function(){
for(var i in Player.list){
Player.list[i].drawPlayerName();
}
}
var drawGFXGround = function(){
}
var drawEntities = function(){
for(var i in Player.list){
Player.list[i].drawPlayer();
}
for(var i in Bullet.list){
Bullet.list[i].draw();
}
}
var drawMapOver = function(){
var x = WIDTH/2 - Player.list[selfId].x;
var y = HEIGHT/2 - Player.list[selfId].y;
tmxmap.drawLayer("fringe",x,y); // needs to get rendered on last pos.
tmxmap.drawLayer("over",x,y);
}
var drawGFXOver = function(){
}
var drawInventory = function(){
if(Player.list[selfId].inInventory) {
ui.style.display = 'inline-block';
}
else {
ui.style.display = 'none';
}
}
// TODO Collision
var drawScore = function(){
ctx.fillStyle = 'green';
ctx.fillText(Player.list[selfId].score, 0, 30);
}
document.onkeydown = function(event){
//console.log(event.keyCode);
if (document.activeElement === document.getElementById('ui') ||
document.activeElement === document.getElementById('game') ||
document.activeElement === document.getElementById('ctx')){
// shift
if(event.keyCode === 16)
self.shift = true;
// inventory (i)
if(event.keyCode === 73)
socket.emit('keyPress',{inputId: 'inInventory', state: !Player.list[selfId].inInventory, shift: self.shift});
// movement
if(event.keyCode === 68 || event.keyCode === 39) // d
socket.emit('keyPress',{inputId: 'right', state: true, shift: self.shift});
else if(event.keyCode === 65 || event.keyCode === 37) // a
socket.emit('keyPress',{inputId: 'left', state: true, shift: self.shift});
else if(event.keyCode === 83 || event.keyCode === 40) // s
socket.emit('keyPress',{inputId: 'down', state: true, shift: self.shift});
else if(event.keyCode === 87 || event.keyCode === 38) // w
socket.emit('keyPress',{inputId: 'up', state: true, shift: self.shift});
else if(event.keyCode === 88)
socket.emit('keyPress',{inputId: 'sit', state: !Player.list[selfId].sit, shift: self.shift});
}
}
document.onkeyup = function(event){
// shift
if(event.keyCode === 16)
self.shift = false;
// movement
if(event.keyCode === 68 || event.keyCode === 39) // d
socket.emit('keyPress', {inputId: 'right', state: false, shift: self.shift});
else if(event.keyCode === 65 || event.keyCode === 37) // a
socket.emit('keyPress', {inputId: 'left', state: false, shift: self.shift});
else if(event.keyCode === 83 || event.keyCode === 40) // s
socket.emit('keyPress', {inputId: 'down', state: false, shift: self.shift});
else if(event.keyCode === 87 || event.keyCode === 38) // w
socket.emit('keyPress', {inputId: 'up', state: false, shift: self.shift});
}
document.onmousedown = function(event){
if (document.activeElement === document.getElementById('ui') ||
document.activeElement === document.getElementById('game') ||
document.activeElement === document.getElementById('ctx')){
socket.emit('keyPress',{inputId: 'attack', state: true});
}
}
document.onmouseup = function(event){
socket.emit('keyPress',{inputId: 'attack', state: false});
}
document.onmousemove = function(event){
var x = -250 + event.clientX - 8;
var y = -250 + event.clientY - 8;
var angle = Math.atan2(y, x) / Math.PI * 180;
socket.emit('keyPress',{inputId: 'mouseAngle', state: angle});
}
</script>
</html>