mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-14 21:27:23 +01:00
* Added image * Added new achievement to user schema * Added new achievement to content * Added new achievement to libs * Added achievement text to locale * Added achievement to notification model and controller * Grant achievement on joining or creating first challenge * Added achievement to modal template * Compiled new sprites * Added integration tests * Fix linting error
This commit is contained in:
@@ -304,5 +304,15 @@ describe('POST /challenges', () => {
|
|||||||
|
|
||||||
await expect(groupLeader.sync()).to.eventually.have.property('challenges').to.include(challenge._id);
|
await expect(groupLeader.sync()).to.eventually.have.property('challenges').to.include(challenge._id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('awards achievement if this is creator\'s first challenge', async () => {
|
||||||
|
await groupLeader.post('/challenges', {
|
||||||
|
group: group._id,
|
||||||
|
name: 'Test Challenge',
|
||||||
|
shortName: 'TC Label',
|
||||||
|
});
|
||||||
|
groupLeader = await groupLeader.sync();
|
||||||
|
expect(groupLeader.achievements.joinedChallenge).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -123,5 +123,12 @@ describe('POST /challenges/:challengeId/join', () => {
|
|||||||
|
|
||||||
await expect(authorizedUser.get('/tags')).to.eventually.have.length(userTagsLength + 1);
|
await expect(authorizedUser.get('/tags')).to.eventually.have.length(userTagsLength + 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('awards achievement if this is user\'s first challenge', async () => {
|
||||||
|
await authorizedUser.post(`/challenges/${challenge._id}/join`);
|
||||||
|
|
||||||
|
await authorizedUser.sync();
|
||||||
|
expect(authorizedUser.achievements.joinedChallenge).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ describe('POST /challenges/:challengeId/winner/:winnerId', () => {
|
|||||||
await sleep(0.5);
|
await sleep(0.5);
|
||||||
|
|
||||||
await expect(winningUser.sync()).to.eventually.have.deep.property('achievements.challenges').to.include(challenge.name);
|
await expect(winningUser.sync()).to.eventually.have.deep.property('achievements.challenges').to.include(challenge.name);
|
||||||
expect(winningUser.notifications.length).to.equal(1);
|
expect(winningUser.notifications.length).to.equal(2); // 2 because winningUser just joined the challenge, which now awards an achievement
|
||||||
expect(winningUser.notifications[0].type).to.equal('WON_CHALLENGE');
|
expect(winningUser.notifications[1].type).to.equal('WON_CHALLENGE');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gives winner gems as reward', async () => {
|
it('gives winner gems as reward', async () => {
|
||||||
|
|||||||
452
website/assets/sprites/dist/spritesmith-main-0.css
vendored
452
website/assets/sprites/dist/spritesmith-main-0.css
vendored
File diff suppressed because it is too large
Load Diff
BIN
website/assets/sprites/dist/spritesmith-main-0.png
vendored
BIN
website/assets/sprites/dist/spritesmith-main-0.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 506 KiB After Width: | Height: | Size: 506 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
@@ -147,6 +147,10 @@ habitrpg.controller('NotificationCtrl',
|
|||||||
$rootScope.playSound('Achievement_Unlocked');
|
$rootScope.playSound('Achievement_Unlocked');
|
||||||
Achievement.displayAchievement('joinedGuild', {size: 'md'});
|
Achievement.displayAchievement('joinedGuild', {size: 'md'});
|
||||||
break;
|
break;
|
||||||
|
case 'CHALLENGE_JOINED_ACHIEVEMENT':
|
||||||
|
$rootScope.playSound('Achievement_Unlocked');
|
||||||
|
Achievement.displayAchievement('joinedChallenge', {size: 'md'});
|
||||||
|
break;
|
||||||
case 'NEW_CONTRIBUTOR_LEVEL':
|
case 'NEW_CONTRIBUTOR_LEVEL':
|
||||||
$rootScope.playSound('Achievement_Unlocked');
|
$rootScope.playSound('Achievement_Unlocked');
|
||||||
Achievement.displayAchievement('contributor', {size: 'md'});
|
Achievement.displayAchievement('contributor', {size: 'md'});
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -79,5 +79,7 @@
|
|||||||
"onlyChalLeaderEditTasks": "Tasks belonging to a challenge can only be edited by the leader.",
|
"onlyChalLeaderEditTasks": "Tasks belonging to a challenge can only be edited by the leader.",
|
||||||
"userAlreadyInChallenge": "User is already participating in this challenge.",
|
"userAlreadyInChallenge": "User is already participating in this challenge.",
|
||||||
"cantOnlyUnlinkChalTask": "Only broken challenges tasks can be unlinked.",
|
"cantOnlyUnlinkChalTask": "Only broken challenges tasks can be unlinked.",
|
||||||
"shortNameTooShort": "Tag Name must have at least 3 characters."
|
"shortNameTooShort": "Tag Name must have at least 3 characters.",
|
||||||
|
"joinedChallenge": "Joined a Challenge",
|
||||||
|
"joinedChallengeText": "This user put themselves to the test by joining a Challenge!"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,11 @@ let basicAchievs = {
|
|||||||
titleKey: 'joinedGuild',
|
titleKey: 'joinedGuild',
|
||||||
textKey: 'joinedGuildText',
|
textKey: 'joinedGuildText',
|
||||||
},
|
},
|
||||||
|
joinedChallenge: {
|
||||||
|
icon: 'achievement-challenge',
|
||||||
|
titleKey: 'joinedChallenge',
|
||||||
|
textKey: 'joinedChallengeText',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Object.assign(achievementsData, basicAchievs);
|
Object.assign(achievementsData, basicAchievs);
|
||||||
|
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ function _getBasicAchievements (user, language) {
|
|||||||
_addSimple(result, user, {path: 'partyOn', language});
|
_addSimple(result, user, {path: 'partyOn', language});
|
||||||
_addSimple(result, user, {path: 'joinedGuild', language});
|
_addSimple(result, user, {path: 'joinedGuild', language});
|
||||||
_addSimple(result, user, {path: 'royallyLoyal', language});
|
_addSimple(result, user, {path: 'royallyLoyal', language});
|
||||||
|
_addSimple(result, user, {path: 'joinedChallenge', language});
|
||||||
|
|
||||||
_addSimpleWithMasterCount(result, user, {path: 'beastMaster', language});
|
_addSimpleWithMasterCount(result, user, {path: 'beastMaster', language});
|
||||||
_addSimpleWithMasterCount(result, user, {path: 'mountMaster', language});
|
_addSimpleWithMasterCount(result, user, {path: 'mountMaster', language});
|
||||||
|
|||||||
@@ -228,6 +228,12 @@ api.createChallenge = {
|
|||||||
let challengeValidationErrors = challenge.validateSync();
|
let challengeValidationErrors = challenge.validateSync();
|
||||||
if (challengeValidationErrors) throw challengeValidationErrors;
|
if (challengeValidationErrors) throw challengeValidationErrors;
|
||||||
|
|
||||||
|
// Add achievement if user's first challenge
|
||||||
|
if (!user.achievements.joinedChallenge) {
|
||||||
|
user.achievements.joinedChallenge = true;
|
||||||
|
user.addNotification('CHALLENGE_JOINED_ACHIEVEMENT');
|
||||||
|
}
|
||||||
|
|
||||||
let results = await Bluebird.all([challenge.save({
|
let results = await Bluebird.all([challenge.save({
|
||||||
validateBeforeSave: false, // already validate
|
validateBeforeSave: false, // already validate
|
||||||
}), group.save()]);
|
}), group.save()]);
|
||||||
@@ -286,6 +292,12 @@ api.joinChallenge = {
|
|||||||
|
|
||||||
challenge.memberCount += 1;
|
challenge.memberCount += 1;
|
||||||
|
|
||||||
|
// Add achievement if user's first challenge
|
||||||
|
if (!user.achievements.joinedChallenge) {
|
||||||
|
user.achievements.joinedChallenge = true;
|
||||||
|
user.addNotification('CHALLENGE_JOINED_ACHIEVEMENT');
|
||||||
|
}
|
||||||
|
|
||||||
// Add all challenge's tasks to user's tasks and save the challenge
|
// Add all challenge's tasks to user's tasks and save the challenge
|
||||||
let results = await Bluebird.all([challenge.syncToUser(user), challenge.save()]);
|
let results = await Bluebird.all([challenge.syncToUser(user), challenge.save()]);
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ let schema = new Schema({
|
|||||||
getwell: Number,
|
getwell: Number,
|
||||||
royallyLoyal: Boolean,
|
royallyLoyal: Boolean,
|
||||||
joinedGuild: Boolean,
|
joinedGuild: Boolean,
|
||||||
|
joinedChallenge: Boolean,
|
||||||
},
|
},
|
||||||
|
|
||||||
backer: {
|
backer: {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const NOTIFICATION_TYPES = [
|
|||||||
'BOSS_DAMAGE', // Not used currently but kept to avoid validation errors
|
'BOSS_DAMAGE', // Not used currently but kept to avoid validation errors
|
||||||
'GUILD_PROMPT',
|
'GUILD_PROMPT',
|
||||||
'GUILD_JOINED_ACHIEVEMENT',
|
'GUILD_JOINED_ACHIEVEMENT',
|
||||||
|
'CHALLENGE_JOINED_ACHIEVEMENT',
|
||||||
];
|
];
|
||||||
|
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 506 KiB After Width: | Height: | Size: 506 KiB |
@@ -163,3 +163,14 @@ script(id='modals/achievements/joinedGuild.html', type='text/ng-template')
|
|||||||
br
|
br
|
||||||
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
|
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
|
||||||
+achievementFooter
|
+achievementFooter
|
||||||
|
|
||||||
|
// Joined Challenge
|
||||||
|
script(id='modals/achievements/joinedChallenge.html', type='text/ng-template')
|
||||||
|
.modal-content(style='min-width:28em')
|
||||||
|
.modal-body.text-center
|
||||||
|
h3(style='margin-bottom:0')=env.t('modalAchievement')
|
||||||
|
+achievementAvatar('challenge',0)
|
||||||
|
p=env.t('joinedChallengeText')
|
||||||
|
br
|
||||||
|
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
|
||||||
|
+achievementFooter
|
||||||
|
|||||||
Reference in New Issue
Block a user