function hours (hours, tick) {
if (tick == undefined) { tick = 1; }
return (hours*60*60*1000)/tick;
}
class petStat {
constructor(value,min,max) {
var myValue;
var myMin = Number.NEGATIVE_INFINITY;
var myMax = Number.POSITIVE_INFINITY;
function checkBounds(value) {
if (value > myMax) { return [myMax, value - myMax]; }
if (value < myMin) { return [myMin, value - myMin];}
return [value,0];
}
if (typeof min == "number") { myMin = min; }
if ((typeof max == "number" ) && ( max >= min )) { myMax = max; }
myValue = checkBounds(value)[0];
// Public Methods
this.setValue = function (newVal) {
var bounded = checkBounds(newVal);
myValue = bounded[0];
return bounded[1];
};
this.setBounds = function (lower,upper) {
if ((typeof lower == "number") && (typeof upper == "number") && (lower < upper)) {
myMin = lower;
myMax = upper;
checkBounds();
}
return [myMin,myMax];
};
this.getValue = function () {
return myValue;
};
this.modValue = function (mod) {
var bounded = checkBounds(myValue+mod);
myValue = bounded[0];
return bounded[1];
};
this.percent = function () {
return myValue/myMax;
};
}
};
class statBar {
constructor(parentID,type,value) {
var myParent = "body";
var myType = "StatBar";
var myValue = 0.5;
var mySel = "";
if (typeof value == "number") { myValue = value; }
if (typeof parentID == "string") { myParent = parentID; mySel="#"; }
if (typeof type == "string") { myType = type; }
var current = new petStat(myValue,0,1);
var myBack = elementPlace(mySel+myParent, myParent+"_"+myType, "statbar_back", "div");
var myFill = elementPlace("#"+myParent+"_"+myType, null, "statbar_fill "+myType, "div");
this.update = function (newVal) {
current.setValue(newVal);
myFill.style.width = (current.getValue()*100)+"%";
myFill.innerText = myType+" "+Math.floor(current.getValue()*100)+"%";
}
}
};
class pet {
constructor(dna) {
var me = this;
//Initialise Private values
var myDNA = {
"gender":Math.round(Math.random()),
"health":(Math.round(Math.random()*20)+80),
"endurance":(Math.round(Math.random()*50)+50),
"heartiness":(Math.random()*100)
};
if (typeof dna == "object") {
if (typeof dna["gender"] == "object") { myDNA["gender"] = dna["gender"][Math.round(Math.random())]; }
if (typeof dna["health"] == "object") { myDNA["health"] = dna["health"][Math.round(Math.random())]; }
if (typeof dna["endurance"] == "object") { myDNA["endurance"] = dna["endurance"][Math.round(Math.random())]; }
if (typeof dna["heartiness"] == "object") { myDNA["heartiness"] = dna["heartiness"][Math.round(Math.random())]; }
}
var birth = new Date();
var petID = "pet_"+birth.valueOf();
var name = petID;
var tickTime = 50;
var lifeStageIndex = ["egg","baby","toddler","kid","teen","adult","midaged","old"];
var lifeStage = 0;
var lifeMax = hours(168,tickTime); //168 hours *should* be 7 days
var lifeStageTime = hours(0.5,tickTime);
var lifeTimeCurrent = 0;
var statHp = new petStat(myDNA["health"],0,myDNA["health"]);
var statGender = new petStat(myDNA["gender"],0,1);
var statHunger = new petStat(1,0,myDNA["endurance"]);
var statThurst = new petStat(1,0,myDNA["endurance"]);
var statMood = new petStat(0,-100,100);
var statHeart = new petStat(myDNA["heartiness"],50,200);
var statActive = new petStat(Math.random()*(myDNA["heartiness"]+myDNA["endurance"]),0,(myDNA["heartiness"]+myDNA["endurance"]));
var statEnergy = new petStat(1,0,statActive.getValue());
var foodBowl = new petStat(75000,0,250000);
var waterBowl = new petStat(75000,0,250000);
var guiPetID = elementPlace("#petPin", petID, "petContainer","div");
var guiPetIconID = elementPlace("#"+petID,null,"gender_"+statGender.getValue()+" egg","div");
guiPetIconID.onclick = function () { me.nameChange(); };
var guiActionQueueID = elementPlace("#"+petID,null,"actionQueue","div");
var guiActionCurrentID = elementPlace("#"+petID,null,"actionCurrent","div");
var guiBowlID = elementPlace("#"+petID,petID+"_bowl_tray","bowl_tray","div");
var guiBowlFood = new statBar(petID+"_bowl_tray","food");
var guiBowlWater = new statBar(petID+"_bowl_tray","water");
var guiActionMenuID = elementPlace("#"+petID,petID+"_actions","actionMenu","div");
var guiActionFeedID = elementPlace("#"+petID+"_actions",null,"button feed disabled", "div");
guiActionFeedID.innerText = "F";
guiActionFeedID.onclick = function () { me.actionAdd("feed"); };
var guiActionWaterID = elementPlace("#"+petID+"_actions",null,"button water disabled", "div");
guiActionWaterID.innerText = "W";
guiActionWaterID.onclick = function () { me.actionAdd("water"); };
var guiStatsID = elementPlace("#"+petID,petID+"_stats","statsContainer","div");
var guiStatAge = elementPlace("#"+petID,null,"age", "div");
var guiStatHp = new statBar(petID+"_stats","health");
var guiStatHunger = new statBar(petID+"_stats","hunger");
var guiStatThurst = new statBar(petID+"_stats","thirst");
var guiStatEnergy = new statBar(petID+"_stats","energy");
var guiStatMood = new statBar(petID+"_stats","mood");
var actionQueue = [];
var actionCurrent = "";
//Private Methods
function tickToTime (ticks) {
var days = ((((Math.abs(ticks)*tickTime)/1000)/60)/60)/24;
var hours = (days%1)*24;
var minutes = (hours%1)*60;
var seconds = (minutes%1)*60;
return Math.floor(days)+"D "+Math.floor(hours).toString().padStart(2,"0")+":"+Math.floor(minutes).toString().padStart(2,"0")+":"+Math.floor(seconds).toString().padStart(2,"0");
}
function updateGui() {
guiActionCurrentID.innerText = actionCurrent+"ing";
guiStatHp.update(statHp.percent());
guiStatHunger.update(statHunger.percent());
guiStatThurst.update(statThurst.percent());
guiStatEnergy.update(statEnergy.percent());
guiStatMood.update((statMood.percent()/2)+0.5);
guiBowlFood.update(foodBowl.percent());
guiBowlWater.update(waterBowl.percent());
guiStatAge.innerText = tickToTime(lifeTimeCurrent - hours(0.5,tickTime));
}
function tickMe() {
var elapsedMS = ((new Date - birth.getTime()) - (lifeTimeCurrent*tickTime))/tickTime;
for (;elapsedMS > 0;elapsedMS--) {
lifeTimeCurrent++;
lifeStageTime--;
if (lifeStageTime <= 0) { age(); }
if (lifeStage > 0) { // Eggs don't need food or water.
actionDo();
if (statEnergy.getValue() < 5 && actionQueue.includes("rest") == false) {
"rest,".repeat(9).split(",").forEach(function (e) { actionQueue.push(e);});
}
if (statThurst.getValue() > 5 && actionQueue.includes("drink") == false) {
"drink,".repeat(4).split(",").forEach(function (e) { actionQueue.push(e);});
}
if (statHunger.getValue() > 5 && actionQueue.includes("eat") == false) {
"eat,".repeat(4).split(",").forEach(function (e) { actionQueue.push(e);});
}
} else { // Do this while its an egg
actionCurrent = "Incubat";
statHp.setValue((statHp.setBounds()[1]+1)-((lifeStageTime/hours(0.5,tickTime))*statHp.setBounds()[1]));
}
}
updateGui();
}
function hurt (amount) {
window.gameDB.message(name+" is taking damage!",2,tickTime );
var pain = statHp.modValue(-amount);
if (pain < 0) {
return die();
} else {
return emotion(-pain); // This kind of doesn't do anything...
}
}
function drink (amount) {
if ((statEnergy.getValue() >= amount) && (waterBowl.getValue() >= amount)) {
hurt(statHunger.modValue(amount*0.2));
statEnergy.modValue(-amount);
waterBowl.modValue(-amount);
return statThurst.modValue(-amount);
} else {
actionQueue.push("drink");
actionCurrent = "rest";
var energyDef = statEnergy.modValue(-amount);
var waterDef = waterBowl.modValue(-amount);
if (energyDef < waterDef) { return statThurst.modValue(-(amount+energyDef));
} else { return statThurst.modValue(-(amount+waterDef)); }
}
}
function eat (amount) {
if ((statEnergy.getValue() >=amount) && (foodBowl.getValue() >= amount)) {
hurt(statThurst.modValue(amount*0.2));
statEnergy.modValue(-amount);
foodBowl.modValue(-amount);
return statHunger.modValue(-amount);
} else {
actionQueue.push("eat");
actionCurrent = "rest";
var energyDef = statEnergy.modValue(-amount);
var foodDef = foodBowl.modValue(-amount);
if (energyDef < foodDef) { return statHunger.modValue(-(amount+energyDef));
} else { return statHunger.modValue(-(amount+foodDef));}
}
}
function play (amount) {
if (statEnergy.getValue() >= amount*3) {
hurt(statHunger.modValue(amount));
hurt(statThurst.modValue(amount));
hurt(statEnergy.modValue(-amount*3));
return emotion(amount);
} else {
actionQueue.push("play");
actionCurrent = "rest";
}
}
function rest (amount) {
hurt(statHunger.modValue(amount*0.3));
hurt(statThurst.modValue(amount*0.3));
return statHp.modValue(statEnergy.modValue((amount)*(statHp.percent()+statMood.percent())));
}
function emotion (amount) {
var adjustedAmount = amount - (amount * (statMood.getValue() / 100));
statMood.modValue(adjustedAmount);
// statMood.modValue(Math.sqrt( (statMood.getValue() + amount) / 200));
}
function age () {
lifeStage++;
if (lifeStage > lifeStageIndex.length-1) { return die(); }
guiPetIconID.classList.replace(lifeStageIndex[lifeStage - 1],lifeStageIndex[lifeStage]);
//Change stats
statHp.setBounds(0,statHp.setBounds()[1]*(1+statHeart.percent()));
statHp.modValue(statHp.setBounds()[1]);
statThurst.setBounds(0,statThurst.setBounds()[1]*(1+statHeart.percent()));
statHunger.setBounds(0,statHunger.setBounds()[1]*(1+statHeart.percent()));
statEnergy.setBounds(0,statEnergy.setBounds()[1]*(1+statHeart.percent()));
lifeStageTime = (((lifeMax-lifeTimeCurrent)/(10-lifeStage))*(statHeart.getValue()/100));
window.gameDB.message("Your pet has grown to the next stage if its life.");
}
function die () {
actionQueue = [];
actionCurrent = "Decompos";
clearInterval(myTicker);
guiPetIconID.className = "dead_pet";
guiPetIconID.innerText = "RIP
"+name;
guiStatsID.innerHTML = "";
window.gameDB.message(name+" has died, but all is not lost, you will never forget them, but it seems they left behind a new egg, you will need to pay to have it hatched. But it also looks like your pet was hording coins, theres just enough here to hatch the new egg.",3,30000);
window.gameDB.player.giveReward(300);
window.gameDB.infoexch.market.addItem(window.gameDB.itemDB[1]);
}
function actionDo () {
if (actionQueue.length) {
actionCurrent = actionQueue.shift();
// action logic here
if (actionCurrent == "drink") { emotion(-(drink(1)*0.25)); }
if (actionCurrent == "eat") { emotion(-(eat(1)*0.25)); }
if (actionCurrent == "play") { play(1); }
if (actionCurrent == "rest") { emotion(-(rest(1)*0.25)); }
} else { // Nothing to do
actionCurrent = "rest";
emotion(-(rest(1)*0.25));
}
}
//Public Methods
this.statGet = function () {
return {"health":statHp.percent(),"hunger":statHunger.percent(),"thurst":statThurst.percent(),"energy":statEnergy.percent(),"mood":statMood.getValue()};
};
this.nameChange = function () {
name = window.prompt("What would you like to name this pet?", name);
};
this.actionAdd = function (action) {
if (typeof action != "string") { return false; }
if (action == "water") {
var neededWater = waterBowl.setBounds()[1]-waterBowl.getValue();
var someWater = window.gameDB.player.spendWater(neededWater);
if (someWater >= 0) {
waterBowl.modValue(neededWater);
window.gameDB.message("You fill "+name+"'s water bowl.");
window.gameDB.player.giveWater(someWater);
} else {
window.gameDB.message("You give "+name+" the water you have.");
waterBowl.modValue(neededWater+someWater);
}
}
if (action == "feed") {
var neededFood = foodBowl.setBounds()[1]-foodBowl.getValue();
var someFood = window.gameDB.player.spendFood(neededFood);
if (someFood >= 0) {
foodBowl.modValue(neededFood);
window.gameDB.message("You fill "+name+"'s food bowl.");
window.gameDB.player.giveFood(someFood);
} else {
window.gameDB.message("You give "+name+" the food you have.");
foodBowl.modValue(neededFood+someFood);
}
}
if (action == "play") {
window.gameDB.message("You play with "+name+" for a little while");
"play,".repeat(9).split(",").forEach(function (e) { actionQueue.unshift(e);});
}
};
//Init
var myTicker = setInterval(tickMe, tickTime);
}
};
class player {
constructor() {
var coins = new petStat(0,0,null);
var food = new petStat(0,0,null);
var water = new petStat(0,0,null);
var playerName = "player_"+(new Date()).valueOf();
var guiPlayerID = elementPlace("body", playerName, "player", "div");
var guiPlayerFood = elementPlace("#"+playerName, null, "foodSupply", "div");
var guiPlayerWater = elementPlace("#"+playerName, null, "waterSupply", "div");
var guiPlayerCoins = elementPlace("#"+playerName, null, "coins", "div");
function guiUpdate () {
guiPlayerFood.innerText = "Food:"+Math.round(food.getValue()/10000);
guiPlayerWater.innerText = "Water:"+Math.round(water.getValue()/10000);
guiPlayerCoins.innerText = "Coins:"+coins.getValue();
}
this.makePurchase = function (value) {
var def = coins.modValue(-value);
if (def < 0) {
coins.modValue((value+def));
return false;
} else { return true; }
};
this.giveReward = function (value) {
coins.modValue(value);
};
this.giveFood = function (value) {
food.modValue(value);
};
this.giveWater = function (value) {
water.modValue(value);
};
this.spendFood = function (value) {
return food.modValue(-value);
};
this.spendWater = function (value) {
return water.modValue(-value);
};
this.playerInventory = new market(playerName);
var myTicker = setInterval(guiUpdate, 250);
}
};
class item {
constructor(DOMParent, name, value, description, count, countUse, itemFunction) {
var myName = name;
var myValue = value;
var myDesc = description;
var myCount = count;
var myCountUse = countUse;
var myFunction = itemFunction;
var itemID = myName+"_"+(new Date).valueOf();
var myParent = "body";
if (DOMParent != "body") { myParent = "#"+DOMParent; }
var guiItemContainerID = elementPlace(myParent,itemID,"itemContainer","div");
var guiItemCountID = elementPlace("#"+itemID,null, "itemCount", "div");
guiItemCountID.innerText = myCount;
var guiItemNameID = elementPlace("#"+itemID,null, "itemName", "div");
guiItemNameID.innerText = myName;
var guiItemValueID = elementPlace("#"+itemID,null, "itemValue", "div");
guiItemValueID.innerText = myValue;
var guiItemDescID = elementPlace("#"+itemID,null, "itemDesc", "div");
guiItemDescID.innerText = myDesc;
guiItemContainerID.onclick = function () {
if (window.gameDB.player.makePurchase(value)) {
itemFunction();
myCount -= myCountUse;
if (myCount <= 0) { guiItemContainerID.parentNode.removeChild(guiItemContainerID); }
} else { window.gameDB.message("You don't have enough coins for that!", 2); }
};
}
}
class market {
constructor(DOMParent) {
var me = this;
var myParent = "body";
var marketID = "market_"+(new Date).valueOf();
if (DOMParent != "body") { myParent = "#"+DOMParent; marketID += "_"+DOMParent; }
var guiMarketID = elementPlace(myParent,marketID,"market","div");
var inventory = [];
this.addItem = function (itemObject, name, value, discription, count, countUse, itemFunction) {
var itemIndex = inventory.length;
if (typeof itemObject == "object") {
name = itemObject.name;
value = itemObject.value;
discription = itemObject.desc;
count = itemObject.count;
countUse = itemObject.countUse;
itemFunction = itemObject.myFunction;
}
inventory.push(new item(marketID, name, value, discription,count, countUse, function () {
var myIndex = itemIndex;
inventory.splice(myIndex,1);
itemFunction();
}));
};
}
}
class messageCenter {
constructor (DOMParent) {
var myParent = "body";
var logID = "log_"+(new Date).valueOf();
if (DOMParent != "body") { myParent = "#"+DOMParent; }
var guiLogID = elementPlace(myParent,logID,"log","div");
var MaxMessageQueue = 50;
var messageQueue = [];
function cullOldMessages () {
var curTime = new Date();
messageQueue.forEach( function (message,index,queue) {
if ((message.birth.valueOf()+message.life) < curTime.valueOf()) {
queue.splice(index,1);
}
});
}
function guiUpdate () {
guiLogID.innerHTML = "";
cullOldMessages();
messageQueue.forEach( function (message,index) {
if (index < 50) {
guiLogID.innerHTML = '