mirror of
https://github.com/sudoxnym/habitica-self-host.git
synced 2026-08-03 04:29:40 +00:00
[https://github.com/HabitRPG/habitrpg/issues/1977] port pet-feeding to
user.ops, so that it's now available in the API. Also add handling of 200 errors to simply notify and continue on up to server (friendly messages)
This commit is contained in:
parent
aac5cc6d39
commit
ab5bd6d5af
2 changed files with 124 additions and 6 deletions
96
dist/habitrpg-shared.js
vendored
96
dist/habitrpg-shared.js
vendored
|
|
@ -10478,9 +10478,15 @@ var process=require("__browserify_process");(function() {
|
|||
});
|
||||
}
|
||||
if (scheduleMisses > 0) {
|
||||
api.score(user, task, 'down', {
|
||||
times: scheduleMisses,
|
||||
cron: true
|
||||
user.ops.score({
|
||||
params: {
|
||||
id: task.id,
|
||||
direction: 'down'
|
||||
},
|
||||
query: {
|
||||
times: scheduleMisses,
|
||||
cron: true
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -10862,7 +10868,40 @@ var process=require("__browserify_process");(function() {
|
|||
|
||||
|
||||
/*
|
||||
This wraps the user prototype, giving it functions
|
||||
User is now wrapped (both on client and server), adding a few new properties:
|
||||
* getters (_statsComputed, tasks, etc)
|
||||
* user.fns, which is a bunch of helper functions
|
||||
These were originally up above, but they make more sense belonging to the user object so we don't have to pass
|
||||
the user object all over the place. In fact, we should pull in more functions such as cron(), updateStats(), etc.
|
||||
* user.ops, which is super important:
|
||||
|
||||
If a function is inside user.ops, it has magical properties. If you call it on the client it updates the user object in
|
||||
the browser and when it's done it POSTs to the server, calling `src/controllers/user.js#OP_NAME` (the exact same name
|
||||
of the op function). The first argument `req` is `{query, body, params}`, it's what the express controller function
|
||||
expects. Because of this, we don't construct op functions in standard way (function(arg1,arg2,arg3){}), but instead
|
||||
the first arg is {query, body, params} and the second is a callback(err, results). `query` is the most commonly-used,
|
||||
but body is useful for updates/creates (eg, tasks), and params are used in those cases too (eg, {op:'updateTask',{params:{id:task.id}, body:task}}})
|
||||
This needs refinement: see http://stackoverflow.com/questions/4024271/rest-api-best-practices-where-to-put-parameters
|
||||
|
||||
If `src/controllers/user.js#OP_NAME` doesn't exist, it's automatically added. It runs the code in user.ops.OP_NAME
|
||||
to update the user model server-side, then performs `user.save()`. You can see this in action for `user.ops.buy`. That
|
||||
function doesn't exist on the server - so the client calls it, it updates user in the browser, auto-POSTs to server, server
|
||||
handles it by calling `user.ops.buy` again (to update user on the server), and then saves. We can do this for
|
||||
everything that doesn't need any code different from what's in user.ops.OP_NAME for special-handling server-side. If we
|
||||
*do* need special handling, just add `src/controllers/user.js#OP_NAME` to override the user.ops.OP_NAME, and just be
|
||||
sure to call user.ops.OP_NAME at some point within the overridden function.
|
||||
|
||||
TODO
|
||||
* Allow different error handling - like "200 - not enough gold" (which shouldn't be treated as 500)
|
||||
* Is this the best way to wrap the user object? I thought of using user.prototype, but user is an object not a Function.
|
||||
user on the server is a Mongoose model, so we can use prototype - but to do it on the client, we'd probably have to
|
||||
move to $resource for user
|
||||
* Move to $resource!
|
||||
* Migrate the remaining parts: Tags, feeding pets, etc
|
||||
|
||||
BUGS
|
||||
* User registration doesn't refresh, and you have to click "Play" again (and refresh *yet again* after getting in)
|
||||
* Daily repeats don't have the days showing up (translations issue?)
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -10897,6 +10936,55 @@ var process=require("__browserify_process");(function() {
|
|||
}
|
||||
return task;
|
||||
},
|
||||
feed: function(req, cb) {
|
||||
var egg, evolve, food, pet, potion, userPets, _ref, _ref1, _ref2, _ref3;
|
||||
_ref2 = [(_ref = req.query) != null ? _ref.pet : void 0, content.food[(_ref1 = req.query) != null ? _ref1.food : void 0]], pet = _ref2[0], food = _ref2[1];
|
||||
_ref3 = pet.split('-'), egg = _ref3[0], potion = _ref3[1];
|
||||
if (!(pet && food)) {
|
||||
return cb("?food=__&pet=__ are both required in query, and must be valid");
|
||||
}
|
||||
if (content.specialPets[pet]) {
|
||||
return cb("Can't feed this pet.");
|
||||
}
|
||||
if (user.items.mounts[pet] && (userPets[pet] >= 50 || food.name === 'Saddle')) {
|
||||
return cb("You already have that mount");
|
||||
}
|
||||
userPets = user.items.pets;
|
||||
evolve = function() {
|
||||
userPets[pet] = 0;
|
||||
user.items.mounts[pet] = true;
|
||||
if (pet === user.items.currentPet) {
|
||||
user.items.currentPet = "";
|
||||
}
|
||||
return cb({
|
||||
code: 200,
|
||||
message: "You have tamed " + egg + ", let's go for a ride!"
|
||||
}, req);
|
||||
};
|
||||
if (food.name === 'Saddle') {
|
||||
evolve();
|
||||
} else {
|
||||
if (food.target === potion) {
|
||||
userPets[pet] += 5;
|
||||
cb({
|
||||
code: 200,
|
||||
message: "" + egg + " really likes the " + food.name + "!"
|
||||
}, req);
|
||||
} else {
|
||||
userPets[pet] += 2;
|
||||
cb({
|
||||
code: 200,
|
||||
message: "" + egg + " eats the " + food.name + " but doesn't seem to enjoy it."
|
||||
}, req);
|
||||
}
|
||||
if (userPets[pet] >= 50 && !user.items.mounts[pet]) {
|
||||
evolve();
|
||||
}
|
||||
}
|
||||
user.items.pets[pet] = userPets[pet];
|
||||
user.items.food[food.name]--;
|
||||
return typeof cb === "function" ? cb(null, req) : void 0;
|
||||
},
|
||||
buy: function(req, cb) {
|
||||
var item, key, _ref;
|
||||
key = req.query.key;
|
||||
|
|
|
|||
|
|
@ -344,7 +344,8 @@ api.cron = (user, options={}) ->
|
|||
_.times daysMissed, (n) ->
|
||||
thatDay = moment(now).subtract('days', n + 1)
|
||||
scheduleMisses++ if api.shouldDo(thatDay, repeat, user.preferences)
|
||||
api.score(user, task, 'down', {times:scheduleMisses, cron:true}) if scheduleMisses > 0
|
||||
if scheduleMisses > 0
|
||||
user.ops.score({params:{id:task.id, direction:'down'}, query:{times:scheduleMisses, cron:true}})
|
||||
|
||||
switch type
|
||||
when 'daily'
|
||||
|
|
@ -647,6 +648,35 @@ api.wrap = (user) ->
|
|||
cb? null, req
|
||||
task
|
||||
|
||||
feed: (req, cb) ->
|
||||
[pet, food] = [req.query?.pet, content.food[req.query?.food]]
|
||||
[egg, potion] = pet.split('-')
|
||||
|
||||
return cb("?food=__&pet=__ are both required in query, and must be valid") unless pet and food # TODO validation on pet string
|
||||
return cb("Can't feed this pet.") if content.specialPets[pet]
|
||||
return cb("You already have that mount") if user.items.mounts[pet] and (userPets[pet] >= 50 or food.name is 'Saddle')
|
||||
|
||||
userPets = user.items.pets
|
||||
evolve = ->
|
||||
userPets[pet] = 0
|
||||
user.items.mounts[pet] = true
|
||||
user.items.currentPet = "" if pet is user.items.currentPet
|
||||
cb {code:200, message:"You have tamed #{egg}, let's go for a ride!"}, req
|
||||
|
||||
if food.name is 'Saddle'
|
||||
evolve()
|
||||
else
|
||||
if food.target is potion
|
||||
userPets[pet] += 5
|
||||
cb {code:200, message: "#{egg} really likes the #{food.name}!"}, req
|
||||
else
|
||||
userPets[pet] += 2
|
||||
cb {code:200, message: "#{egg} eats the #{food.name} but doesn't seem to enjoy it."}, req
|
||||
evolve() if userPets[pet] >= 50 and not user.items.mounts[pet]
|
||||
user.items.pets[pet] = userPets[pet]
|
||||
user.items.food[food.name]--
|
||||
cb? null, req
|
||||
|
||||
buy: (req, cb) ->
|
||||
{key} = req.query
|
||||
item = if key is 'potion' then content.potion else content.gear.flat[key]
|
||||
|
|
@ -694,7 +724,7 @@ api.wrap = (user) ->
|
|||
user.stats.lvl-- if user.stats.lvl > 1
|
||||
|
||||
# Lose a stat point
|
||||
lostStat = randomVal _.reduce ['str','con','per','int'], ((m,k)->(m[k]=k if user.stats[v];m)), {}
|
||||
lostStat = randomVal _.reduce(['str','con','per','int'], ((m,k)->(m[k]=k if user.stats[v];m)), {})
|
||||
user.stats[lostStat]-- if lostStat
|
||||
|
||||
# Lose a gear piece
|
||||
|
|
|
|||
Loading…
Reference in a new issue