Stripped all derby related code.
Added require.js wrapper. Alogos is still BROKEN. I'm deploying them here for testing.
This commit is contained in:
@@ -4,11 +4,12 @@ Shared resources useful for the multiple HabitRPG repositories, that way all the
|
||||
* Algorithms - level up algorithm, scoring functions, etc
|
||||
* Item definitions - weapons, armor, pets
|
||||
|
||||
Note: We can't load CommonJS format into the browser. There's a way to pull it in with RequireJS (r.js?), but I couldn't get that working. Instead I created a `Makefile` which runs Browserify to compile `index-browser.js`, which you include in a `<script/>` tag in your index.html. Let's fix this sometime.
|
||||
|
||||
##Installation
|
||||
* `npm install`
|
||||
* `make`
|
||||
* Node.js - just include files as usual.
|
||||
* Browser - user requre.js with "cs" plugin to include files directly into your index.html
|
||||
|
||||
#TODO add and example of require.js config.
|
||||
|
||||
##CSS
|
||||
Shared CSS between the website and the mobile app is a fuzzy area. For now we'll have the website define canonical CSS, and share that down the mobile app.
|
||||
|
||||
+378
@@ -0,0 +1,378 @@
|
||||
({ define: (
|
||||
if typeof define == "function"
|
||||
define
|
||||
else
|
||||
(F)->
|
||||
F(require, exports, module)
|
||||
)}).define (require, exports, module)->
|
||||
XP = 15
|
||||
HP = 2
|
||||
obj = module.exports =
|
||||
{};
|
||||
obj.priorityValue = (priority = '!') ->
|
||||
switch priority
|
||||
when '!' then 1
|
||||
when '!!' then 1.5
|
||||
when '!!!' then 2
|
||||
else
|
||||
1
|
||||
|
||||
obj.tnl = (level) ->
|
||||
if level >= 100
|
||||
value = 0
|
||||
else
|
||||
value = Math.round(((Math.pow(level, 2) * 0.25) + (10 * level) + 139.75) / 10) * 10
|
||||
# round to nearest 10
|
||||
return value
|
||||
|
||||
###
|
||||
Calculates Exp modificaiton based on level and weapon strength
|
||||
{value} task.value for exp gain
|
||||
{weaponStrength) weapon strength
|
||||
{level} current user level
|
||||
{priority} user-defined priority multiplier
|
||||
###
|
||||
obj.expModifier = (value, weaponStr, level, priority = '!') ->
|
||||
str = (level - 1) / 2
|
||||
# ultimately get this from user
|
||||
totalStr = (str + weaponStr) / 100
|
||||
strMod = 1 + totalStr
|
||||
exp = value * XP * strMod * obj.priorityValue(priority)
|
||||
return Math.round(exp)
|
||||
|
||||
###
|
||||
Calculates HP modification based on level and armor defence
|
||||
{value} task.value for hp loss
|
||||
{armorDefense} defense from armor
|
||||
{helmDefense} defense from helm
|
||||
{level} current user level
|
||||
{priority} user-defined priority multiplier
|
||||
###
|
||||
obj.hpModifier = (value, armorDef, helmDef, shieldDef, level, priority = '!') ->
|
||||
def = (level - 1) / 2
|
||||
# ultimately get this from user?
|
||||
totalDef = (def + armorDef + helmDef + shieldDef) / 100
|
||||
#ultimate get this from user
|
||||
defMod = 1 - totalDef
|
||||
hp = value * HP * defMod * obj.priorityValue(priority)
|
||||
return Math.round(hp * 10) / 10
|
||||
# round to 1dp
|
||||
|
||||
###
|
||||
Future use
|
||||
{priority} user-defined priority multiplier
|
||||
###
|
||||
obj.gpModifier = (value, modifier, priority = '!', streak, user) ->
|
||||
val = value * modifier * obj.priorityValue(priority)
|
||||
if streak and user
|
||||
streakBonus = streak / 100 + 1
|
||||
# eg, 1-day streak is 1.1, 2-day is 1.2, etc
|
||||
afterStreak = val * streakBonus
|
||||
user.streakBonus = afterStreak - val if (val > 0)
|
||||
# can we do this without model? just global emit?
|
||||
return afterStreak
|
||||
else
|
||||
return val
|
||||
|
||||
###
|
||||
Calculates the next task.value based on direction
|
||||
Uses a capped inverse log y=.95^x, y>= -5
|
||||
{currentValue} the current value of the task
|
||||
{direction} up or down
|
||||
###
|
||||
obj.taskDeltaFormula = (currentValue, direction) ->
|
||||
if currentValue < -47.27 then currentValue = -47.27
|
||||
else if currentValue > 21.27 then currentValue = 21.27
|
||||
delta = Math.pow(0.9747, currentValue)
|
||||
return delta if direction is 'up'
|
||||
return -delta
|
||||
|
||||
|
||||
###
|
||||
Drop System
|
||||
###
|
||||
|
||||
randomDrop = (user, delta, priority, streak = 0) ->
|
||||
# limit drops to 2 / day
|
||||
if !user.items.lastDrop?
|
||||
user.items =
|
||||
{
|
||||
date: +moment().subtract('d', 1) # trick - set it to yesterday on first run, that way they can get drops today
|
||||
count: 0
|
||||
}
|
||||
reachedDropLimit = (helpers.daysBetween(user.items.lastDrop.date,
|
||||
+new Date) is 0) and user.items.lastDrop.count >= 2
|
||||
return if reachedDropLimit
|
||||
|
||||
# % chance of getting a pet or meat
|
||||
chanceMultiplier = Math.abs(delta)
|
||||
chanceMultiplier *= obj.priorityValue(priority)
|
||||
# multiply chance by reddness
|
||||
chanceMultiplier += streak
|
||||
# streak bonus
|
||||
console.log chanceMultiplier
|
||||
|
||||
if user.flags.dropsEnabled and Math.random() < (.05 * chanceMultiplier)
|
||||
# current breakdown - 3% (adjustable) chance on drop
|
||||
# If they got a drop: 50% chance of egg, 50% Hatching Potion. If hatchingPotion, broken down further even further
|
||||
rarity = Math.random()
|
||||
|
||||
# Egg, 40% chance
|
||||
if rarity > .6
|
||||
drop = randomVal(pets)
|
||||
user.items.eggs.push drop
|
||||
drop.type = 'Egg'
|
||||
drop.dialog = "You've found a #{drop.text} Egg! #{drop.notes}"
|
||||
|
||||
# Hatching Potion, 60% chance - break down by rarity even more. FIXME this may not be the best method, so revisit
|
||||
else
|
||||
acceptableDrops = []
|
||||
|
||||
# Tier 5 (Blue Moon Rare)
|
||||
if rarity < .1
|
||||
acceptableDrops =
|
||||
['Base', 'White', 'Desert', 'Red', 'Shade', 'Skeleton', 'Zombie', 'CottonCandyPink', 'CottonCandyBlue',
|
||||
'Golden']
|
||||
|
||||
# Tier 4 (Very Rare)
|
||||
else if rarity < .2
|
||||
acceptableDrops =
|
||||
['Base', 'White', 'Desert', 'Red', 'Shade', 'Skeleton', 'Zombie', 'CottonCandyPink', 'CottonCandyBlue']
|
||||
|
||||
# Tier 3 (Rare)
|
||||
else if rarity < .3
|
||||
acceptableDrops = ['Base', 'White', 'Desert', 'Red', 'Shade', 'Skeleton']
|
||||
|
||||
# Tier 2 (Scarce)
|
||||
else if rarity < .4
|
||||
acceptableDrops = ['Base', 'White', 'Desert']
|
||||
# Tier 1 (Common)
|
||||
else
|
||||
acceptableDrops = ['Base']
|
||||
|
||||
acceptableDrops = hatchingPotions.filter (hatchingPotion) ->
|
||||
hatchingPotion.name in acceptableDrops
|
||||
drop = randomVal acceptableDrops
|
||||
user.items.hatchingPotions.push drop.name
|
||||
drop.type = 'HatchingPotion'
|
||||
drop.dialog = "You've found a #{drop.text} Hatching Potion! #{drop.notes}"
|
||||
|
||||
user.drop = drop
|
||||
|
||||
user.items.lastDrop.date = +new Date
|
||||
user.items.lastDrop.count++
|
||||
|
||||
# {task} task you want to score
|
||||
# {direction} 'up' or 'down'
|
||||
obj.score = (user, task, direction, items) ->
|
||||
{gp, hp, exp, lvl} = user.stats
|
||||
{type, value, streak} = task
|
||||
priority = task.priority or '!'
|
||||
|
||||
# If they're trying to purhcase a too-expensive reward, confirm they want to take a hit for it
|
||||
if task.value > user.stats.gp and task.type is 'reward'
|
||||
r = confirm "Not enough GP to purchase this reward, buy anyway and lose HP? (Punishment for taking a reward you didn't earn)."
|
||||
unless r
|
||||
#TODO if this rule is working OK.
|
||||
return
|
||||
|
||||
delta = 0
|
||||
calculateDelta = (adjustvalue = true) ->
|
||||
# Each iteration calculate the delta (nextDelta), which is then accumulated in delta
|
||||
# (aka, the total delta). This weirdness won't be necessary when calculating mathematically
|
||||
# rather than iteratively
|
||||
nextDelta = obj.taskDeltaFormula(value, direction)
|
||||
value += nextDelta if adjustvalue
|
||||
delta += nextDelta
|
||||
|
||||
addPoints = ->
|
||||
level = user.stats.lvl
|
||||
weaponStrength = items.items.weapon[user.items.weapon].strength
|
||||
exp += obj.expModifier(delta, weaponStrength, level, priority) / 2
|
||||
# / 2 hack for now bcause people leveling too fast
|
||||
if streak
|
||||
gp += obj.gpModifier(delta, 1, priority, streak, user)
|
||||
else
|
||||
gp += obj.gpModifier(delta, 1, priority)
|
||||
|
||||
|
||||
subtractPoints = ->
|
||||
level = user.stats.lvl
|
||||
armorDefense = items.items.armor[user.items.armor].defense
|
||||
helmDefense = items.items.head[user.items.head].defense
|
||||
shieldDefense = items.items.shield[user.items.shield].defense
|
||||
hp += obj.hpModifier(delta, armorDefense, helmDefense, shieldDefense, level, priority)
|
||||
|
||||
switch type
|
||||
when 'habit'
|
||||
calculateDelta()
|
||||
# Add habit value to habit-history (if different)
|
||||
if (delta > 0) then addPoints() else subtractPoints()
|
||||
task.history ?= []
|
||||
if task.value != value
|
||||
historyEntry = { date: +new Date, value: value }
|
||||
task.history.push historyEntry
|
||||
|
||||
when 'daily'
|
||||
calculateDelta(false)
|
||||
if delta != 0
|
||||
addPoints()
|
||||
# obviously for delta>0, but also a trick to undo accidental checkboxes
|
||||
if direction is 'up'
|
||||
streak = if streak then streak + 1 else 1
|
||||
else
|
||||
streak = if streak then streak - 1 else 0
|
||||
task.streak = streak
|
||||
|
||||
when 'todo'
|
||||
calculateDelta()
|
||||
addPoints() # obviously for delta>0, but also a trick to undo accidental checkboxes
|
||||
|
||||
when 'reward'
|
||||
# Don't adjust values for rewards
|
||||
calculateDelta(false)
|
||||
# purchase item
|
||||
gp -= Math.abs(task.value)
|
||||
num = parseFloat(task.value).toFixed(2)
|
||||
# if too expensive, reduce health & zero gp
|
||||
if gp < 0
|
||||
hp += gp
|
||||
# hp - gp difference
|
||||
gp = 0
|
||||
|
||||
task.value = value
|
||||
updateStats user, { hp, exp, gp }
|
||||
|
||||
# Drop system
|
||||
# randomDrop(user, delta, priority, streak) if direction is 'up'
|
||||
|
||||
return delta
|
||||
|
||||
###
|
||||
Updates user stats with new stats. Handles death, leveling up, etc
|
||||
{stats} new stats
|
||||
{update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately
|
||||
###
|
||||
updateStats = (user, newStats) ->
|
||||
# if user is dead, dont do anything
|
||||
return if user.stats.hp <= 0
|
||||
|
||||
if newStats.hp?
|
||||
# Game Over
|
||||
if newStats.hp <= 0
|
||||
user.stats.hp = 0
|
||||
# signifies dead
|
||||
return
|
||||
else
|
||||
user.stats.hp = newStats.hp
|
||||
|
||||
if newStats.exp?
|
||||
tnl = obj.tnl(user.stats.lvl)
|
||||
#silent = false
|
||||
# if we're at level 100, turn xp to gold
|
||||
if user.stats.lvl >= 100
|
||||
newStats.gp += newStats.exp / 15
|
||||
newStats.exp = 0
|
||||
user.stats.lvl = 100
|
||||
else
|
||||
# level up & carry-over exp
|
||||
if newStats.exp >= tnl
|
||||
#silent = true # push through the negative xp silently
|
||||
user.stats.exp = newStats.exp
|
||||
# push normal + notification
|
||||
while newStats.exp >= tnl and user.stats.lvl < 100 # keep levelling up
|
||||
newStats.exp -= tnl
|
||||
user.stats.lvl++
|
||||
tnl = obj.tnl(user.stats.lvl)
|
||||
if user.stats.lvl == 100
|
||||
newStats.exp = 0
|
||||
user.stats.hp = 50
|
||||
|
||||
user.stats.exp = newStats.exp
|
||||
#if silent
|
||||
#console.log("pushing silent :" + obj.stats.exp)
|
||||
|
||||
|
||||
# Set flags when they unlock features
|
||||
if !user.flags.customizationsNotification and (user.stats.exp > 10 or user.stats.lvl > 1)
|
||||
user.flags.customizationsNotification = true
|
||||
if !user.flags.itemsEnabled and user.stats.lvl >= 2
|
||||
user.flags.itemsEnabled = true
|
||||
if !user.flags.partyEnabled and user.stats.lvl >= 3
|
||||
user.flags.partyEnabled = true
|
||||
if !user.flags.dropsEnabled and user.stats.lvl >= 4
|
||||
user.flags.dropsEnabled = true
|
||||
|
||||
if newStats.gp?
|
||||
#FIXME what was I doing here? I can't remember, gp isn't defined
|
||||
gp = 0.0 if (!gp? or gp < 0)
|
||||
user.stats.gp = newStats.gp
|
||||
|
||||
###
|
||||
At end of day, add value to all incomplete Daily & Todo tasks (further incentive)
|
||||
For incomplete Dailys, deduct experience
|
||||
Make sure to run this function once in a while as server will not take care of overnight calculations.
|
||||
And you have to run it every time client connects.
|
||||
###
|
||||
obj.cron = (user) ->
|
||||
today = +new Date
|
||||
daysPassed = helpers.daysBetween(user.lastCron, today, user.preferences.dayStart)
|
||||
if daysPassed > 0
|
||||
user.lastCron = today
|
||||
|
||||
if user.flags.rest is true
|
||||
user.dailys.forEach (daily) ->
|
||||
daily.completed = false
|
||||
return
|
||||
|
||||
# Tally each task
|
||||
todoTally = 0
|
||||
user.todos.concat(user.dailys).forEach (task) ->
|
||||
{id, type, completed, repeat} = task
|
||||
# Deduct experience for missed Daily tasks,
|
||||
# but not for Todos (just increase todo's value)
|
||||
unless completed
|
||||
# for todos & typical dailies, these are equivalent
|
||||
daysFailed = daysPassed
|
||||
# however, for dailys which have repeat dates, need
|
||||
# to calculate how many they've missed according to their own schedule
|
||||
if type == 'daily' && repeat
|
||||
daysFailed = 0
|
||||
for i in [1..daysPassed] by 1
|
||||
thatDay = moment().subtract('days', i + 1)
|
||||
if repeat[helpers.dayMapping[thatDay.day()]] == true
|
||||
daysFailed++
|
||||
score user, task, 'down'
|
||||
if type == 'daily'
|
||||
if completed #set OHV for completed dailies
|
||||
task.value = task.value + taskDeltaFormula(task.value, 'up')
|
||||
task.history ?= []
|
||||
task.history.push { date: +new Date, value: task.value }
|
||||
task.completed = false
|
||||
else
|
||||
#get updated value
|
||||
absVal = if (completed) then Math.abs(task.value) else task.value
|
||||
todoTally += absVal
|
||||
user.habits.forEach (task) -> # slowly reset 'onlies' value to 0
|
||||
if task.up == false or task.down == false
|
||||
if Math.abs(task.value) < 0.1
|
||||
task.value = 0
|
||||
else
|
||||
task.value = task.value / 2
|
||||
|
||||
# Finished tallying
|
||||
user.history ?= {};
|
||||
user.history.todos ?= [];
|
||||
user.history.exp ?= []
|
||||
user.history.todos.push { date: today, value: todoTally }
|
||||
# tally experience
|
||||
expTally = user.stats.exp
|
||||
lvl = 0
|
||||
#iterator
|
||||
while lvl < (user.stats.lvl - 1)
|
||||
lvl++
|
||||
expTally += obj.tnl(lvl)
|
||||
user.history.exp.push { date: today, value: expTally }
|
||||
user
|
||||
|
||||
|
||||
@@ -1,256 +0,0 @@
|
||||
var HP = 15
|
||||
, XP = 2
|
||||
, Items = require('./items');
|
||||
|
||||
function priorityValue(priority) {
|
||||
if (priority == null) {
|
||||
priority = '!';
|
||||
}
|
||||
switch (priority) {
|
||||
case '!':
|
||||
return 1;
|
||||
case '!!':
|
||||
return 1.5;
|
||||
case '!!!':
|
||||
return 2;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
function tnl(level) {
|
||||
var value;
|
||||
if (level >= 100) {
|
||||
value = 0;
|
||||
} else {
|
||||
value = Math.round(((Math.pow(level, 2) * 0.25) + (10 * level) + 139.75) / 10) * 10;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
/*
|
||||
Calculates Exp modificaiton based on level and weapon strength
|
||||
{value} task.value for exp gain
|
||||
{weaponStrength) weapon strength
|
||||
{level} current user level
|
||||
{priority} user-defined priority multiplier
|
||||
*/
|
||||
|
||||
|
||||
function expModifier(value, weaponStr, level, priority) {
|
||||
var exp, str, strMod, totalStr;
|
||||
if (priority == null) {
|
||||
priority = '!';
|
||||
}
|
||||
str = (level - 1) / 2;
|
||||
totalStr = (str + weaponStr) / 100;
|
||||
strMod = 1 + totalStr;
|
||||
exp = value * XP * strMod * priorityValue(priority);
|
||||
return Math.round(exp);
|
||||
};
|
||||
|
||||
/*
|
||||
Calculates HP modification based on level and armor defence
|
||||
{value} task.value for hp loss
|
||||
{armorDefense} defense from armor
|
||||
{helmDefense} defense from helm
|
||||
{level} current user level
|
||||
{priority} user-defined priority multiplier
|
||||
*/
|
||||
|
||||
|
||||
function hpModifier(value, armorDef, helmDef, shieldDef, level, priority) {
|
||||
var def, defMod, hp, totalDef;
|
||||
if (priority == null) {
|
||||
priority = '!';
|
||||
}
|
||||
def = (level - 1) / 2;
|
||||
totalDef = (def + armorDef + helmDef + shieldDef) / 100;
|
||||
defMod = 1 - totalDef;
|
||||
hp = value * HP * defMod * priorityValue(priority);
|
||||
return Math.round(hp * 10) / 10;
|
||||
};
|
||||
|
||||
/*
|
||||
Future use
|
||||
{priority} user-defined priority multiplier
|
||||
*/
|
||||
|
||||
|
||||
function gpModifier(value, modifier, priority) {
|
||||
if (priority == null) {
|
||||
priority = '!';
|
||||
}
|
||||
return value * modifier * priorityValue(priority);
|
||||
};
|
||||
|
||||
/*
|
||||
Calculates the next task.value based on direction
|
||||
Uses a capped inverse log y=.95^x, y>= -5
|
||||
{currentValue} the current value of the task
|
||||
{direction} up or down
|
||||
*/
|
||||
|
||||
|
||||
function taskDeltaFormula(currentValue, direction) {
|
||||
var delta;
|
||||
if (currentValue < -47.27) {
|
||||
currentValue = -47.27;
|
||||
} else if (currentValue > 21.27) {
|
||||
currentValue = 21.27;
|
||||
}
|
||||
delta = Math.pow(0.9747, currentValue);
|
||||
if (direction === 'up') {
|
||||
return delta;
|
||||
}
|
||||
return -delta;
|
||||
};
|
||||
|
||||
function score(user, taskId, direction, times, cron) {
|
||||
var task = _.findWhere(user.tasks, {id: taskId})
|
||||
, type = task.type
|
||||
, value = task.value
|
||||
, priority = task.priority || '!'
|
||||
, delta = 0
|
||||
, times = times? times: 1;
|
||||
|
||||
|
||||
if (task.value > user.stats.gp && task.type === 'reward') {
|
||||
r = confirm("Not enough GP to purchase this reward, buy anyway and lose HP? (Punishment for taking a reward you didn't earn).");
|
||||
if (!r) return;
|
||||
}
|
||||
|
||||
function calculateDelta(adjustvalue) {
|
||||
adjustvalue = adjustvalue? adjustvalue: true;
|
||||
_.times(times, function(n) {
|
||||
var nextDelta;
|
||||
nextDelta = taskDeltaFormula(value, direction);
|
||||
if (adjustvalue) {
|
||||
value += nextDelta;
|
||||
}
|
||||
delta += nextDelta;
|
||||
});
|
||||
};
|
||||
|
||||
function addPoints() {
|
||||
var level, weaponStrength;
|
||||
level = user.stats.lvl;
|
||||
weaponStrength = Items.items.weapon[user.items.weapon].strength;
|
||||
user.stats.exp += expModifier(delta, weaponStrength, level, priority);
|
||||
user.stats.gp += gpModifier(delta, 1, priority);
|
||||
};
|
||||
|
||||
function subtractPoints() {
|
||||
var armorDefense, helmDefense, level, shieldDefense;
|
||||
level = user.stats.lvl;
|
||||
armorDefense = Items.items.armor[user.items.armor].defense;
|
||||
helmDefense = Items.items.head[user.items.head].defense;
|
||||
shieldDefense = Items.items.shield[user.items.shield].defense;
|
||||
user.stats.hp += hpModifier(delta, armorDefense, helmDefense, shieldDefense, level, priority);
|
||||
};
|
||||
switch (type) {
|
||||
case 'habit':
|
||||
calculateDelta();
|
||||
if (delta > 0) {
|
||||
addPoints();
|
||||
} else {
|
||||
subtractPoints();
|
||||
}
|
||||
task.history = task.history? task.history: [];
|
||||
if (task.value !== value) {
|
||||
task.history.push({
|
||||
date: +(new Date),
|
||||
value: value
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'daily':
|
||||
if (cron != null) {
|
||||
calculateDelta();
|
||||
subtractPoints();
|
||||
} else {
|
||||
calculateDelta(false);
|
||||
if (delta !== 0) {
|
||||
addPoints();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'todo':
|
||||
if (cron != null) {
|
||||
calculateDelta();
|
||||
} else {
|
||||
calculateDelta();
|
||||
addPoints();
|
||||
}
|
||||
break;
|
||||
case 'reward':
|
||||
calculateDelta(false);
|
||||
user.stats.gp -= Math.abs(task.value);
|
||||
var num = parseFloat(task.value).toFixed(2);
|
||||
if (user.stats.gp < 0) {
|
||||
user.stats.hp += user.stats.gp;
|
||||
user.stats.gp = 0;
|
||||
}
|
||||
}
|
||||
task.value = value;
|
||||
updateStats(user);
|
||||
return delta;
|
||||
};
|
||||
|
||||
/*
|
||||
Updates user stats with new stats. Handles death, leveling up, etc
|
||||
{stats} new stats
|
||||
{update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately
|
||||
*/
|
||||
|
||||
|
||||
function updateStats(user) {
|
||||
if (user.stats.lvl === 0) return;
|
||||
if (user.stats.hp <= 0) {
|
||||
user.stats.lvl = 0; // signifies dead
|
||||
user.stats.hp = 0;
|
||||
return;
|
||||
}
|
||||
if (user.stats.lvl >= 100) {
|
||||
user.stats.gp += user.stats.exp / 15;
|
||||
user.stats.exp = 0;
|
||||
user.stats.lvl = 100;
|
||||
} else {
|
||||
var currTnl = user.stats.tnl = tnl(user.stats.lvl);
|
||||
if (user.stats.exp >= currTnl) {
|
||||
while (user.stats.exp >= currTnl && user.stats.lvl < 100) {
|
||||
user.stats.exp -= currTnl;
|
||||
user.stats.lvl++;
|
||||
user.stats.tnl = tnl(user.stats.lvl);
|
||||
}
|
||||
if (user.stats.lvl === 100) {
|
||||
user.stats.exp = 0;
|
||||
}
|
||||
user.stats.hp = 50;
|
||||
}
|
||||
}
|
||||
if (!user.flags.customizationsNotification && (user.stats.exp > 10 || user.stats.lvl > 1)) {
|
||||
user.flags.customizationsNotification = true;
|
||||
user.flags.customizationsNotification = true;
|
||||
}
|
||||
if (!user.flags.itemsEnabled && user.stats.lvl >= 2) {
|
||||
user.flags.itemsEnabled = true;
|
||||
user.flags.itemsEnabled = true;
|
||||
}
|
||||
if (!user.flags.partyEnabled && user.stats.lvl >= 3) {
|
||||
user.flags.partyEnabled = true;
|
||||
user.flags.partyEnabled = true;
|
||||
}
|
||||
if (!user.flags.petsEnabled && user.stats.lvl >= 4) {
|
||||
user.flags.petsEnabled = true;
|
||||
user.flags.petsEnabled = true;
|
||||
}
|
||||
|
||||
if (user.stats.gp < 0) user.stats.gp = 0.0;
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
tnl: tnl,
|
||||
score: score
|
||||
}
|
||||
-2037
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
||||
exports.algos = require('./algos')
|
||||
exports.items = require('./items')
|
||||
exports.helpers = require('./helpers')
|
||||
|
||||
// This is how we're exporting this module to the browser. A preferable way would be http://requirejs.org/docs/api.html#packages
|
||||
// but I couldn't get that working
|
||||
try {
|
||||
window;
|
||||
window.habitrpgShared = exports;
|
||||
} catch(e) {}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
({ define: (
|
||||
if typeof define == "function"
|
||||
define
|
||||
else
|
||||
(F)->
|
||||
F(require, exports, module)
|
||||
)}).define (require, exports, module)->
|
||||
obj = module.exports = {};
|
||||
items = obj.items =
|
||||
{
|
||||
weapon: [
|
||||
{index: 0, text: "Training Sword", classes: "weapon_0", notes: 'Training weapon.', strength: 0, value: 0}
|
||||
{index: 1, text: "Sword", classes: 'weapon_1', notes: 'Increases experience gain by 3%.', strength: 3, value: 20}
|
||||
{index: 2, text: "Axe", classes: 'weapon_2', notes: 'Increases experience gain by 6%.', strength: 6, value: 30}
|
||||
{index: 3, text: "Morningstar", classes: 'weapon_3', notes: 'Increases experience gain by 9%.', strength: 9, value: 45}
|
||||
{index: 4, text: "Blue Sword", classes: 'weapon_4', notes: 'Increases experience gain by 12%.', strength: 12, value: 65}
|
||||
{index: 5, text: "Red Sword", classes: 'weapon_5', notes: 'Increases experience gain by 15%.', strength: 15, value: 90}
|
||||
{index: 6, text: "Golden Sword", classes: 'weapon_6', notes: 'Increases experience gain by 18%.', strength: 18, value: 120}
|
||||
{index: 7, text: "Dark Souls Blade", classes: 'weapon_7', notes: 'Increases experience gain by 21%.', strength: 21, value: 150}
|
||||
]
|
||||
armor: [
|
||||
{index: 0, text: "Cloth Armor", classes: 'armor_0', notes: 'Training armor.', defense: 0, value: 0}
|
||||
{index: 1, text: "Leather Armor", classes: 'armor_1', notes: 'Decreases HP loss by 4%.', defense: 4, value: 30}
|
||||
{index: 2, text: "Chain Mail", classes: 'armor_2', notes: 'Decreases HP loss by 6%.', defense: 6, value: 45}
|
||||
{index: 3, text: "Plate Mail", classes: 'armor_3', notes: 'Decreases HP loss by 7%.', defense: 7, value: 65}
|
||||
{index: 4, text: "Red Armor", classes: 'armor_4', notes: 'Decreases HP loss by 8%.', defense: 8, value: 90}
|
||||
{index: 5, text: "Golden Armor", classes: 'armor_5', notes: 'Decreases HP loss by 10%.', defense: 10, value: 120}
|
||||
{index: 6, text: "Shade Armor", classes: 'armor_6', notes: 'Decreases HP loss by 12%.', defense: 12, value: 150}
|
||||
]
|
||||
head: [
|
||||
{index: 0, text: "No Helm", classes: 'head_0', notes: 'Training helm.', defense: 0, value: 0}
|
||||
{index: 1, text: "Leather Helm", classes: 'head_1', notes: 'Decreases HP loss by 2%.', defense: 2, value: 15}
|
||||
{index: 2, text: "Chain Coif", classes: 'head_2', notes: 'Decreases HP loss by 3%.', defense: 3, value: 25}
|
||||
{index: 3, text: "Plate Helm", classes: 'head_3', notes: 'Decreases HP loss by 4%.', defense: 4, value: 45}
|
||||
{index: 4, text: "Red Helm", classes: 'head_4', notes: 'Decreases HP loss by 5%.', defense: 5, value: 60}
|
||||
{index: 5, text: "Golden Helm", classes: 'head_5', notes: 'Decreases HP loss by 6%.', defense: 6, value: 80}
|
||||
{index: 6, text: "Shade Helm", classes: 'head_6', notes: 'Decreases HP loss by 7%.', defense: 7, value: 100}
|
||||
]
|
||||
shield: [
|
||||
{index: 0, text: "No Shield", classes: 'shield_0', notes: 'No Shield.', defense: 0, value: 0}
|
||||
{index: 1, text: "Wooden Shield", classes: 'shield_1', notes: 'Decreases HP loss by 3%', defense: 3, value: 20}
|
||||
{index: 2, text: "Buckler", classes: 'shield_2', notes: 'Decreases HP loss by 4%.', defense: 4, value: 35}
|
||||
{index: 3, text: "Enforced Shield", classes: 'shield_3', notes: 'Decreases HP loss by 5%.', defense: 5, value: 55}
|
||||
{index: 4, text: "Red Shield", classes: 'shield_4', notes: 'Decreases HP loss by 7%.', defense: 7, value: 70}
|
||||
{index: 5, text: "Golden Shield", classes: 'shield_5', notes: 'Decreases HP loss by 8%.', defense: 8, value: 90}
|
||||
{index: 6, text: "Tormented Skull", classes: 'shield_6', notes: 'Decreases HP loss by 9%.', defense: 9, value: 120}
|
||||
]
|
||||
potion:
|
||||
{type: 'potion', text: "Potion", notes: "Recover 15 HP", value: 25, classes: 'potion'}
|
||||
reroll:
|
||||
{type: 'reroll', text: "Re-Roll", classes: 'reroll', notes: "Resets your task values back to 0 (yellow). Useful when everything's red and it's hard to stay alive.", value: 0 }
|
||||
pets: [
|
||||
{text: 'Wolf', name: 'Wolf', value: 3}
|
||||
{text: 'Tiger Cub', name: 'TigerCub', value: 3}
|
||||
#{text: 'Polar Bear Cub', name: 'PolarBearCub', value: 3} #commented out because there are no polarbear modifiers yet, special drop?
|
||||
{text: 'Panda Cub', name: 'PandaCub', value: 3}
|
||||
{text: 'Lion Cub', name: 'LionCub', value: 3}
|
||||
{text: 'Fox', name: 'Fox', value: 3}
|
||||
{text: 'Flying Pig', name: 'FlyingPig', value: 3}
|
||||
{text: 'Dragon', name: 'Dragon', value: 3}
|
||||
{text: 'Cactus', name: 'Cactus', value: 3}
|
||||
{text: 'Bear Cub', name: 'BearCub', value: 3}
|
||||
]
|
||||
hatchingPotions: [
|
||||
{text: 'Base', name: 'Base', notes: "Hatches your pet in it's base form.", value: 1}
|
||||
{text: 'White', name: 'White', notes: 'Turns your animal into a White pet.', value: 2}
|
||||
{text: 'Desert', name: 'Desert', notes: 'Turns your animal into a Desert pet.', value: 2}
|
||||
{text: 'Red', name: 'Red', notes: 'Turns your animal into a Red pet.', value: 3}
|
||||
{text: 'Shade', name: 'Shade', notes: 'Turns your animal into a Shade pet.', value: 3}
|
||||
{text: 'Skeleton', name: 'Skeleton', notes: 'Turns your animal into a Skeleton.', value: 3}
|
||||
{text: 'Zombie', name: 'Zombie', notes: 'Turns your animal into a Zombie.', value: 4}
|
||||
{text: 'Cotton Candy Pink', name: 'CottonCandyPink', notes: 'Turns your animal into a Cotton Candy Pink pet.', value: 4}
|
||||
{text: 'Cotton Candy Blue', name: 'CottonCandyBlue', notes: 'Turns your animal into a Cotton Candy Blue pet.', value: 4}
|
||||
{text: 'Golden', name: 'Golden', notes: 'Turns your animal into a Golden pet.', value: 5}
|
||||
]
|
||||
}
|
||||
|
||||
# add "type" to each item, so we can reference that as "weapon" or "armor" in the html
|
||||
['weapon', 'armor', 'head', 'shield'].forEach (key)->
|
||||
items[key].forEach (item)->
|
||||
item.type = key
|
||||
|
||||
items.pets.forEach (pet)->
|
||||
pet.notes = 'Find a hatching potion to pour on this egg, and one day it will hatch into a loyal pet.'
|
||||
items.hatchingPotions.forEach (hatchingPotion)->
|
||||
hatchingPotion.notes = "Pour this on an egg, and it will hatch as a #{hatchingPotion.text} pet."
|
||||
|
||||
|
||||
###
|
||||
app exports
|
||||
###
|
||||
obj.app = (appExports, user) ->
|
||||
appExports.buyItem = (e, el, next) ->
|
||||
#TODO: this should be working but it's not. so instead, i'm passing all needed values as data-attrs
|
||||
# item = model.at(e.target)
|
||||
gp = user.stats.gp
|
||||
[type, value, index] = [ $(el).attr('data-type'), $(el).attr('data-value'), $(el).attr('data-index') ]
|
||||
|
||||
return if gp < value
|
||||
# make sure deduction doesn't happen unless purchase was successful, see https://github.com/lefnire/habitrpg/issues/233
|
||||
deductGP = ->
|
||||
user.stats.gp = gp - value
|
||||
if type == 'weapon'
|
||||
user.set 'items.weapon', index, deductGP
|
||||
updateStore model
|
||||
else if type == 'armor'
|
||||
user.set 'items.armor', index, deductGP
|
||||
updateStore model
|
||||
else if type == 'head'
|
||||
user.set 'items.head', index, deductGP
|
||||
updateStore model
|
||||
else if type == 'shield'
|
||||
user.set 'items.shield', index, deductGP
|
||||
updateStore model
|
||||
else if type == 'potion'
|
||||
hp = user.get 'stats.hp'
|
||||
hp += 15
|
||||
hp = 50 if hp > 50
|
||||
user.set 'stats.hp', hp, deductGP
|
||||
|
||||
|
||||
###
|
||||
update store
|
||||
###
|
||||
obj.updateStore = updateStore = (user) ->
|
||||
if !items.next?
|
||||
items.next =
|
||||
{}
|
||||
equipped = user.items
|
||||
|
||||
['weapon', 'armor', 'shield', 'head'].forEach (type) ->
|
||||
i = parseInt(equipped? [type] || 0) + 1
|
||||
showNext = true
|
||||
if i is items[type].length - 1
|
||||
if (type in ['armor', 'shield', 'head'])
|
||||
showNext = user.backer.tier >= 45 # backer armor
|
||||
else
|
||||
showNext = user.backer.tier >= 70 # backer weapon
|
||||
else if i is items[type].length
|
||||
showNext = false
|
||||
|
||||
items.next[type] = if showNext then items[type][i] else {hide: true}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,5 @@
|
||||
"name": "habitrpg-shared",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"browserify": "*",
|
||||
"moment": "*"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user