mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-05-18 19:58:52 +00:00
quests: add collection quests & quest arks
This commit is contained in:
parent
fe6b505c09
commit
9aeb4f9ffb
7 changed files with 118 additions and 82 deletions
2
dist/customizer.css
vendored
2
dist/customizer.css
vendored
|
|
@ -2236,7 +2236,7 @@
|
|||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.quest_evil_santa {
|
||||
.quest_evilsanta {
|
||||
background-image: url(spritesmith.png);
|
||||
background-position: -162px -150px;
|
||||
width: 118px;
|
||||
|
|
|
|||
2
dist/habitrpg-shared.css
vendored
2
dist/habitrpg-shared.css
vendored
File diff suppressed because one or more lines are too long
124
dist/habitrpg-shared.js
vendored
124
dist/habitrpg-shared.js
vendored
|
|
@ -10462,23 +10462,45 @@ var global=self;/**
|
|||
});
|
||||
|
||||
api.quests = {
|
||||
evil_santa: {
|
||||
type: 'boss',
|
||||
name: "Evil Santa",
|
||||
text: "Evil Santa (Party 1)",
|
||||
notes: "An evil Santa Clause has captured a Polar Bear Cub. Vanguish this evil, and save the cub!",
|
||||
stats: {
|
||||
evilsanta: {
|
||||
text: "Evil Santa",
|
||||
notes: "An evil Santa Clause has captured a fully grown Polar Bear. Vanguish this evil, and save the beast!",
|
||||
value: 4,
|
||||
boss: {
|
||||
name: "Evil Santa",
|
||||
hp: 100,
|
||||
str: 1
|
||||
},
|
||||
drop: {
|
||||
type: 'pets',
|
||||
type: 'mounts',
|
||||
key: 'BearCub-Polar',
|
||||
text: "Polar Bear Cub (Pet)",
|
||||
text: "Polar Bear (Mount)",
|
||||
gp: 20,
|
||||
exp: 100
|
||||
}
|
||||
},
|
||||
evilsanta2: {
|
||||
text: "Find Baby Bear",
|
||||
notes: "Mama bear begs you to find her cub. He ran off into the icefields when mama was captured by Evil Santa, find his tracks!",
|
||||
value: 4,
|
||||
previous: 'evilsanta',
|
||||
collect: {
|
||||
tracks: {
|
||||
text: 'Tracks',
|
||||
count: 20
|
||||
},
|
||||
branches: {
|
||||
text: 'Broken Twigs',
|
||||
count: 10
|
||||
}
|
||||
},
|
||||
value: 4
|
||||
drop: {
|
||||
type: 'pets',
|
||||
key: 'BearCub-Polar',
|
||||
text: "Polar Bear (Pet)",
|
||||
gp: 20,
|
||||
exp: 100
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -10724,6 +10746,10 @@ var process=require("__browserify_process");(function() {
|
|||
return max * (bonus / (bonus + halfway));
|
||||
};
|
||||
|
||||
api.monod = function(bonus, rateOfIncrease, max) {
|
||||
return rateOfIncrease * max * bonus / (rateOfIncrease * bonus + max);
|
||||
};
|
||||
|
||||
/*
|
||||
Preen history for users with > 7 history entries
|
||||
This takes an infinite array of single day entries [day day day day day...], and turns it into a condensed array
|
||||
|
|
@ -11329,7 +11355,7 @@ var process=require("__browserify_process");(function() {
|
|||
message: ":pet not found in user.items.pets"
|
||||
});
|
||||
}
|
||||
if (!((_ref2 = user.items.food) != null ? _ref2[food.name] : void 0)) {
|
||||
if (!((_ref2 = user.items.food) != null ? _ref2[food.key] : void 0)) {
|
||||
return cb({
|
||||
code: 404,
|
||||
message: ":food not found in user.items.food"
|
||||
|
|
@ -11341,7 +11367,7 @@ var process=require("__browserify_process");(function() {
|
|||
message: "Can't feed this pet."
|
||||
});
|
||||
}
|
||||
if (user.items.mounts[pet] && (userPets[pet] >= 50 || food.name === 'Saddle')) {
|
||||
if (user.items.mounts[pet] && (userPets[pet] >= 50 || food.key === 'Saddle')) {
|
||||
return cb({
|
||||
code: 401,
|
||||
message: "You already have that mount"
|
||||
|
|
@ -11356,21 +11382,21 @@ var process=require("__browserify_process");(function() {
|
|||
}
|
||||
return message = "You have tamed " + egg + ", let's go for a ride!";
|
||||
};
|
||||
if (food.name === 'Saddle') {
|
||||
if (food.key === 'Saddle') {
|
||||
evolve();
|
||||
} else {
|
||||
if (food.target === potion) {
|
||||
userPets[pet] += 5;
|
||||
message = "" + egg + " really likes the " + food.name + "!";
|
||||
message = "" + egg + " really likes the " + food.key + "!";
|
||||
} else {
|
||||
userPets[pet] += 2;
|
||||
message = "" + egg + " eats the " + food.name + " but doesn't seem to enjoy it.";
|
||||
message = "" + egg + " eats the " + food.key + " but doesn't seem to enjoy it.";
|
||||
}
|
||||
if (userPets[pet] >= 50 && !user.items.mounts[pet]) {
|
||||
evolve();
|
||||
}
|
||||
}
|
||||
user.items.food[food.name]--;
|
||||
user.items.food[food.key]--;
|
||||
return cb({
|
||||
code: 200,
|
||||
message: message
|
||||
|
|
@ -11843,43 +11869,42 @@ var process=require("__browserify_process");(function() {
|
|||
}), user);
|
||||
},
|
||||
randomDrop: function(modifiers) {
|
||||
var a, acceptableDrops, alpha, chanceMultiplier, delta, drop, max, priority, rarity, reachedDropLimit, streak, _base, _base1, _base2, _base3, _name, _name1, _name2, _ref, _ref1;
|
||||
delta = modifiers.delta;
|
||||
_ref = modifiers.task, priority = _ref.priority, streak = _ref.streak;
|
||||
if (streak == null) {
|
||||
streak = 0;
|
||||
var acceptableDrops, bonus, chance, drop, dropK, quest, rarity, task, _base, _base1, _base2, _name, _name1, _name2, _ref, _ref1;
|
||||
task = modifiers.task;
|
||||
bonus = Math.abs(task.value) * task.priority + (task.streak || 0) + (user._statsComputed.per * .5);
|
||||
bonus /= 100;
|
||||
chance = api.diminishingReturns(bonus, 1, 0.5);
|
||||
console.log("Drop Equation: Bonus(" + (bonus.toFixed(3)) + "), Modified Chance(" + (chance.toFixed(3)) + ")\n");
|
||||
quest = content.quests[(_ref = user.party.quest) != null ? _ref.key : void 0];
|
||||
if ((quest != null ? quest.collect : void 0) && user.fns.predictableRandom(user.stats.gp) < bonus) {
|
||||
dropK = user.fns.randomVal(quest.collect, {
|
||||
key: true
|
||||
});
|
||||
user.party.quest.tally.collect[dropK]++;
|
||||
if (typeof user.markModified === "function") {
|
||||
user.markModified('party.quest.tally');
|
||||
}
|
||||
console.log({
|
||||
tally: user.party.quest.tally
|
||||
});
|
||||
}
|
||||
if ((_base = user.items).lastDrop == null) {
|
||||
_base.lastDrop = {
|
||||
date: +moment().subtract('d', 1),
|
||||
count: 0
|
||||
};
|
||||
}
|
||||
reachedDropLimit = (api.daysSince(user.items.lastDrop.date, user.preferences) === 0) && (user.items.lastDrop.count >= 5);
|
||||
if (reachedDropLimit) {
|
||||
if ((api.daysSince(user.items.lastDrop.date, user.preferences) === 0) && (user.items.lastDrop.count >= 5)) {
|
||||
return;
|
||||
}
|
||||
chanceMultiplier = Math.abs(delta);
|
||||
chanceMultiplier *= priority;
|
||||
chanceMultiplier += streak;
|
||||
chanceMultiplier += user._statsComputed.per * .3;
|
||||
max = 0.75;
|
||||
a = 0.1;
|
||||
alpha = a * max * chanceMultiplier / (a * chanceMultiplier + max);
|
||||
if (((_ref1 = user.flags) != null ? _ref1.dropsEnabled : void 0) && user.fns.predictableRandom(user.stats.exp) < alpha) {
|
||||
if (((_ref1 = user.flags) != null ? _ref1.dropsEnabled : void 0) && user.fns.predictableRandom(user.stats.exp) < chance) {
|
||||
rarity = user.fns.predictableRandom(user.stats.gp);
|
||||
if (rarity > .6) {
|
||||
drop = user.fns.randomVal(_.omit(content.food, 'Saddle'));
|
||||
if ((_base1 = user.items.food)[_name = drop.key] == null) {
|
||||
_base1[_name] = 0;
|
||||
if ((_base = user.items.food)[_name = drop.key] == null) {
|
||||
_base[_name] = 0;
|
||||
}
|
||||
user.items.food[drop.key] += 1;
|
||||
drop.type = 'Food';
|
||||
drop.dialog = "You've found a " + drop.text + " Food! " + drop.notes;
|
||||
} else if (rarity > .3) {
|
||||
drop = user.fns.randomVal(content.eggs);
|
||||
if ((_base2 = user.items.eggs)[_name1 = drop.key] == null) {
|
||||
_base2[_name1] = 0;
|
||||
if ((_base1 = user.items.eggs)[_name1 = drop.key] == null) {
|
||||
_base1[_name1] = 0;
|
||||
}
|
||||
user.items.eggs[drop.key]++;
|
||||
drop.type = 'Egg';
|
||||
|
|
@ -11889,8 +11914,8 @@ var process=require("__browserify_process");(function() {
|
|||
drop = user.fns.randomVal(_.pick(content.hatchingPotions, (function(v, k) {
|
||||
return __indexOf.call(acceptableDrops, k) >= 0;
|
||||
})));
|
||||
if ((_base3 = user.items.hatchingPotions)[_name2 = drop.key] == null) {
|
||||
_base3[_name2] = 0;
|
||||
if ((_base2 = user.items.hatchingPotions)[_name2 = drop.key] == null) {
|
||||
_base2[_name2] = 0;
|
||||
}
|
||||
user.items.hatchingPotions[drop.key]++;
|
||||
drop.type = 'HatchingPotion';
|
||||
|
|
@ -11990,7 +12015,7 @@ var process=require("__browserify_process");(function() {
|
|||
*/
|
||||
|
||||
cron: function(options) {
|
||||
var daysMissed, expTally, lvl, now, tally, todoTally, _base, _base1, _base2;
|
||||
var daysMissed, expTally, lvl, now, tally, todoTally, _base, _base1, _base2, _tally;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
|
|
@ -12112,15 +12137,16 @@ var process=require("__browserify_process");(function() {
|
|||
stealth: 0,
|
||||
streaks: false
|
||||
};
|
||||
tally = {
|
||||
down: user.party.quest.tally.down,
|
||||
up: user.party.quest.tally.up
|
||||
};
|
||||
_.merge(user.party.quest.tally, {
|
||||
tally = user.party.quest.tally;
|
||||
_tally = _.cloneDeep(tally);
|
||||
_.merge(tally, {
|
||||
down: 0,
|
||||
up: 0
|
||||
});
|
||||
return tally;
|
||||
tally.collect = _.transform(tally.collect, (function(m, v, k) {
|
||||
return m[k] = 0;
|
||||
}));
|
||||
return _tally;
|
||||
},
|
||||
preenUserHistory: function(minHistLen) {
|
||||
if (minHistLen == null) {
|
||||
|
|
|
|||
2
dist/spritesmith.css
vendored
2
dist/spritesmith.css
vendored
|
|
@ -2236,7 +2236,7 @@
|
|||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.quest_evil_santa {
|
||||
.quest_evilsanta {
|
||||
background-image: url(spritesmith.png);
|
||||
background-position: -162px -150px;
|
||||
width: 118px;
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
|
@ -481,25 +481,33 @@ _.each api.food, (food,key) ->
|
|||
_.defaults food, {value: 1, key, notes: "Feed this to a pet and it may grow into a sturdy steed."}
|
||||
|
||||
api.quests =
|
||||
evil_santa:
|
||||
type: 'boss' # 'collection'
|
||||
name: "Evil Santa"
|
||||
text: "Evil Santa (Party 1)"
|
||||
notes: "An evil Santa Clause has captured a Polar Bear Cub. Vanguish this evil, and save the cub!"
|
||||
|
||||
evilsanta:
|
||||
text: "Evil Santa" # title of the quest (eg, Deep into Vice's Layer)
|
||||
notes: "An evil Santa Clause has captured a fully grown Polar Bear. Vanguish this evil, and save the beast!"
|
||||
value: 4 # Gem cost to buy, GP sell-back
|
||||
#mechanic: enum['perfectDailies', ...]
|
||||
#collection:
|
||||
# feather: name: 'Feather', count: 10
|
||||
# ingot: name: 'Golden Ingot', count: 10
|
||||
stats:
|
||||
boss:
|
||||
name: "Evil Santa" # name of the boss himself (eg, Vice)
|
||||
hp: 100
|
||||
str: 1 # Multiplier of users' missed dailies
|
||||
drop:
|
||||
type: 'pets'
|
||||
type: 'mounts'
|
||||
key: 'BearCub-Polar'
|
||||
text: "Polar Bear Cub (Pet)"
|
||||
text: "Polar Bear (Mount)"
|
||||
gp: 20
|
||||
exp: 100 # Exp bonus from defeating the boss
|
||||
value: 4 # Gem cost to buy, GP sell-back
|
||||
|
||||
evilsanta2:
|
||||
text: "Find Baby Bear"
|
||||
notes: "Mama bear begs you to find her cub. He ran off into the icefields when mama was captured by Evil Santa, find his tracks!"
|
||||
value: 4
|
||||
previous: 'evilsanta'
|
||||
collect:
|
||||
tracks: text: 'Tracks', count: 20
|
||||
branches: text: 'Broken Twigs', count: 10
|
||||
drop: type: 'pets', key: 'BearCub-Polar', text: "Polar Bear (Pet)", gp: 20, exp: 100
|
||||
|
||||
|
||||
_.each api.quests, (v,key) ->
|
||||
_.defaults v, {key}
|
||||
|
|
|
|||
|
|
@ -483,9 +483,9 @@ api.wrap = (user) ->
|
|||
userPets = user.items.pets
|
||||
|
||||
return cb({code:404, message:":pet not found in user.items.pets"}) unless userPets[pet]
|
||||
return cb({code:404, message:":food not found in user.items.food"}) unless user.items.food?[food.name]
|
||||
return cb({code:404, message:":food not found in user.items.food"}) unless user.items.food?[food.key]
|
||||
return cb({code:401, message:"Can't feed this pet."}) if content.specialPets[pet]
|
||||
return cb({code:401, message:"You already have that mount"}) if user.items.mounts[pet] and (userPets[pet] >= 50 or food.name is 'Saddle')
|
||||
return cb({code:401, message:"You already have that mount"}) if user.items.mounts[pet] and (userPets[pet] >= 50 or food.key is 'Saddle')
|
||||
|
||||
message = ''
|
||||
evolve = ->
|
||||
|
|
@ -494,18 +494,18 @@ api.wrap = (user) ->
|
|||
user.items.currentPet = "" if pet is user.items.currentPet
|
||||
message = "You have tamed #{egg}, let's go for a ride!"
|
||||
|
||||
if food.name is 'Saddle'
|
||||
if food.key is 'Saddle'
|
||||
evolve()
|
||||
else
|
||||
if food.target is potion
|
||||
userPets[pet] += 5
|
||||
message = "#{egg} really likes the #{food.name}!"
|
||||
message = "#{egg} really likes the #{food.key}!"
|
||||
else
|
||||
userPets[pet] += 2
|
||||
message = "#{egg} eats the #{food.name} but doesn't seem to enjoy it."
|
||||
message = "#{egg} eats the #{food.key} but doesn't seem to enjoy it."
|
||||
if userPets[pet] >= 50 and !user.items.mounts[pet]
|
||||
evolve()
|
||||
user.items.food[food.name]--
|
||||
user.items.food[food.key]--
|
||||
cb {code:200, message}, req
|
||||
|
||||
# buy is for gear, purchase is for gem-purchaseables (i know, I know...)
|
||||
|
|
@ -864,17 +864,10 @@ api.wrap = (user) ->
|
|||
|
||||
randomDrop: (modifiers) ->
|
||||
{task} = modifiers
|
||||
# limit drops to 2 / day
|
||||
user.items.lastDrop ?=
|
||||
date: +moment().subtract('d', 1) # trick - set it to yesterday on first run, that way they can get drops today
|
||||
count: 0
|
||||
|
||||
reachedDropLimit = (api.daysSince(user.items.lastDrop.date, user.preferences) is 0) and (user.items.lastDrop.count >= 5)
|
||||
return if reachedDropLimit
|
||||
|
||||
# % chance of getting a pet or meat
|
||||
# % chance of getting a drop
|
||||
bonus =
|
||||
Math.abs(task.value) * # + Task Redness (as a %)
|
||||
Math.abs(task.value) * # + Task Redness
|
||||
task.priority + # * Task Priority
|
||||
(task.streak or 0) + # + Streak bonus
|
||||
(user._statsComputed.per * .5) # + Perception
|
||||
|
|
@ -882,6 +875,14 @@ api.wrap = (user) ->
|
|||
chance = api.diminishingReturns(bonus, 1, 0.5) # see HabitRPG/habitrpg#1922 for details
|
||||
console.log "Drop Equation: Bonus(#{bonus.toFixed(3)}), Modified Chance(#{chance.toFixed(3)})\n"
|
||||
|
||||
quest = content.quests[user.party.quest?.key]
|
||||
if quest?.collect and user.fns.predictableRandom(user.stats.gp) < bonus # NOTE: < bonus, higher chance than drops
|
||||
dropK = user.fns.randomVal quest.collect, {key:true}
|
||||
user.party.quest.tally.collect[dropK]++
|
||||
user.markModified? 'party.quest.tally'
|
||||
console.log {tally:user.party.quest.tally}
|
||||
|
||||
return if (api.daysSince(user.items.lastDrop.date, user.preferences) is 0) and (user.items.lastDrop.count >= 5)
|
||||
if user.flags?.dropsEnabled and user.fns.predictableRandom(user.stats.exp) < chance
|
||||
|
||||
# current breakdown - 1% (adjustable) chance on drop
|
||||
|
|
@ -1087,9 +1088,10 @@ api.wrap = (user) ->
|
|||
user.stats.buffs = {str:0,int:0,per:0,con:0,stealth:0,streaks:false}
|
||||
|
||||
# After all is said and done, tally up user's effect on quest, return those values & reset the user's
|
||||
tally = down:user.party.quest.tally.down, up:user.party.quest.tally.up
|
||||
_.merge user.party.quest.tally, {down:0,up:0}
|
||||
tally
|
||||
tally = user.party.quest.tally; _tally = _.cloneDeep tally
|
||||
_.merge tally, {down:0,up:0}
|
||||
tally.collect = _.transform tally.collect, ((m,v,k)->m[k]=0)
|
||||
_tally
|
||||
|
||||
# Registered users with some history
|
||||
preenUserHistory: (minHistLen = 7) ->
|
||||
|
|
|
|||
Loading…
Reference in a new issue