matrix-engine-wgpu
Version:
Networking implemented - based on kurento openvidu server. fix arcball camera,instanced draws added also effect pipeline blend with instancing option.Normalmap added, Fixed shadows casting vs camera/video texture, webGPU powered pwa application. Crazy fas
1,455 lines (1,424 loc) • 1.1 MB
JavaScript
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.HeroProps = exports.Hero = exports.HERO_ARCHETYPES = void 0;
exports.mergeArchetypes = mergeArchetypes;
exports.mergeArchetypesWeighted = mergeArchetypesWeighted;
/**
* @description
* Hero based classes
* Core of RPG type of game.
*/
const HERO_ARCHETYPES = exports.HERO_ARCHETYPES = {
Warrior: {
hpMult: 1.2,
manaMult: 0.8,
attackMult: 1.1,
armorMult: 1.2,
moveSpeed: 1.0,
attackSpeed: 1.0,
hpRegenMult: 1.2,
manaRegenMult: 0.8
},
Tank: {
hpMult: 1.6,
manaMult: 0.6,
attackMult: 0.9,
armorMult: 1.5,
moveSpeed: 0.9,
attackSpeed: 0.8,
hpRegenMult: 1.4,
manaRegenMult: 0.7
},
Assassin: {
hpMult: 0.9,
manaMult: 0.9,
attackMult: 1.5,
armorMult: 0.8,
moveSpeed: 1.3,
attackSpeed: 1.4,
hpRegenMult: 0.9,
manaRegenMult: 0.9
},
Mage: {
hpMult: 0.8,
manaMult: 1.5,
attackMult: 0.9,
armorMult: 0.7,
moveSpeed: 1.0,
attackSpeed: 0.9,
hpRegenMult: 0.8,
manaRegenMult: 1.5
},
Support: {
hpMult: 1.0,
manaMult: 1.2,
attackMult: 0.8,
armorMult: 1.0,
moveSpeed: 1.0,
attackSpeed: 1.0,
hpRegenMult: 1.2,
manaRegenMult: 1.2
},
Ranger: {
hpMult: 1.0,
manaMult: 1.0,
attackMult: 1.2,
armorMult: 0.9,
moveSpeed: 1.2,
attackSpeed: 1.2,
hpRegenMult: 1.0,
manaRegenMult: 1.0
},
Summoner: {
hpMult: 0.9,
manaMult: 1.4,
attackMult: 0.8,
armorMult: 0.9,
moveSpeed: 1.0,
attackSpeed: 0.9,
hpRegenMult: 1.0,
manaRegenMult: 1.4
},
Necromancer: {
hpMult: 0.9,
manaMult: 1.4,
attackMult: 0.9,
armorMult: 0.8,
moveSpeed: 1.0,
attackSpeed: 0.9,
hpRegenMult: 0.9,
manaRegenMult: 1.4
},
Engineer: {
hpMult: 1.1,
manaMult: 1.0,
attackMult: 1.0,
armorMult: 1.1,
moveSpeed: 1.0,
attackSpeed: 1.0,
hpRegenMult: 1.0,
manaRegenMult: 1.0
},
// special for creeps
creep: {
hpMult: 0.6,
manaMult: 1,
attackMult: 1,
armorMult: 1,
moveSpeed: 0.3,
attackSpeed: 0.5,
hpRegenMult: 1,
manaRegenMult: 1
}
};
class HeroProps {
constructor(name) {
this.name = name;
this.levels = [{
level: 1,
xp: 100,
hp: 500,
mana: 300,
attack: 40,
armor: 5,
moveSpeed: 1.0,
attackSpeed: 1.0,
hpRegen: 2.0,
mpRegen: 1.0,
abilityPoints: 1
}, {
level: 2,
xp: 200,
hp: 570,
mana: 345,
attack: 46,
armor: 5.5,
moveSpeed: 1.05,
attackSpeed: 1.05,
hpRegen: 2.25,
mpRegen: 1.15,
abilityPoints: 2
}, {
level: 3,
xp: 350,
hp: 645,
mana: 395,
attack: 52,
armor: 6,
moveSpeed: 1.10,
attackSpeed: 1.10,
hpRegen: 2.52,
mpRegen: 1.31,
abilityPoints: 3
}, {
level: 4,
xp: 500,
hp: 725,
mana: 450,
attack: 58,
armor: 6.5,
moveSpeed: 1.15,
attackSpeed: 1.16,
hpRegen: 2.81,
mpRegen: 1.49,
abilityPoints: 4
}, {
level: 5,
xp: 700,
hp: 810,
mana: 510,
attack: 65,
armor: 7,
moveSpeed: 1.20,
attackSpeed: 1.23,
hpRegen: 3.13,
mpRegen: 1.68,
abilityPoints: 5
}, {
level: 6,
xp: 900,
hp: 900,
mana: 575,
attack: 72,
armor: 7.5,
moveSpeed: 1.25,
attackSpeed: 1.31,
hpRegen: 3.48,
mpRegen: 1.88,
abilityPoints: 6
}, {
level: 7,
xp: 1150,
hp: 995,
mana: 645,
attack: 80,
armor: 8,
moveSpeed: 1.30,
attackSpeed: 1.40,
hpRegen: 3.85,
mpRegen: 2.10,
abilityPoints: 7
}, {
level: 8,
xp: 1400,
hp: 1095,
mana: 720,
attack: 88,
armor: 8.5,
moveSpeed: 1.35,
attackSpeed: 1.50,
hpRegen: 4.25,
mpRegen: 2.33,
abilityPoints: 8
}, {
level: 9,
xp: 1700,
hp: 1200,
mana: 800,
attack: 97,
armor: 9,
moveSpeed: 1.40,
attackSpeed: 1.61,
hpRegen: 4.68,
mpRegen: 2.58,
abilityPoints: 9
}, {
level: 10,
xp: null,
hp: 1310,
mana: 885,
attack: 107,
armor: 9.5,
moveSpeed: 1.45,
attackSpeed: 1.73,
hpRegen: 5.13,
mpRegen: 2.84,
abilityPoints: 10
}];
this.currentLevel = 1;
this.currentXP = 0;
this.gold = 200;
this.baseXP = 100;
this.baseGold = 200;
// --- Multipliers
this.xpMultiplier = {
stronger: 0.1,
weaker: 0.2
};
this.goldMultiplier = 50;
// --- Maximum level difference for XP
this.maxLevelDiffForXP = 3;
this.abilities = [{
name: "Spell 1",
level: 1,
maxLevel: 4
}, {
name: "Spell 2",
level: 0,
maxLevel: 4
}, {
name: "Spell 3",
level: 0,
maxLevel: 4
}, {
name: "Ultimate",
level: 0,
maxLevel: 1
}];
this.invertoryBonus = {
hp: 1,
mana: 1,
attack: 1,
armor: 1,
moveSpeed: 1,
attackSpeed: 1,
hpRegen: 1,
mpRegen: 1
};
this.updateStats();
}
updateStats() {
const lvlData = this.levels[this.currentLevel - 1];
if (!lvlData) return;
// console.log('updateStats: armor ', this.invertoryBonus.armor)
Object.assign(this, {
hp: lvlData.hp * this.invertoryBonus.hp,
mana: lvlData.mana * this.invertoryBonus.mana,
attack: lvlData.attack * this.invertoryBonus.attack,
armor: lvlData.armor * this.invertoryBonus.armor,
moveSpeed: lvlData.moveSpeed * this.invertoryBonus.moveSpeed,
attackSpeed: lvlData.attackSpeed * this.invertoryBonus.attackSpeed,
hpRegen: lvlData.hpRegen * this.invertoryBonus.hpRegen,
mpRegen: lvlData.mpRegen * this.invertoryBonus.mpRegen,
abilityPoints: lvlData.abilityPoints
});
dispatchEvent(new CustomEvent('stats-localhero', {
detail: {
gold: this.gold,
currentLevel: this.currentLevel,
xp: this.currentXP,
hp: this.hp,
mana: this.mana,
attack: this.attack,
armor: this.armor,
moveSpeed: this.moveSpeed,
attackSpeed: this.attackSpeed,
hpRegen: this.hpRegen,
mpRegen: this.mpRegen
}
}));
}
// --- Kill enemy: only enemyLevel argument
killEnemy(enemyLevel) {
if (enemyLevel < 1) enemyLevel = 1;
const levelDiff = this.currentLevel - enemyLevel;
// --- XP calculation with cap for weak enemies
let earnedXP = 0;
if (levelDiff < this.maxLevelDiffForXP) {
if (enemyLevel >= this.currentLevel) {
earnedXP = this.baseXP * (1 + this.xpMultiplier.stronger * (enemyLevel - this.currentLevel));
} else {
earnedXP = this.baseXP * (1 - this.xpMultiplier.weaker * (this.currentLevel - enemyLevel));
}
earnedXP = Math.round(Math.max(0, earnedXP));
}
// --- Gold reward
const goldReward = this.baseGold + enemyLevel * this.goldMultiplier;
this.currentXP += earnedXP;
this.gold += goldReward;
// for creep any way - rule if they kill hero
// maybe some smlall reward... checkLevelUp
console.log(`${this.name} killed Lv${enemyLevel} enemy: +${earnedXP} XP, +${goldReward} gold`);
this.checkLevelUp();
}
// --- Automatic level-up
checkLevelUp() {
while (this.currentLevel < 10) {
const nextLevelXP = this.levels[this.currentLevel - 1].xp;
if (this.currentXP >= nextLevelXP) {
this.currentLevel++;
console.log(`${this.name} leveled up! Now level ${this.currentLevel}`);
this.updateStats();
this.currentXP -= nextLevelXP;
} else break;
}
// emit for hud
// dispatchEvent(new CustomEvent('stats-localhero', {
// detail: {
// gold: this.gold,
// currentLevel: this.currentLevel,
// xp: this.currentXP,
// hp: this.hp,
// mana: this.mana,
// attack: this.attack,
// armor: this.armor,
// moveSpeed: this.moveSpeed,
// attackSpeed: this.attackSpeed,
// hpRegen: this.hpRegen,
// mpRegen: this.mpRegen,
// }
// }))
}
// --- Upgrade abilities
upgradeAbility(spellIndex) {
const spell = this.abilities[spellIndex];
if (!spell) return false;
if (spell.level < spell.maxLevel && this.abilityPoints > 0) {
spell.level++;
this.abilityPoints--;
console.log(`${this.name} upgraded ${spell.name} to level ${spell.level}`);
return true;
}
return false;
}
// --- Get / Set stats
getStat(statName) {
return this[statName] ?? null;
}
setStat(statName, value) {
if (this.hasOwnProperty(statName)) {
this[statName] = value;
return true;
}
return false;
}
// --- Debug print
debugPrint() {
console.table({
level: this.currentLevel,
xp: this.currentXP,
gold: this.gold,
hp: this.hp,
mana: this.mana,
attack: this.attack,
armor: this.armor,
moveSpeed: this.moveSpeed,
attackSpeed: this.attackSpeed,
hpRegen: this.hpRegen,
mpRegen: this.mpRegen,
abilityPoints: this.abilityPoints,
abilities: this.abilities.map(a => `${a.name} (Lv ${a.level})`).join(", ")
});
}
showUpgradeableAbilities() {
if (this.abilityPoints <= 0) {
console.log(`${this.name} has no ability points to spend.`);
return [];
}
const upgradeable = this.abilities.map((spell, index) => ({
...spell,
index
})).filter(spell => spell.level < spell.maxLevel);
if (upgradeable.length === 0) {
console.log(`${this.name} has no spells left to upgrade.`);
return [];
}
console.log(`${this.name} has ${this.abilityPoints} ability point(s) available.`);
console.log("Upgradeable spells:");
upgradeable.forEach(spell => {
console.log(` [${spell.index}] ${spell.name} (Lv ${spell.level}/${spell.maxLevel})`);
});
return upgradeable;
}
// --- Upgrade a spell by name (optional convenience)
upgradeAbilityByName(spellName) {
const spellIndex = this.abilities.findIndex(s => s.name === spellName);
if (spellIndex === -1) return false;
return this.upgradeAbility(spellIndex);
}
// attack - direction always local -> enemy (remote)
calcDamage(attacker, defender, abilityMultiplier = 1.0, critChance = 1, critMult = 1) {
// Use attack from your current scaled stats
const baseAttack = attacker.attack;
// Optional: magic abilities could use mana or another stat later
const base = baseAttack * abilityMultiplier;
// Critical hit roll - not for now
const crit = Math.random() < critChance ? critMult : 1.0;
// Damage reduced by armor
const damage = Math.max(0, base * crit - defender.armor);
// Apply damage
defender.hp = Math.max(0, defender.hp - damage);
// --- Sync energy bar (0 → 1)
const progress = Math.max(0, Math.min(1, defender.hp / this.getHPMax()));
dispatchEvent(new CustomEvent(`onDamage-${defender.name}`, {
detail: {
progress: progress,
attacker: attacker.name,
defenderLevel: defender.currentLevel,
defender: defender.name,
hp: defender.hp,
damage: damage
}
}));
return {
damage,
crit: crit > 1.0
};
}
}
exports.HeroProps = HeroProps;
class Hero extends HeroProps {
constructor(name, archetypes = ["Warrior"]) {
super(name);
// limit to 2 mix
this.archetypes = archetypes.slice(0, 2);
this.applyArchetypeStats();
}
applyArchetypeStats() {
if (!this.archetypes || this.archetypes.length === 0) return;
let typeData;
if (this.archetypes.length === 2) {
typeData = mergeArchetypes(this.archetypes[0], this.archetypes[1]);
} else {
typeData = HERO_ARCHETYPES[this.archetypes[0]];
}
if (!typeData) return;
this.hp *= typeData.hpMult;
this.mana *= typeData.manaMult;
this.attack *= typeData.attackMult;
this.armor *= typeData.armorMult;
this.moveSpeed *= typeData.moveSpeed;
this.attackSpeed *= typeData.attackSpeed;
this.hpRegen *= typeData.hpRegenMult;
this.mpRegen *= typeData.manaRegenMult;
this._mergedArchetype = typeData._mergedFrom || this.archetypes;
}
getHPMax() {
let typeData;
if (this.archetypes.length === 2) {
typeData = mergeArchetypes(this.archetypes[0], this.archetypes[1]);
} else {
typeData = HERO_ARCHETYPES[this.archetypes[0]];
}
this.baseHp = this.levels[this.currentLevel - 1].hp;
return this.baseHp; // * typeData.hpMult; ???
}
// Override updateStats to include archetype scaling
updateStats() {
super.updateStats();
this.applyArchetypeStats();
}
}
exports.Hero = Hero;
function mergeArchetypes(typeA, typeB) {
if (!HERO_ARCHETYPES[typeA] || !HERO_ARCHETYPES[typeB]) {
console.warn(`Invalid archetype(s): ${typeA}, ${typeB}`);
return HERO_ARCHETYPES[typeA] || HERO_ARCHETYPES[typeB];
}
const a = HERO_ARCHETYPES[typeA];
const b = HERO_ARCHETYPES[typeB];
const merged = {};
// Average their multipliers (or tweak with weights if needed)
for (const key in a) {
if (typeof a[key] === "number" && typeof b[key] === "number") {
merged[key] = (a[key] + b[key]) / 2;
}
}
merged._mergedFrom = [typeA, typeB];
return merged;
}
// not used now
function mergeArchetypesWeighted(typeA, typeB, weightA = 0.7) {
const a = HERO_ARCHETYPES[typeA];
const b = HERO_ARCHETYPES[typeB];
const wB = 1 - weightA;
const merged = {};
for (const key in a) if (typeof a[key] === "number" && typeof b[key] === "number") merged[key] = a[key] * weightA + b[key] * wB;
merged._mergedFrom = [typeA, typeB];
return merged;
}
},{}],2:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ROCK_RANK = exports.RCSAccount = void 0;
var _utils = require("../../../src/engine/utils.js");
/**
* @description This is clone from hang3d.
* @author Nikola Lukic
* @email zlatnaspirala@gmail.com
* @website https://maximumroulette.com
*/
class RCSAccount {
email = null;
token = null;
constructor(apiDomain) {
this.apiDomain = apiDomain;
this.visitor();
addEventListener('F12', e => {
console.log(`%c[Debbuger] ${e.detail}`, REDLOG);
localStorage.removeItem("visitor");
this.visitor(e.detail);
});
// this.leaderboardBtn = document.createElement('div')
// this.leaderboardBtn.id = 'leaderboard';
// this.leaderboardBtn.innerHTML = `
// <button id="leaderboardBtn" class="btn">Leaderboard</button>
// `;
// document.body.appendChild(this.leaderboardBtn);
// this.leaderboardBtn = document.getElementById('leaderboardBtn');
// this.leaderboardBtn.addEventListener("click", this.getLeaderboard)
}
createDOM = hideLoginForm => {
if (typeof hideLoginForm === 'undefined') hideLoginForm = false;
var parent = document.createElement('div');
this.parent = parent;
//parent.classList.add('')
parent.id = 'myAccountLoginForm';
if (hideLoginForm == true) parent.style.display = 'none';
var logo = document.createElement('img');
logo.id = 'logologin';
logo.setAttribute('alt', 'Login');
logo.style = 'width: 100px;border-radius: 10px;padding: 6px;';
logo.src = './res/icons/512.png';
var title = document.createElement('div');
title.style.display = 'flex';
title.innerHTML = `
<div style='width:100%; margin: 5px 5px;'> <h2 style='margin: 5px 5px;'>Rocket GamePlay Login Form</h2>
Maximumroulette.com</div>
`;
title.appendChild(logo);
var content = document.createElement('div');
content.style.display = 'flex';
content.style.flexDirection = 'column';
content.style.background = 'transparent';
var emailLabel = document.createElement('label');
emailLabel.id = 'emailLabel';
emailLabel.innerHTML = `Email:`;
emailLabel.setAttribute('for', 'arg-email');
var email = document.createElement('input');
// email.classList.add('myInput')
email.id = 'arg-email';
var passLabel = document.createElement('label');
passLabel.id = 'passLabel';
passLabel.innerHTML = `Passw:`;
passLabel.setAttribute('for', 'arg-pass');
var pass = document.createElement('input');
pass.id = 'arg-pass';
// pass.classList.add('myInput')
var loginBtn = document.createElement('button');
loginBtn.id = 'loginRCSBtn';
loginBtn.innerHTML = `LOGIN`;
loginBtn.classList.add('btn');
loginBtn.classList.add('btnMargin');
loginBtn.addEventListener('click', this.login);
var gotoRegisterMyAccount = document.createElement('button');
gotoRegisterMyAccount.id = 'registerBtn';
gotoRegisterMyAccount.classList.add(`btn`);
gotoRegisterMyAccount.classList.add(`btnMargin`);
gotoRegisterMyAccount.innerHTML = `REGISTER`;
gotoRegisterMyAccount.addEventListener('click', this.register);
var hideLoginMyAccount = document.createElement('button');
hideLoginMyAccount.classList.add(`btn`);
hideLoginMyAccount.classList.add(`btnMargin`);
hideLoginMyAccount.innerHTML = `NO LOGIN -> INSTANT PLAY`;
hideLoginMyAccount.addEventListener('click', () => {
(0, _utils.byId)('myAccountLoginForm').remove();
});
if ((0, _utils.isMobile)() == false) {
var descText = document.createElement('div');
descText.id = 'descText';
descText.style = 'font-size:smaller;';
descText.innerHTML = `<span style="width:45%" >Welcome to rocketCraftingServer platform, enjoy in 'Forest Of Hollow Blood' lets magic begin.</span>`;
// <span style="width:45%;" >Add Url params '?video=false&audio=false' to disable streaming</span>
}
parent.appendChild(title);
parent.appendChild(content);
content.appendChild(emailLabel);
content.appendChild(email);
content.appendChild(passLabel);
content.appendChild(pass);
content.appendChild(loginBtn);
content.appendChild(gotoRegisterMyAccount);
content.appendChild(hideLoginMyAccount);
// content.appendChild(logo)
if ((0, _utils.isMobile)() == false) content.appendChild(descText);
document.body.appendChild(parent);
};
createLeaderboardDOM = data => {
if ((0, _utils.byId)('leaderboard') != null) {
(0, _utils.byId)('leaderboard').style.display = 'block';
return;
}
// console.log('TEST MOBILE +++')
var parent = document.createElement('div');
parent.style = ``;
parent.classList.add('leaderboard');
// if(isMobile() == true) {
// parent.style = `
// position: absolute;
// border-radius: 4px;
// top: 10%;
// left: 0%;
// width: 95%;
// padding: 10px;`;
// }
parent.id = 'leaderboard';
var title = document.createElement('div');
title.innerHTML = `<h3>Top 10 leaderboard [RocketCraftingServer]</h3>`;
parent.appendChild(title);
var tableLabel = document.createElement('div');
tableLabel.style.display = 'flex';
tableLabel.style.flexDirection = 'row';
var nicklabel = document.createElement('div');
nicklabel.innerText = 'Nickname';
nicklabel.style.width = '100%';
var pointslabel = document.createElement('div');
pointslabel.innerText = 'Points';
pointslabel.style.width = '100%';
tableLabel.appendChild(nicklabel);
tableLabel.appendChild(pointslabel);
parent.appendChild(tableLabel);
var parentForTable = document.createElement('div');
parentForTable.style.height = '70vh';
parentForTable.style.overflow = 'scroll';
parentForTable.style.overflowX = 'hidden';
data.forEach((element, index) => {
var table = document.createElement('div');
table.style.display = 'flex';
table.style.flexDirection = 'row';
table.style.justifyContent = 'center';
table.style.alignItems = 'center';
table.style.boxShadow = 'none';
var nick = document.createElement('div');
nick.innerText = element.nickname;
nick.style.width = '100%';
if (index == 0) {
nick.style.boxShadow = '0px 7px 2px -1px #ffe100';
} else if (index == 1) {
nick.style.boxShadow = '0px 7px 2px -1px white';
} else if (index == 2) {
nick.style.boxShadow = '0px 7px 2px -1px #a01010';
} else {
nick.style.boxShadow = '0px 7px 2px -1px #757471';
}
var points = document.createElement('div');
points.innerText = element.points;
points.style.width = '100%';
if (index == 0) {
points.style.boxShadow = '0px 7px 2px -1px #ffe100';
} else if (index == 1) {
points.style.boxShadow = '0px 7px 2px -1px white';
} else if (index == 2) {
points.style.boxShadow = '0px 7px 2px -1px #a01010';
} else {
points.style.boxShadow = '0px 7px 2px -1px #757471';
}
// var medal = document.createElement('img');
// medal.id = 'medal';
// logo.src = './assets/icons/icon96.png';
table.appendChild(nick);
table.appendChild(points);
table.innerHTML += ROCK_RANK.getRankMedalImg(ROCK_RANK.getRank(element.points));
parentForTable.appendChild(table);
});
parent.appendChild(parentForTable);
var hideBtn = document.createElement('button');
hideBtn.classList = 'btn';
hideBtn.style.marginTop = '7px';
hideBtn.innerText = 'HIDE';
hideBtn.addEventListener('click', () => {
parent.style.display = 'none';
});
parent.appendChild(hideBtn);
document.body.appendChild(parent);
};
register = () => {
this.register_procedure(this);
};
async register_procedure() {
let route = this.apiDomain || location.origin;
(0, _utils.byId)('loginRCSBtn').disabled = true;
(0, _utils.byId)('registerBtn').disabled = true;
let args = {
emailField: (0, _utils.byId)('arg-email') != null ? (0, _utils.byId)('arg-email').value : null,
passwordField: (0, _utils.byId)('arg-pass') != null ? (0, _utils.byId)('arg-pass').value : null
};
if (args.emailField == null || args.passwordField == null) {
_utils.mb.show('Please fill up email and passw for login or register.');
}
fetch(route + '/rocket/register', {
method: 'POST',
headers: _utils.jsonHeaders,
body: JSON.stringify(args)
}).then(d => {
return d.json();
}).then(r => {
_utils.mb.error(`${r.message}`);
if (r.message == "Check email for conmfirmation key.") {
this.email = (0, _utils.byId)('arg-email').value;
sessionStorage.setItem('email', (0, _utils.byId)('arg-email').value);
(0, _utils.byId)('emailLabel').remove();
(0, _utils.byId)('loginRCSBtn').remove();
(0, _utils.byId)('arg-email').remove();
(0, _utils.byId)("passLabel").innerHTML = 'ENTER CONFIRMATION CODE';
(0, _utils.byId)('arg-pass').value = "";
(0, _utils.byId)('registerBtn').removeEventListener('click', this.register);
(0, _utils.byId)('registerBtn').disabled = false;
(0, _utils.byId)('registerBtn').innerHTML = 'CONFIRM CODE FROM EMAIL';
(0, _utils.byId)('registerBtn').id = 'CC';
(0, _utils.byId)('CC').addEventListener('click', () => {
this.confirmation();
});
sessionStorage.setItem('RocketAcountRegister', 'Check email for conmfirmation key.');
} else {
setTimeout(() => {
_utils.mb.show("Next Register/Login call try in 5 secounds...");
this.preventDBLOG = false;
this.preventDBREG = false;
(0, _utils.byId)('loginRCSBtn').disabled = false;
(0, _utils.byId)('registerBtn').disabled = false;
}, 5000);
}
}).catch(err => {
console.log('[My Account Error]', err);
_utils.mb.show("Next Register call try in 5 secounds...");
setTimeout(() => {
this.preventDBLOG = false;
this.preventDBREG = false;
(0, _utils.byId)('loginRCSBtn').disabled = false;
(0, _utils.byId)('registerBtn').disabled = false;
}, 5000);
return;
});
}
confirmation = async () => {
let route = this.apiDomain;
const args = {
emailField: this.email,
tokenField: (0, _utils.byId)('arg-pass').value
};
fetch(route + '/rocket/confirmation', {
method: 'POST',
headers: _utils.jsonHeaders,
body: JSON.stringify(args)
}).then(d => {
return d.json();
}).then(r => {
if (r.message == "Wrong confirmation code.") {} else if (r.message == "Confirmation done.") {
alert(r.message);
this.parent.innerHTML = '';
// ----
this.createDOM();
}
_utils.mb.error(`${r.message}`);
});
};
gameStarted = async () => {
let route = this.apiDomain || location.origin;
let args = {
username: 'guest'
};
fetch(route + '/rocket/fohbstart', {
method: 'POST',
headers: _utils.jsonHeaders,
body: JSON.stringify(args)
}).then(d => {
return d.json();
}).then(r => {
console.log(r.message);
_utils.mb.show(`${r.message}`);
if (r.message == "User logged") {}
}).catch(err => {
console.log('[RCS Error]', err);
return;
});
};
login = async () => {
let route = this.apiDomain || location.origin;
(0, _utils.byId)('loginRCSBtn').disabled = true;
(0, _utils.byId)('registerBtn').disabled = true;
let args = {
emailField: (0, _utils.byId)('arg-email') != null ? (0, _utils.byId)('arg-email').value : null,
passwordField: (0, _utils.byId)('arg-pass') != null ? (0, _utils.byId)('arg-pass').value : null
};
fetch(route + '/rocket/login', {
method: 'POST',
headers: _utils.jsonHeaders,
body: JSON.stringify(args)
}).then(d => {
return d.json();
}).then(r => {
console.log(r.message);
_utils.mb.show(`${r.message}`);
if (r.message == "User logged") {
this.email = (0, _utils.byId)('arg-email').value;
(0, _utils.byId)('myAccountLoginForm').style.display = 'none';
sessionStorage.setItem('RocketAcount', JSON.stringify(r.flag));
}
}).catch(err => {
console.log('[My Account Error]', err);
_utils.mb.show("Next Login call try in 5 secounds...");
setTimeout(() => {
this.preventDBLOG = false;
this.preventDBREG = false;
(0, _utils.byId)('registerBtn').disabled = false;
(0, _utils.byId)('loginRCSBtn').disabled = false;
}, 5000);
return;
});
};
async visitor(isRegular) {
if (typeof isRegular === 'undefined') isRegular = 'Yes';
if (localStorage.getItem("visitor") == 'welcome') return;
let route = this.apiDomain;
let args = {
email: (0, _utils.byId)('arg-email') != null ? (0, _utils.byId)('arg-email').value : 'no-email',
userAgent: navigator.userAgent.toString(),
fromUrl: location.href.toString(),
isRegular: isRegular
};
fetch(route + '/rocket/visitors', {
method: 'POST',
headers: _utils.jsonHeaders,
body: JSON.stringify(args)
}).then(d => {
return d.json();
}).then(() => {
localStorage.setItem("visitor", "welcome");
}).catch(err => {
console.log('ERR', err);
});
}
getLeaderboard = async e => {
e.preventDefault();
(0, _utils.byId)('netHeaderTitle').click();
// this.leaderboardBtn.disabled = true;
fetch(this.apiDomain + '/rocket/public-leaderboard', {
method: 'POST',
headers: _utils.jsonHeaders,
body: JSON.stringify({})
}).then(d => {
return d.json();
}).then(r => {
_utils.mb.error(`${r.message}`);
if (r.message == "You got leaderboard data.") {
this.leaderboardData = r.leaderboard;
this.createLeaderboardDOM(r.leaderboard);
}
// setTimeout(() => {this.leaderboardBtn.disabled = false}, 5000)
}).catch(err => {
console.log('[Leaderboard Error]', err);
_utils.mb.show("Next call try in 5 secounds...");
// setTimeout(() => {this.leaderboardBtn.disabled = false}, 5000)
return;
});
};
getLeaderboardFor3dContext = async e => {
// e.preventDefault();
fetch(this.apiDomain + '/rocket/public-leaderboard', {
method: 'POST',
headers: _utils.jsonHeaders,
body: JSON.stringify({})
}).then(d => {
return d.json();
}).then(r => {
_utils.mb.error(`${r.message}`);
if (r.message == "You got leaderboard data.") {
this.leaderboardData = r.leaderboard;
console.log('PREPARE FOR 3d context', this.leaderboardData);
}
setTimeout(() => {
this.leaderboardBtn.disabled = false;
}, 5000);
}).catch(err => {
console.log('[Leaderboard Error]', err);
_utils.mb.show("Next call try in 5 secounds...");
setTimeout(() => {
this.leaderboardBtn.disabled = false;
}, 5000);
return;
});
};
async points10() {
let route = this.apiDomain;
if (sessionStorage.getItem('RocketAcount') != null && JSON.parse(sessionStorage.getItem('RocketAcount')).token) {
console.log("NO ACCOUNT USER", sessionStorage.getItem('RocketAcount'));
return;
}
let args = {
email: (0, _utils.byId)('arg-email') != null ? (0, _utils.byId)('arg-email').value : 'no-email',
userAgent: navigator.userAgent.toString(),
fromUrl: location.href.toString(),
token: JSON.parse(sessionStorage.getItem('RocketAcount')).token,
mapName: 'FOHB'
};
fetch(route + '/rocket/point-plus10', {
method: 'POST',
headers: _utils.jsonHeaders,
body: JSON.stringify(args)
}).then(d => {
return d.json();
}).then(() => {
localStorage.setItem("visitor", "welcome");
}).catch(err => {
console.log('ERR', err);
});
}
async dead() {
let route = this.apiDomain;
if (sessionStorage.getItem('RocketAcount') != null && JSON.parse(sessionStorage.getItem('RocketAcount')).token) {
console.log("NO ACCOUNT USER", sessionStorage.getItem('RocketAcount'));
return;
}
let args = {
email: (0, _utils.byId)('arg-email') != null ? (0, _utils.byId)('arg-email').value : 'no-email',
userAgent: navigator.userAgent.toString(),
fromUrl: location.href.toString(),
token: JSON.parse(sessionStorage.getItem('RocketAcount')).token,
mapName: 'FOHB'
};
fetch(route + '/rocket/point-plus10', {
method: 'POST',
headers: _utils.jsonHeaders,
body: JSON.stringify(args)
}).then(d => {
return d.json();
}).then(() => {
localStorage.setItem("visitor", "welcome");
}).catch(err => {
console.log('ERR', err);
});
}
}
exports.RCSAccount = RCSAccount;
var ROCK_RANK = exports.ROCK_RANK = {
getRank: points => {
points = parseInt(points);
if (points < 1001) {
return "junior";
} else if (points < 2000) {
return "senior";
} else if (points < 3000) {
return "captain";
} else if (points < 5000) {
return "general";
} else {
return "ultimate-killer";
}
},
getRankMedalImg: rank => {
if (rank == 'junior') {
return `<img style="height: 60px" src="./res/icons/medals/1.png" />`;
} else if (points == 'senior') {
return `<img style="height: 60px" src="./res/icons/medals/2.png" />`;
} else if (points == 'captain') {
return `<img style="height: 60px" src="./res/icons/medals/3.png" />`;
} else if (points == 'general') {
return `<img style="height: 60px" src="./res/icons/medals/4.png" />`;
} else {
return `<img style="height: 60px" src="./res/icons/medals/5.png" />`;
}
}
};
},{"../../../src/engine/utils.js":47}],3:[function(require,module,exports){
"use strict";
var _webgpuGltf = require("../../../src/engine/loaders/webgpu-gltf.js");
var _net = require("../../../src/engine/networking/net.js");
var _utils = require("../../../src/engine/utils.js");
var _world = _interopRequireDefault(require("../../../src/world.js"));
var _hero = require("./hero.js");
var _animatedCursor = require("../../../src/engine/plugin/animated-cursor/animated-cursor.js");
var _matrixStream = require("../../../src/engine/networking/matrix-stream.js");
var _rocketCraftingAccount = require("./rocket-crafting-account.js");
var _enBackup = require("../../../public/res/multilang/en-backup.js");
var _tts = require("./tts.js");
var _editor = require("../../../src/tools/editor/editor.js");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* @name forestOfHollowBloodStartSceen
*
* @licence
* Creative Commons Attribution 4.0 International (CC BY 4.0)
* You are free to share and adapt this project, provided that you give appropriate credit.
* Attribution requirement:
* Include the following notice (with working link) in any distributed version or about page:
*
* "Forest Of Hollow Blood — an RPG example made with MatrixEngineWGPU (https://github.com/zlatnaspirala/matrix-engine-wgpu)"
* @Note
* “Character and animation assets from Mixamo,
* used under Adobe’s royalty‑free license.
* Redistribution of raw assets is not permitted.”
*
* @Note
* This is startup main instance for menu screen and for the game.
* All @zlatnaspirala software use networking based
* on openvidu/kurento media server(webRTC).
* Node.js used for middleware.
* Server Events API also used for helping in creation of
* matching/waiting list players or get status of public channel
* (game-play channel).
*
* @note
* Only last non selected hero player will get
* first free hero in selection action next/back.
* For now. Next better varian can be timer solution.
*
* @Backend Session account stuff.
* RocketCraftingServer platform used.
**/
_utils.LS.clear();
_utils.SS.clear();
let forestOfHollowBloodStartSceen = new _world.default({
dontUsePhysics: true,
// useEditor: true,
useSingleRenderPass: true,
canvasSize: 'fullscreen',
// {w: window.visualViewport.width, h: window.visualViewport.height }
mainCameraParams: {
type: 'WASD',
responseCoef: 1000
},
clearColor: {
r: 0,
b: 0.1,
g: 0.1,
a: 1
}
}, forestOfHollowBloodStartSceen => {
if ('serviceWorker' in navigator) {
if (location.hostname.indexOf('localhost') == -1) {
navigator.serviceWorker.register('cache.js');
} else {
// RCSAccount
navigator.serviceWorker.getRegistrations().then(function (registrations) {
for (let registration of registrations) {
registration.unregister();
}
});
}
} else {
console.warn('Matrix Engine WGPU : No support for web workers in this browser.');
}
forestOfHollowBloodStartSceen.tts = new _tts.MatrixTTS();
forestOfHollowBloodStartSceen.account = new _rocketCraftingAccount.RCSAccount("https://maximumroulette.com");
forestOfHollowBloodStartSceen.account.createDOM();
forestOfHollowBloodStartSceen.FS = new _utils.FullscreenManager();
forestOfHollowBloodStartSceen.gamePlayStatus = null;
// in future replace with server event solution
forestOfHollowBloodStartSceen.gamePlayStatusTimer = null;
forestOfHollowBloodStartSceen.heroByBody = [];
forestOfHollowBloodStartSceen.selectedHero = 0;
forestOfHollowBloodStartSceen.lock = false;
// Audios
forestOfHollowBloodStartSceen.matrixSounds.createAudio('music2', 'res/audios/rpg/music.mp3', 1);
forestOfHollowBloodStartSceen.matrixSounds.createAudio('music', 'res/audios/rpg/wizard-rider.mp3', 1);
forestOfHollowBloodStartSceen.matrixSounds.createAudio('click1', 'res/audios/click1.mp3', 1);
app.matrixSounds.audios.click1.volume = 0.2;
forestOfHollowBloodStartSceen.matrixSounds.createAudio('hover', 'res/audios/kenney/mp3/click3.mp3', 2);
forestOfHollowBloodStartSceen.matrixSounds.createAudio('feel', 'res/audios/rpg/feel.mp3', 2);
let heros = null;
function checkUsername() {
if (JSON.parse(_utils.SS.get('RocketAcount')) != null && typeof JSON.parse(_utils.SS.get('RocketAcount')).nickname !== 'undefined') {
return JSON.parse(_utils.SS.get('RocketAcount')).nickname;
} else {
if (app.net.session !== null) {
return app.net.session.connection.connectionId;
} else {
return 'nosession';
}
}
}
// Networking
forestOfHollowBloodStartSceen.net = new _net.MatrixStream({
active: true,
domain: 'maximumroulette.com',
port: 2020,
sessionName: 'forestOfHollowBlood-free-for-all-start',
resolution: '160x240',
isDataOnly: true
});
function handleHeroImage(selectHeroIndex) {
// func exist in case of changinf hero names...
let name = 'no-name';
if (selectHeroIndex == 0) {
name = 'mariasword';
} else if (selectHeroIndex == 1) {
name = 'slayzer';
} else if (selectHeroIndex == 2) {
name = 'steelborn';
} else if (selectHeroIndex == 3) {
name = 'warrok';
} else if (selectHeroIndex == 4) {
name = 'skeletonz';
} else if (selectHeroIndex == 5) {
name = 'erika';
} else if (selectHeroIndex == 6) {
name = 'arissa';
}
return name;
}
function checkHeroStatus() {
const indices = [];
document.querySelectorAll('[data-hero-index]').forEach(elem => {
const index = parseInt(elem.getAttribute('data-hero-index'));
indices.push(index);
});
// check if any value appears more than once
const hasDuplicate = indices.some((val, i) => indices.indexOf(val) !== i);
return hasDuplicate;
}
function determinateTeam() {
console.log('check remote conn.app.net.session.remoteConnections.size..', app.net.session.remoteConnections.size);
if (app.net.session.remoteConnections.size == 0) {
// Rule - even -> south team odd -> north team
return "south";
} else {
if ((0, _utils.isOdd)(app.net.session.remoteConnections.size) == true) {
return "north";
} else {
return "south";
}
}
}
function determinateSelection() {
if (app.net.session.connection != null) {
// console.log("Test team data moment", byId(`waiting-${app.net.session.connection.connectionId}`).getAttribute('data-hero-team'))
let testDom = (0, _utils.byId)(`waiting-${app.net.session.connection.connectionId}`).getAttribute('data-hero-team');
if (typeof testDom != 'string') {
console.log('Potencial error not handled....');
}
app.net.sendOnlyData({
type: "selectHeroIndex",
selectHeroIndex: app.selectedHero,
team: testDom
});
}
// fix for local
if ((0, _utils.byId)(`waithero-img-${app.net.session.connection.connectionId}`)) {
let heroImage = (0, _utils.byId)(`waithero-img-${app.net.session.connection.connectionId}`);
heroImage.src = `./res/textures/rpg/hero-image/${handleHeroImage(app.selectedHero)}.png`;
heroImage.setAttribute('data-hero-index', app.selectedHero);
} else {
let heroImage = document.createElement('img');
heroImage.setAttribute('data-hero-index', app.selectedHero);
heroImage.id = `waithero-img-${app.net.session.connection.connectionId}`;
heroImage.width = '64';
heroImage.height = '64';
heroImage.src = `./res/textures/rpg/hero-image/${handleHeroImage(app.selectedHero)}.png`;
(0, _utils.byId)(`waiting-${app.net.session.connection.connectionId}`).appendChild(heroImage);
}
// Only last non selected hero player will get
// first free hero in selection action next/back.
// For now.
if (checkHeroStatus() == true) {
console.log("hero used keep graphics no send");
return;
}
if (isAllSelected() == true) {
forestOfHollowBloodStartSceen.gotoGamePlay();
}
}
forestOfHollowBloodStartSceen.determinateSelection = determinateSelection;
function isAllSelected() {
let sumParty = document.querySelectorAll('[id*="waiting-"]');
let testSelection = document.querySelectorAll('[id*="waithero-img-"]');
console.info(testSelection, ' testSelection vs Number of players:', sumParty);
if (sumParty.length == forestOfHollowBloodStartSceen.MINIMUM_PLAYERS) {
// good all are still here
if (testSelection.length == forestOfHollowBloodStartSceen.MINIMUM_PLAYERS) {
// good all selected hero !PLAY!
return true;
} else {
_utils.mb.error(`No selection hero for all players...`);
return false;
}
} else {
_utils.mb.error(`No enough players...`);
return false;
}
}
forestOfHollowBloodStartSceen.gotoGamePlay = preventEmit => {
setTimeout(() => {
// check again ! good all selected hero !PLAY!
// console.log('...', byId(`waiting-${app.net.session.connection.connectionId}`));
_utils.LS.set('player', {
mesh: heros[app.selectedHero].meshName,
hero: heros[app.selectedHero].name,
path: heros[app.selectedHero].path,
archetypes: [heros[app.selectedHero].type],
team: (0, _utils.byId)(`waiting-${app.net.session.connection.connectionId}`).getAttribute('data-hero-team'),
data: Date.now(),
numOfPlayers: forestOfHollowBloodStartSceen.MINIMUM_PLAYERS,
useCameraOrAudio: true
});
_utils.SS.set('player', {
mesh: heros[app.selectedHero].meshName,
hero: heros[app.selectedHero].name,
path: heros[app.selectedHero].path,
archetypes: [heros[app.selectedHero].type],
team: (0, _utils.byId)(`waiting-${app.net.session.connection.connectionId}`).getAttribute('data-hero-team'),
data: Date.now(),
numOfPlayers: forestOfHollowBloodStartSceen.MINIMUM_PLAYERS,
useCameraOrAudio: true
});
if (typeof preventEmit === 'undefined') forestOfHollowBloodStartSceen.net.sendOnlyData({
type: 'start'
});
location.assign('rpg-game.html');
}, 1000);
};
if ('connection' in navigator && navigator.connection) {
navigator.connection.onchange = e => {
console.info('Network state changed...', e);
if (e.target.downlink < 0.4) {
(0, _utils.byId)('loader').style.display = 'block';
(0, _utils.byId)('loader').style.fontSize = '150%';
(0, _utils.byId)('loader').innerHTML = `NO INTERNET CONNECTIONS`;
setTimeout(() => {
location.href = 'https://maximumroulette.com';
}, 3000);
}
};
}
addEventListener('check-gameplay-channel', e => {
let info = e.detail;
if (info.status != 'false' && typeof info.status !== "undefined") {
// console.log('check-gameplay-channel status:', info.status)
(0, _utils.byId)("onlineUsers").innerHTML = `GamePlay:Free`;
forestOfHollowBloodStartSceen.gamePlayStatus = "free";
(0, _utils.byId)('startBtnText').innerHTML = app.label.get.play;
(0, _utils.byId)("startBtnText").style.color = 'rgba(0, 0, 0, 0)';
clearInterval(forestOfHollowBloodStartSceen.gamePlayStatusTimer);
forestOfHollowBloodStartSceen.gamePlayStatusTimer = null;
} else {
// console.log('check-gameplay-channel status:', info.status)
if (typeof info.status != "undefined" && info.status == "false") {
// no internet
(0, _utils.byId)('loader').style.display = 'block';
alert("This is modal window, No internet connection... Please try ");
} else {
info = JSON.parse(e.detail);
if (info.connections && info.connections.numberOfElements == 0) {
(0, _utils.byId)("onlineUsers").innerHTML = `GamePlay:Free`;
forestOfHollowBloodStartSceen.gamePlayStatus = "free";
(0, _utils.byId)('startBtnText').innerHTML = app.label.get.play;
(0, _utils.byId)("startBtnText").style.color = 'rgba(0, 0, 0, 0)';
clearInterval(forestOfHollowBloodStartSceen.gamePlayStatusTimer);
forestOfHollowBloodStartSceen.gamePlayStatusTimer = null;
return;
}
(0, _utils.byId)("onlineUsers").innerHTML = `${app.label.get.alreadyingame}:${info.connections.numberOfElements}`;
forestOfHollowBloodStartSceen.gamePlayStatus = "used";
(0, _utils.byId)('startBtnText').innerHTML = `${app.label.get.gameplaychannel}:${app.label.get.used}`;
(0, _utils.byId)("startBtnText").style.color = 'rgb(255 53 53)';
forestOfHollowBloodStartSceen.gamePlayStatusTimer = setTimeout(() => {
app.net.fetchInfo('forestOfHollowBlood-free-for-all');
}, 30000);
}
}
});
forestOfHollowBloodStartSceen.MINIMUM_PLAYERS = location.hostname.indexOf('localhost') != -1 ? 2 : 4;
forestOfHollowBloodStartSceen.setWaitingList = () => {
// access net doms who comes with broadcaster2.html
const waitingForOthersDOM = document.createElement("div");
waitingForOthersDOM.id = "waitingForOthersDOM";
Object.assign(waitingForOthersDOM.style, {
flexFlow: 'wrap',
width: "100%",
height: "35%",
backgroundColor: "rgba(60, 60, 60, 1)",
display: "flex",
alignItems: "center",
justifyContent: "space-around",
color: "white",
fontFamily: "'Orbitron', sans-serif",
zIndex: "1",
fontSize: '20px',
padding: "10px",
boxSizing: "border-box"
});
(0, _utils.byId)('session-header').appendChild(waitingForOthersDOM);
const onlineUsers = document.createElement("div");
onlineUsers.id = "onlineUsers";
Object.assign(onlineUsers.style, {
flexFlow: 'wrap',
width: "100%",
height: "35%",
backgroundColor: "rgba(60, 60, 60, 1)",
display: "flex",
alignItems: "center",
justifyContent: "space-around",
color: "white",
fontFamily: "'Orbitron', sans-serif",
zIndex: "1",
fontSize: '20px',
padding: "10px",
boxSizing: "border-box"
});
(0, _utils.byId)('netHeader').appendChild(onlineUsers);
// app.net.fetchInfo('forestOfHollowBlood-free-for-all');
};
if (document.querySelector('.form-group')) document.querySelector('.form-group').style.display = 'none';
// keep simple all networking code on top level
// all job will be done with no account for now.
addEventListener('net-ready', () => {
(0, _utils.byId)('matrix-net').style.opacity = '0.75';
document.querySelector('.form-group').style.display = 'none';
(0, _utils.byId)("caller-title").innerHTML = `forestOfHollowBlood`;
(0, _utils.byId)("sessionName").disabled = true;
forestOfHollowBloodStartSceen.setWaitingList();
// check game-play channel
setTimeout(() => {
app.net.fetchInfo('forestOfHollowBlood-free-for-all');
app.sendmsg = m => {
if (typeof m != 'string') return;
if (m.length > 120) return;
let username = checkUsername();
if (username != 'nosession') app.net.sendOnlyData({
type: "chat",
msg: m,
username: username
});
};
}, 1500);
});
addEventListener('connectionDestroyed', e => {
(0, _utils.byId)(`waiting-${e.detail.connectionId}`).remove();
});
addEventListener("onConnectionCreated", e => {
console.log('newconn : created', e.detail);
let newPlayer = document.createElement('div');
if (app.net.session.connection.connectionId == e.detail.connection.connectionId) {
console.log('newconn : created [LOCAL] determinate team');
document.title = app.net.session.connection.connectionId;
let team = determinateTeam();
newPlayer.setAttribute('data-hero-team', team);
newPlayer.innerHTML = `<div id="${e.detail.connection.connectionId}-title" >Player:${e.detail.connection.connectionId} Team:${team}</div>`;
setTimeout(() => {
//---------- test
if (app.net.session.connection != null) {
console.log("Test team data moment", (0, _utils.byId)(`waiting-${app.net.session.connection.connectionId}`).getAttribute('data-hero-team'));
let testDom = (0, _utils.byId)(`waiting-${app.net.session.connection.connectionId}`).getAttribute('data-hero-team');
if (typeof testDom != 'string') {
console.low('Potencial error not handled....');
}
app.net.sendOnlyData({
type: "selectHeroIndex",
selectHeroIndex: app.selectedHero,
team: testDom
});
app.net.sendOnlyData({
type: "team-notify",
team: team
});
}
}, 2000);
} else {
newPlayer.innerHTML = `<div id="${e.detail.connection.connectionId}-title" >Player:${e.detail.connection.connectionId}</div>`;
}
newPlayer.id = `waiting-${e.detail.connection.connectionId}`;
(0, _utils.byId)('waitingForOthersDOM').appendChild(newPlayer);
let testParty = document.querySelectorAll('[id*="waiting-"]');
console.info('Test number of players:', testParty);
if (testParty.length == forestOfHollowBloodStartSceen.MINIMUM_PLAYERS) {
// when all choose hero goto play
_utils.mb.success(`Consensus is reached. Party${forestOfHollowBloodStartSceen.MINIMUM_PLAYERS}
When all player select hero gameplay starts.
`);
} else if (testParty.length < forestOfHollowBloodStartSceen.MINIMUM_PLAYERS) {
_utils.mb.success(`Player ${e.detail.connection.connectionId} joined part