pets/old/libs/pet.js

570 lines
22 KiB
JavaScript

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<br />"+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 = '<p class="urgency_'+message.urgency+'">'+message.content+"</p>"+guiLogID.innerHTML;
}
});
}
this.addMessage = function (message, urgency, life) {
var myMessage = "";
var myUrgency = 0;
var myLife = 10000;
if (typeof message == "string") { myMessage = message; }
if (typeof urgency == "number") { myUrgency = urgency; }
if (typeof life == "number") { myLife = life; }
messageQueue.unshift({"birth": new Date(),"content":myMessage,"urgency":myUrgency,"life":myLife});
guiUpdate();
guiLogID.scrollTop = guiLogID.scrollHeight;
}
var myTicker = setInterval(guiUpdate, 250);
}
}
class game {
constructor() {
window.gameDB = this;
window.gameDB.initTime = new Date();
window.gameDB.gameID = "game_"+window.gameDB.initTime.valueOf();
window.gameDB = {};
window.gameDB.player = new player;
window.gameDB.player.pets = [];
window.gameDB.petpen = elementPlace("body","petPin",null,"div");
window.gameDB.infoexch = elementPlace("body","infoex",null,"div");
window.gameDB.infoexch.messages = new messageCenter("infoex");
window.gameDB.infoexch.market = new market("infoex");
window.gameDB.itemDB = [
{"name":"Egg","value":300,"desc":"Your first pet egg, take care of it!","count":1,"countUse":1, "myFunction": function () {
window.gameDB.player.pets.push(new pet());
window.gameDB.message("Great! Now you have your own little pet egg, in time it will hatch and you'll need to make sure its well fed and watered. But to do that you'll need to buy some water so you can put it in their bowl. And don't forget, you can rename your pet at any time by clicking on its avitar.",1,60000);
window.gameDB.infoexch.market.addItem(window.gameDB.itemDB[3]);
}},
{"name":"Egg","value":300,"desc":"Another pet egg","count":1,"countUse":1, "myFunction": function () { window.gameDB.player.pets.push(new pet()); }},
{"name":"SEgg","value":3000,"desc":"Another pet egg, it almost looks like a rock.","count":1,"countUse":1, "myFunction": function () { window.gameDB.player.pets.push(new pet({"gender":[1,0],"health":[200,300],"endurance":[200,300],"heartiness":[100,130]})); }},
{"name":"Food","value":50,"desc":"Food for your pet, don't forget to put it in their bowl.","count":1,"countUse":1, "myFunction": function () {
window.gameDB.player.giveFood(1000000);
window.gameDB.message("Good, now don't forget to put it in their bowl by clicking the <span class="+'"food">F</span> button, now lets buy some water so you can water your pet.',1,60000);
window.gameDB.infoexch.market.addItem(window.gameDB.itemDB[4]); }},
{"name":"Water","value":50,"desc":"Water for your pet, don't forget to put it in their bowl.","count":1,"countUse":1, "myFunction": function () {
window.gameDB.player.giveWater(1000000);
window.gameDB.message("Alright, now that you have some water, lets fill up your pets water bowl, you can do that by clicking the <span class="+'"water">W</span> button. The next thing you will need is a toy to play with your pet, you should have just enough money for that now.',1,60000);
window.gameDB.infoexch.market.addItem(window.gameDB.itemDB[5]);
}},
{"name":"Toy","value":100,"desc":"A toy to keep your pet happy.","count":1,"countUse":1, "myFunction": function () {
window.gameDB.player.playerInventory.addItem(window.gameDB.itemDB[6]);
window.gameDB.infoexch.market.addItem(window.gameDB.itemDB[7]);
window.gameDB.infoexch.market.addItem(window.gameDB.itemDB[8]);
}},
{"name":"Toy","value":0,"desc":"A toy to keep your pet happy.","count":1,"countUse":0, "myFunction": function () { window.gameDB.player.pets.forEach(function (thisPet) { thisPet.actionAdd("play"); }); }},
{"name":"Food","value":50,"desc":"Food for your pet, don't forget to put it in their bowl.","count":1,"countUse":0, "myFunction": function () { window.gameDB.player.giveFood(1000000); }},
{"name":"Water","value":50,"desc":"Water for your pet, don't forget to put it in their bowl.","count":1,"countUse":0, "myFunction": function () { window.gameDB.player.giveWater(1000000); }},
{"name":"Aid Kit (5)","value":100,"desc":"Emergency First Aid kit, heals 100% of all pets health.","count":1,"countUse":0, "myFunction": function () { window.gameDB.player.playerInventory.addItem(window.gameDB.itemDB[10]); }},
{"name":"Aid Kit (5)","value":100,"desc":"Emergency First Aid kit, heals 100% of all pets health.","count":5,"countUse":1, "myFunction": function () { }}
];
window.gameDB.encounterDB = [
{"chance":75, "myFunction": function () {
window.gameDB.player.pets.forEach( function (pet) {
window.gameDB.player.giveReward(Math.round(((Math.random()*50)+1)*(1+(pet.statGet()["mood"]/100))));
});
window.gameDB.message("A stranger smiles at your pet, and gives you a few coins.");
}},
{"chance":15, "myFunction": function () { window.gameDB.infoexch.market.addItem(window.gameDB.itemDB[2]); window.gameDB.message("Huh, whats that on the ground, it looks like another egg, you can pay a hatchery to hatch it for you."); }}
];
window.gameDB.randomEncounter = function () {
console.log("Checking Encounter Table");
var dice = Math.round(Math.random()*100);
console.log("rolled a "+dice);
var myEncounters = window.gameDB.encounterDB.filter( function (e) { return e.chance >= dice; });
if (myEncounters.length > 0) {
console.log("randomly choosing from "+myEncounters.length);
myEncounters[Math.floor(Math.random()*myEncounters.length)].myFunction();
} else {
window.gameDB.message("Something happened somewhere, just not here.");
}
};
window.gameDB.save = function () {
var saveingString = window.gameDB.ti
};
window.gameDB.load = function () {};
// init finished
window.gameDB.message = function (message,urgency,life) {
window.gameDB.infoexch.messages.addMessage(message,urgency,life);
}
window.gameDB.infoexch.market.addItem(window.gameDB.itemDB[0]);
var myEncounterTicker = setInterval(window.gameDB.randomEncounter, hours(1/60));
window.gameDB.player.giveReward(500);
window.gameDB.message("Welcome to Pets: To get started you'll want to buy a new egg from the market",1,60*1000);
window.gameDB.message("You have been given 500 coins. Use them well.");
}
}