Merge branch 'develop' into sabrecat/pet-201511

Conflicts:
	common/dist/sprites/spritesmith-main-5.css
	common/dist/sprites/spritesmith-main-5.png
	common/dist/sprites/spritesmith-main-6.css
	common/dist/sprites/spritesmith-main-6.png
	common/dist/sprites/spritesmith-main-7.css
	common/dist/sprites/spritesmith-main-7.png
	common/dist/sprites/spritesmith-main-8.css
	common/dist/sprites/spritesmith-main-8.png
	common/dist/sprites/spritesmith-main-9.css
	common/dist/sprites/spritesmith-main-9.png
This commit is contained in:
Sabe Jones 2015-11-11 18:36:25 -05:00
commit 83b61f9aa3
99 changed files with 8682 additions and 7987 deletions

View file

@ -1,30 +1,30 @@
.2014_Fall_HealerPROMO2 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -387px -950px;
background-position: -637px -955px;
width: 90px;
height: 90px;
}
.2014_Fall_Mage_PROMO9 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -970px -483px;
background-position: -452px -347px;
width: 120px;
height: 90px;
}
.2014_Fall_RoguePROMO3 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -970px -680px;
background-position: -573px -347px;
width: 105px;
height: 90px;
}
.2014_Fall_Warrior_PROMO {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -569px -950px;
background-position: -590px -461px;
width: 90px;
height: 90px;
}
.promo_backtoschool {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -220px -220px;
background-position: -970px -342px;
width: 150px;
height: 150px;
}
@ -36,49 +36,49 @@
}
.promo_classes_fall_2014 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -326px -664px;
background-position: -326px -760px;
width: 321px;
height: 100px;
}
.promo_classes_fall_2015 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: 0px -564px;
background-position: 0px -660px;
width: 377px;
height: 99px;
}
.promo_dilatoryDistress {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -660px -950px;
background-position: 0px -955px;
width: 90px;
height: 90px;
}
.promo_enchanted_armoire {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -378px -564px;
background-position: -378px -660px;
width: 374px;
height: 76px;
}
.promo_enchanted_armoire_201507 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -289px -859px;
background-position: -970px -641px;
width: 217px;
height: 90px;
}
.promo_enchanted_armoire_201508 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -725px -859px;
background-position: -723px -342px;
width: 180px;
height: 90px;
}
.promo_enchanted_armoire_201509 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -933px -950px;
background-position: -273px -955px;
width: 90px;
height: 90px;
}
.promo_enchanted_armoire_201511 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -970px -392px;
background-position: -1111px -493px;
width: 122px;
height: 90px;
}
@ -90,250 +90,256 @@
}
.promo_haunted_hair {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -970px -148px;
background-position: -1127px -194px;
width: 100px;
height: 137px;
}
.customize-option.promo_haunted_hair {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -995px -163px;
background-position: -1152px -209px;
width: 60px;
height: 60px;
}
.promo_item_notif {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -452px -347px;
background-position: -970px -91px;
width: 249px;
height: 102px;
}
.promo_mystery_201405 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px -182px;
background-position: -546px -955px;
width: 90px;
height: 90px;
}
.promo_mystery_201406 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -970px -771px;
background-position: -311px -220px;
width: 90px;
height: 96px;
}
.promo_mystery_201407 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px -704px;
background-position: -876px -433px;
width: 42px;
height: 62px;
}
.promo_mystery_201408 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px -428px;
background-position: -1188px -641px;
width: 60px;
height: 71px;
}
.promo_mystery_201409 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -842px -950px;
background-position: -182px -955px;
width: 90px;
height: 90px;
}
.promo_mystery_201410 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px -364px;
background-position: -1169px -823px;
width: 72px;
height: 63px;
}
.promo_mystery_201411 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px 0px;
background-position: -364px -955px;
width: 90px;
height: 90px;
}
.promo_mystery_201412 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1154px -634px;
background-position: -904px -342px;
width: 42px;
height: 66px;
}
.promo_mystery_201501 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px -570px;
background-position: -899px -166px;
width: 48px;
height: 63px;
}
.promo_mystery_201502 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -478px -950px;
background-position: -499px -461px;
width: 90px;
height: 90px;
}
.promo_mystery_201503 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px -273px;
background-position: -728px -955px;
width: 90px;
height: 90px;
}
.promo_mystery_201504 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px -500px;
background-position: -1188px -732px;
width: 60px;
height: 69px;
}
.promo_mystery_201505 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -751px -950px;
background-position: -91px -955px;
width: 90px;
height: 90px;
}
.promo_mystery_201506 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px -634px;
background-position: -899px -230px;
width: 42px;
height: 69px;
}
.promo_mystery_201507 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -970px -574px;
background-position: -220px -220px;
width: 90px;
height: 105px;
}
.promo_mystery_201508 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -293px -950px;
background-position: -314px -326px;
width: 93px;
height: 90px;
}
.promo_mystery_201509 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -1111px -91px;
background-position: -455px -955px;
width: 90px;
height: 90px;
}
.promo_mystery_201510 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -199px -950px;
background-position: -220px -326px;
width: 93px;
height: 90px;
}
.promo_mystery_3014 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -507px -859px;
background-position: -970px -732px;
width: 217px;
height: 90px;
}
.promo_orca {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -970px -286px;
background-position: -1121px -342px;
width: 105px;
height: 105px;
}
.promo_partyhats {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -970px -868px;
background-position: -1111px -584px;
width: 115px;
height: 47px;
}
.promo_pastel_skin {
background-image: url(spritesmith-largeSprites-0.png);
background-position: 0px -775px;
background-position: -331px -871px;
width: 330px;
height: 83px;
}
.customize-option.promo_pastel_skin {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -25px -790px;
background-position: -356px -886px;
width: 60px;
height: 60px;
}
.promo_pet_skins {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -970px 0px;
background-position: -970px -493px;
width: 140px;
height: 147px;
}
.customize-option.promo_pet_skins {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -995px -15px;
background-position: -995px -508px;
width: 60px;
height: 60px;
}
.promo_shimmer_hair {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -331px -775px;
background-position: 0px -871px;
width: 330px;
height: 83px;
}
.customize-option.promo_shimmer_hair {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -356px -790px;
background-position: -25px -886px;
width: 60px;
height: 60px;
}
.promo_splashyskins {
background-image: url(spritesmith-largeSprites-0.png);
background-position: 0px -950px;
background-position: -970px -823px;
width: 198px;
height: 91px;
}
.customize-option.promo_splashyskins {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -25px -965px;
background-position: -995px -838px;
width: 60px;
height: 60px;
}
.promo_springclasses2014 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -430px -461px;
background-position: -970px 0px;
width: 288px;
height: 90px;
}
.promo_springclasses2015 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: 0px -859px;
background-position: -430px -557px;
width: 288px;
height: 90px;
}
.promo_summer_classes_2014 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: 0px -461px;
background-position: 0px -557px;
width: 429px;
height: 102px;
}
.promo_summer_classes_2015 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -648px -664px;
background-position: -648px -760px;
width: 300px;
height: 88px;
}
.promo_updos {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -723px -342px;
background-position: -970px -194px;
width: 156px;
height: 147px;
}
.promo_veteran_pets {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -753px -564px;
background-position: -723px -509px;
width: 146px;
height: 75px;
}
.promo_winterclasses2015 {
background-image: url(spritesmith-largeSprites-0.png);
background-position: 0px -664px;
background-position: 0px -760px;
width: 325px;
height: 110px;
}
.promo_winteryhair {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -220px -371px;
background-position: -723px -433px;
width: 152px;
height: 75px;
}
.customize-option.promo_winteryhair {
background-image: url(spritesmith-largeSprites-0.png);
background-position: -245px -386px;
background-position: -748px -448px;
width: 60px;
height: 60px;
}
.avatar_variety {
background-image: url(spritesmith-largeSprites-0.png);
background-position: 0px -461px;
width: 498px;
height: 95px;
}
.party_preview {
background-image: url(spritesmith-largeSprites-0.png);
background-position: 0px 0px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 174 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 KiB

After

Width:  |  Height:  |  Size: 266 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 140 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 130 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 KiB

After

Width:  |  Height:  |  Size: 396 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 154 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 144 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 143 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -60,6 +60,8 @@
"noPermissionEditChallenge": "You don't have permissions to edit this challenge",
"noPermissionDeleteChallenge": "You don't have permissions to delete this challenge",
"noPermissionCloseChallenge": "You don't have permissions to close this challenge",
"congratulations": "Congratulations!",
"hurray": "Hurray!",
"noChallengeOwner": "no owner",
"noChallengeOwnerPopover": "This challenge does not have an owner because the person who created the challenge deleted their account."
}

View file

@ -65,6 +65,10 @@
"ultimGearText": "Has upgraded to the maximum weapon and armor set for the following classes:",
"level": "Level",
"levelUp": "Level Up!",
"gainedLevel": "You gained a level!",
"leveledUp": "By accomplishing your real-life goals, you've grown to <strong>Level <%= level %>!</strong>",
"fullyHealed": "You have been fully healed!",
"huzzah": "Huzzah!",
"mana": "Mana",
"hp": "HP",
"mp": "MP",

View file

@ -74,7 +74,7 @@
"infhQuote": "[Habitica] has really helped me impart structure to my life in graduate school.",
"invalidEmail": "A valid email address is required in order to perform a password reset.",
"irishfeet123Quote": "I've had horrible habits with clearing my place completely after meals and leaving cups all over the place. [Habitica] has cured that!",
"joinOthers": "Join 850,000 people making it fun to achieve goals!",
"joinOthers": "Join 900,000 people making it fun to achieve goals!",
"kazuiQuote": "Before [Habitica], I was stuck with my thesis, as well as dissatisfied with my personal discipline regarding housework and things like learning vocabulary and studying Go theory. It turns out breaking down these tasks into smaller manageable checklists is quite the thing to keep me motivated and constantly working.",
"landingadminlink": "administrative packages",
"landingend": "Not convinced yet?",
@ -182,5 +182,11 @@
"tweet": "Tweet",
"apps": "Apps",
"notifyAndroidApp": "Want us to notify you when the Android app is ready? Sign up for this mailing list!",
"checkOutIOSApp": "Check out our new iOS App!"
"checkOutIOSApp": "Check out our new iOS App!",
"imagine1": "Imagine if improving your life were as fun as playing a game.",
"landingCopy1": "Advance in the game by completing your real-life tasks.",
"landingCopy2": "Battle monsters with friends to stay accountable to your goals.",
"landingCopy3": "Join over 900,000 people having fun as they improve their lives.",
"alreadyHaveAccount": "I already have an account!",
"getStartedNow": "Get Started Now!"
}

View file

@ -134,5 +134,17 @@
"thankyou2": "Sending you a thousand thanks.",
"thankyou3": "I'm very grateful - thank you!",
"thankyouCardAchievementTitle": "Greatly Grateful",
"thankyouCardAchievementText": "Thanks for being thankful! Sent or received <%= cards %> Thank-You cards."
"thankyouCardAchievementText": "Thanks for being thankful! Sent or received <%= cards %> Thank-You cards.",
"streakAchievement": "You earned a streak achievement!",
"firstStreakAchievement": "21-Day Streak",
"streakAchievementCount": "<%= streaks %> 21-Day Streaks",
"twentyOneDays": "You've completed your Daily for 21 days in a row!",
"dontBreakStreak": "Amazing job. Don't break the streak!",
"dontStop": "Don't Stop Now!",
"levelUpShare": "I leveled up in Habitica by improving my real-life habits!",
"questUnlockShare": "I unlocked a new quest in Habitica!",
"hatchPetShare": "I hatched a new pet by completing my real-life tasks!",
"raisePetShare": "I raised a pet into a mount by completing my real-life tasks!",
"wonChallengeShare": "I won a challenge in Habitica!",
"achievementShare": "I earned a new achievement in Habitica!"
}

View file

@ -58,8 +58,16 @@
"firstDrop": "You've unlocked the Drop System! Now when you complete tasks, you have a small chance of finding an item, including eggs, potions, and food! You just found a <strong><%= eggText %> Egg</strong>! <%= eggNotes %>",
"useGems": "If you've got your eye on a pet, but can't wait any longer for it to drop, use Gems in <strong>Inventory > Market</strong> to buy one!",
"hatchAPot": "Hatch a <%= potion %> <%= egg %>?",
"hatchedPet": "You hatched a <%= potion %> <%= egg %>!",
"displayNow": "Display Now",
"displayLater": "Display Later",
"earnedCompanion": "With all your productivity, you've earned a new companion. Feed it to make it grow!",
"feedPet": "Feed <%= article %><%= text %> to your <%= name %>?",
"useSaddle": "Saddle <%= pet %>?",
"raisedPet": "You grew a <%= pet %>!",
"earnedSteed": "By completing your tasks, you've earned a faithful steed!",
"rideNow": "Ride Now",
"rideLater": "Ride Later",
"petName": "<%= potion %> <%= egg %>",
"mountName": "<%= potion %> <%= mount %>",
"petKeyName": "Key to the Kennels",

View file

@ -76,5 +76,7 @@
"startAQuest": "START A QUEST",
"startQuest": "Start Quest",
"whichQuestStart": "Which quest do you want to start?",
"getMoreQuests": "Get more quests"
"getMoreQuests": "Get more quests",
"unlockedAQuest": "You unlocked a quest!",
"leveledUpReceivedQuest": "You leveled up to <strong>Level <%= level %></strong> and received a quest scroll!"
}

View file

@ -14,6 +14,11 @@
"startCollapsedPop": "With this option set, the list of task tags will be hidden when you first open a task for editing.",
"startAdvCollapsed": "Advanced Options in tasks start collapsed",
"startAdvCollapsedPop": "With this option set, Advanced Options will be hidden when you first open a task for editing.",
"dontShowAgain": "Don't show this again",
"suppressLevelUpModal": "Don't show popup when gaining a level",
"suppressHatchPetModal": "Don't show popup when hatching a pet",
"suppressRaisePetModal": "Don't show popup when raising a pet into a mount",
"suppressStreakModal": "Don't show popup when attaining a Streak achievement",
"showTour": "Show Tour",
"restartTour": "Restart the introductory tour from when you first joined Habitica.",
"showBailey": "Show Bailey",
@ -81,7 +86,6 @@
"emailChange1": "To change your email address, please send an email to",
"emailChange2": "admin@habitica.com",
"emailChange3": " including both your old and new email address as well as your User ID.",
"username": "Login Name",
"usernameOrEmail": "Login Name or Email",
"email": "Email",
"registeredWithFb": "Registered with Facebook",
@ -89,7 +93,7 @@
"loginNameDescription2": "User->Profile",
"loginNameDescription3": "to change the name that appears in your avatar and chat messages.",
"emailNotifications": "Email Notifications",
"wonChallenge": "You Won a Challenge",
"wonChallenge": "You won a Challenge!",
"newPM": "Received Private Message",
"giftedGems": "Gifted Gems",
"giftedGemsInfo": "<%= amount %> Gems - by <%= name %>",

View file

@ -251,7 +251,8 @@ angular.module('habitrpg')
$window.location.href='/';
});
} else {
if ($window.location.pathname.indexOf('/static') !== 0){
var isStaticOrSocial = $window.location.pathname.match(/^\/(static|social)/);
if (!isStaticOrSocial){
localStorage.clear();
$window.location.href = '/logout';
}

View file

@ -55,7 +55,7 @@ describe "Push-Notifications", ->
expect(pushSpy.sendNotify).to.have.been.calledOnce
expect(pushSpy.sendNotify).to.have.been.calledWith(
user,
'You Won a Challenge',
'You won a Challenge!',
'challenge-name'
)
done()

View file

@ -18,6 +18,9 @@ describe('Inventory Controller', function() {
food: { Meat: 1 },
pets: {},
mounts: {}
},
preferences: {
suppressModals: {}
}
});
@ -53,14 +56,36 @@ describe('Inventory Controller', function() {
expect(scope.selectedPotion.key).to.eql('Base');
});
it('hatches a pet', function(){
scope.chooseEgg('Cactus');
scope.choosePotion('Base');
expect(user.items.eggs).to.eql({Cactus: 0});
expect(user.items.hatchingPotions).to.eql({Base: 0});
expect(user.items.pets).to.eql({'Cactus-Base': 5});
expect(scope.selectedEgg).to.eql(null);
expect(scope.selectedPotion).to.eql(null);
describe('Hatching Pets', function(){
beforeEach(function() {
sandbox.stub(rootScope, 'openModal');
});
it('hatches a pet', function(){
scope.chooseEgg('Cactus');
scope.choosePotion('Base');
expect(user.items.eggs).to.eql({Cactus: 0});
expect(user.items.hatchingPotions).to.eql({Base: 0});
expect(user.items.pets).to.eql({'Cactus-Base': 5});
expect(scope.selectedEgg).to.eql(null);
expect(scope.selectedPotion).to.eql(null);
});
it('shows a modal for pet hatching', function(){
scope.chooseEgg('Cactus');
scope.choosePotion('Base');
expect(rootScope.openModal).to.have.been.calledOnce;
expect(rootScope.openModal).to.have.been.calledWith('hatchPet');
});
it('does not show pet hatching modal if user has opted out', function(){
user.preferences.suppressModals.hatchPet = true;
scope.chooseEgg('Cactus');
scope.choosePotion('Base');
expect(rootScope.openModal).to.not.be.called;
});
});
it('sells an egg', function(){

View file

@ -1,8 +1,10 @@
"use strict";
angular.module('habitrpg').controller("FooterCtrl",
['$scope', '$rootScope', 'User', '$http', 'Notification', 'ApiUrl',
function($scope, $rootScope, User, $http, Notification, ApiUrl) {
['$scope', '$rootScope', 'User', '$http', 'Notification', 'ApiUrl', 'Social',
function($scope, $rootScope, User, $http, Notification, ApiUrl, Social) {
$scope.loadWidgets = Social.loadWidgets;
if(env.isStaticPage){
$scope.languages = env.avalaibleLanguages;
@ -31,21 +33,6 @@ function($scope, $rootScope, User, $http, Notification, ApiUrl) {
// Stripe
$.getScript('//checkout.stripe.com/v2/checkout.js');
// Twitter
$.getScript('https://platform.twitter.com/widgets.js');
// Facebook
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.5";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
// Tumblr
$.getScript('https://assets.tumblr.com/share-button.js');
/* Google Content Experiments
if (window.env.NODE_ENV === 'production') {
$.getScript('//www.google-analytics.com/cx/api.js?experiment=boVO4eEyRfysNE5D53nCMQ', function(){

View file

@ -1,6 +1,6 @@
habitrpg.controller("InventoryCtrl",
['$rootScope', '$scope', 'Shared', '$window', 'User', 'Content', 'Analytics', 'Quests', 'Stats',
function($rootScope, $scope, Shared, $window, User, Content, Analytics, Quests, Stats) {
['$rootScope', '$scope', 'Shared', '$window', 'User', 'Content', 'Analytics', 'Quests', 'Stats', 'Social',
function($rootScope, $scope, Shared, $window, User, Content, Analytics, Quests, Stats, Social) {
var user = User.user;
@ -11,6 +11,9 @@ habitrpg.controller("InventoryCtrl",
_updateDropAnimalCount(user.items);
// Social sharing buttons
$scope.loadWidgets = Social.loadWidgets;
// Functions from Quests service
$scope.lockQuest = Quests.lockQuest;
@ -112,6 +115,10 @@ habitrpg.controller("InventoryCtrl",
var potName = Content.hatchingPotions[potion.key].text();
if (!$window.confirm(window.env.t('hatchAPot', {potion: potName, egg: eggName}))) return;
user.ops.hatch({params:{egg:egg.key, hatchingPotion:potion.key}});
if (!user.preferences.suppressModals.hatchPet) {
$rootScope.hatchedPet = {egg: eggName, potion: potName, eggKey: egg.key, pet: 'Pet-' + egg.key + '-' + potion.key};
$rootScope.openModal('hatchPet', {controller: 'InventoryCtrl', size: 'sm'});
}
$scope.selectedEgg = null;
$scope.selectedPotion = null;
@ -121,7 +128,7 @@ habitrpg.controller("InventoryCtrl",
if(!user.achievements.beastMaster
&& $scope.petCount >= 90) {
User.user.achievements.beastMaster = true;
$rootScope.openModal('achievements/beastMaster');
$rootScope.openModal('achievements/beastMaster', {controller:'UserCtrl', size:'sm'});
}
// Checks if Triad Bingo has been reached for the first time
@ -129,7 +136,7 @@ habitrpg.controller("InventoryCtrl",
&& $scope.mountCount >= 90
&& Shared.count.dropPetsCurrentlyOwned(User.user.items.pets) >= 90) {
User.user.achievements.triadBingo = true;
$rootScope.openModal('achievements/triadBingo');
$rootScope.openModal('achievements/triadBingo', {controller:'UserCtrl', size:'sm'});
}
}
@ -142,8 +149,9 @@ habitrpg.controller("InventoryCtrl",
// Feeding Pet
if ($scope.selectedFood) {
var food = $scope.selectedFood
if (food.key == 'Saddle') {
var food = $scope.selectedFood;
var startingMounts = $scope.mountCount;
if (food.key === 'Saddle') {
if (!$window.confirm(window.env.t('useSaddle', {pet: petDisplayName}))) return;
} else if (!$window.confirm(window.env.t('feedPet', {name: petDisplayName, article: food.article, text: food.text()}))) {
return;
@ -152,12 +160,16 @@ habitrpg.controller("InventoryCtrl",
$scope.selectedFood = null;
_updateDropAnimalCount(user.items);
if ($scope.mountCount > startingMounts && !user.preferences.suppressModals.raisePet) {
$rootScope.raisedPet = {displayName: petDisplayName, spriteName: pet, egg: egg, potion: potion}
$rootScope.openModal('raisePet', {controller:'InventoryCtrl',size:'sm'});
}
// Checks if mountmaster has been reached for the first time
if(!user.achievements.mountMaster
&& $scope.mountCount >= 90) {
User.user.achievements.mountMaster = true;
$rootScope.openModal('achievements/mountMaster');
$rootScope.openModal('achievements/mountMaster', {controller:'UserCtrl', size:'sm'});
}
// Selecting Pet

View file

@ -27,6 +27,13 @@ habitrpg.controller('NotificationCtrl',
$rootScope.playSound('Achievement_Unlocked');
}, true);
$rootScope.$watch('user.achievements.challenges.length', function(after, before) {
if (after === before) return;
if (after > before) {
$rootScope.openModal('wonChallenge', {controller: 'UserCtrl', size: 'sm'});
}
});
$rootScope.$watch('user.stats.gp', function(after, before) {
if (after == before) return;
if (User.user.stats.lvl == 0) return;
@ -53,6 +60,23 @@ habitrpg.controller('NotificationCtrl',
Notification.mp(mana);
});
$rootScope.$watch('user.stats.lvl', function(after, before) {
if (after <= before) return;
Notification.lvl();
$rootScope.playSound('Level_Up');
if (User.user._tmp && User.user._tmp.drop && (User.user._tmp.drop.type === 'Quest')) return;
if (after === 3) return; // Drop system unlock. FIXME can we do this without hardcoding?
if (after === 10) return; // Class system unlock. FIXME as above
if (after === 50) return; // Orb of Rebirth unlock FIXME as above
if (!User.user.preferences.suppressModals.levelUp) $rootScope.openModal('levelUp', {controller:'UserCtrl', size:'sm'});
});
$rootScope.$watch('!user.flags.classSelected && user.stats.lvl >= 10', function(after, before){
if(after){
$rootScope.openModal('chooseClass', {controller:'UserCtrl', keyboard:false, backdrop:'static'});
}
});
$rootScope.$watch('user._tmp.crit', function(after, before){
if (after == before || !after) return;
var amount = User.user._tmp.crit * 100 - 100;
@ -98,7 +122,7 @@ habitrpg.controller('NotificationCtrl',
Notification.drop(env.t('messageDropFood', {dropArticle: after.article, dropText: text, dropNotes: notes}), after);
} else if (after.type === 'Quest') {
$rootScope.selectedQuest = Content.quests[after.key];
$rootScope.openModal('questDrop', {controller:'PartyCtrl'});
$rootScope.openModal('questDrop', {controller:'PartyCtrl',size:'sm'});
} else if (after.notificationType === 'Mystery') {
text = Content.gear.flat[after.key].text();
Notification.drop(env.t('messageDropMysteryItem', {dropText: text}), after);
@ -111,19 +135,17 @@ habitrpg.controller('NotificationCtrl',
});
$rootScope.$watch('user.achievements.streak', function(after, before){
if(before == undefined || after == before || after < before) return;
if (User.user.achievements.streak > 1) {
Notification.streak(User.user.achievements.streak);
$rootScope.playSound('Achievement_Unlocked');
}
else {
$rootScope.openModal('achievements/streak');
if(before == undefined || after <= before) return;
Notification.streak(User.user.achievements.streak);
$rootScope.playSound('Achievement_Unlocked');
if (!User.user.preferences.suppressModals.streak) {
$rootScope.openModal('achievements/streak', {controller:'UserCtrl'});
}
});
$rootScope.$watch('user.achievements.ultimateGearSets', function(after, before){
if (_.isEqual(after,before) || !_.contains(User.user.achievements.ultimateGearSets, true)) return;
$rootScope.openModal('achievements/ultimateGear');
$rootScope.openModal('achievements/ultimateGear', {controller:'UserCtrl'});
}, true);
$rootScope.$watch('user.flags.armoireEmpty', function(after,before){
@ -133,27 +155,12 @@ habitrpg.controller('NotificationCtrl',
$rootScope.$watch('user.achievements.rebirths', function(after, before){
if(after === before) return;
$rootScope.openModal('achievements/rebirth');
$rootScope.openModal('achievements/rebirth', {controller:'UserCtrl', size: 'sm'});
});
$rootScope.$watch('user.flags.contributor', function(after, before){
if (after === before || after !== true) return;
$rootScope.openModal('achievements/contributor');
});
// Classes modal
$rootScope.$watch('!user.flags.classSelected && user.stats.lvl >= 10', function(after, before){
if(after){
$rootScope.openModal('chooseClass', {controller:'UserCtrl', keyboard:false, backdrop:'static'});
}
});
$rootScope.$watch('user.stats.lvl', function(after, before) {
if (after == before) return;
if (after > before) {
Notification.lvl();
$rootScope.playSound('Level_Up');
}
$rootScope.openModal('achievements/contributor',{controller:'UserCtrl'});
});
// Completed quest modal

View file

@ -1,12 +1,13 @@
'use strict';
habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','Challenges','$state','$compile','Analytics','Quests',
function($rootScope,$scope,Groups,Chat,User,Challenges,$state,$compile,Analytics,Quests) {
habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','Challenges','$state','$compile','Analytics','Quests','Social',
function($rootScope,$scope,Groups,Chat,User,Challenges,$state,$compile,Analytics,Quests,Social) {
$scope.type = 'party';
$scope.text = window.env.t('party');
$scope.group = $rootScope.party = Groups.party();
$scope.newGroup = new Groups.Group({type:'party'});
$scope.inviteOrStartParty = Groups.inviteOrStartParty;
$scope.loadWidgets = Social.loadWidgets;
if ($state.is('options.social.party')) {
$scope.group.$syncParty(); // Sync party automatically when navigating to party page

View file

@ -1,11 +1,13 @@
"use strict";
habitrpg.controller("UserCtrl", ['$rootScope', '$scope', '$location', 'User', '$http', '$state', 'Guide', 'Shared', 'Content', 'Stats',
function($rootScope, $scope, $location, User, $http, $state, Guide, Shared, Content, Stats) {
habitrpg.controller("UserCtrl", ['$rootScope', '$scope', '$location', 'User', '$http', '$state', 'Guide', 'Shared', 'Content', 'Stats', 'Social',
function($rootScope, $scope, $location, User, $http, $state, Guide, Shared, Content, Stats, Social) {
$scope.profile = User.user;
$scope.statCalc = Stats;
$scope.loadWidgets = Social.loadWidgets;
$scope.hideUserAvatar = function() {
$(".userAvatar").hide();
};

View file

@ -108,7 +108,6 @@ angular.module("habitrpg").factory("Notification",
var stack_topright = {"dir1": "down", "dir2": "left", "spacing1": 15, "spacing2": 15, "firstpos1": 60};
function _notify(html, type, icon) {
console.log(type)
var notice = $.pnotify({
type: type || 'warning', //('info', 'text', 'warning', 'success', 'gp', 'xp', 'hp', 'lvl', 'death', 'mp', 'crit')
text: html,

View file

@ -0,0 +1,41 @@
'use strict';
(function(){
angular
.module('habitrpg')
.factory('Social', socialFactory);
socialFactory.$inject = [];
function socialFactory() {
function loadWidgets() {
// Facebook
if (typeof FB === 'undefined') {
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.5";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
} else {
FB.XFBML.parse(); // http://stackoverflow.com/questions/29133563/
}
// Tumblr
$.getScript('https://assets.tumblr.com/share-button.js');
// Twitter
if (typeof twttr === 'undefined') {
$.getScript('https://platform.twitter.com/widgets.js');
} else {
twttr.widgets.load();
}
}
return {
loadWidgets: loadWidgets
}
}
}());

View file

@ -52,6 +52,7 @@
"js/services/challengeServices.js",
"js/services/paymentServices.js",
"js/services/questServices.js",
"js/services/socialServices.js",
"js/services/statServices.js",
"js/filters/money.js",
@ -122,6 +123,7 @@
"js/services/analyticsServices.js",
"js/services/notificationServices.js",
"js/services/sharedServices.js",
"js/services/socialServices.js",
"js/services/statServices.js",
"common/script/public/userServices.js",
"js/controllers/authCtrl.js",
@ -151,6 +153,7 @@
"js/services/analyticsServices.js",
"js/services/notificationServices.js",
"js/services/sharedServices.js",
"js/services/socialServices.js",
"js/services/statServices.js",
"common/script/public/userServices.js",
"js/controllers/authCtrl.js",

View file

@ -1103,7 +1103,7 @@ api.questLeave = function(req, res, next) {
function _purgeFlagInfoFromChat(group, user) {
group.chat = _.filter(group.chat, function(message) { return !message.flagCount || message.flagCount < 2; });
_.each(group.chat, function (message) {
var userHasFlagged = message.flags[user._id];
var userHasFlagged = message.flags && message.flags[user._id];
message.flags = {};
if (userHasFlagged) message.flags[user._id] = userHasFlagged;

View file

@ -378,6 +378,12 @@ var UserSchema = new Schema({
// Those importantAnnouncements are in fact the recapture emails
importantAnnouncements: {type: Boolean, 'default': true},
weeklyRecaps: {type: Boolean, 'default': true}
},
suppressModals: {
levelUp: {type: Boolean, 'default': false},
hatchPet: {type: Boolean, 'default': false},
raisePet: {type: Boolean, 'default': false},
streak: {type: Boolean, 'default': false}
}
},
profile: {

View file

@ -16,7 +16,7 @@ router.get('/', i18n.getUserLanguage, locals, function(req, res) {
});
});
// -------- Marketing --------
// -------- Static Pages --------
var pages = ['front', 'privacy', 'terms', 'api', 'features', 'videos', 'contact', 'plans', 'new-stuff', 'community-guidelines', 'old-news', 'press-kit', 'faq', 'overview', 'apps'];
@ -29,6 +29,19 @@ _.each(pages, function(name){
});
});
// -------- Social Media Sharing --------
var shareables = ['level-up','hatch-pet','raise-pet','unlock-quest','won-challenge','achievement'];
_.each(shareables, function(name){
router.get('/social/' + name, i18n.getUserLanguage, locals, function(req, res) {
res.render( 'social/' + name, {
env: res.locals.habitrpg,
marked: require('marked')
});
});
});
// --------- Redirects --------
router.get('/static/extensions', function(req, res) {

View file

@ -75,7 +75,18 @@ script(type='text/ng-template', id='partials/options.settings.settings.html')
label
input(type='checkbox', ng-model='user.preferences.displayInviteToPartyWhenPartyIs1', ng-change='set({"preferences.displayInviteToPartyWhenPartyIs1": user.preferences.displayInviteToPartyWhenPartyIs1 ? true : false})')
span.hint(popover-trigger='mouseenter', popover-placement='right', popover=env.t('displayInviteToPartyWhenPartyIs1'))=env.t('displayInviteToPartyWhenPartyIs1')
// button.btn.btn-default(ng-click='showTour()', popover-placement='right', popover-trigger='mouseenter', popover=env.t('restartTour'))= env.t('showTour')
.checkbox
label=env.t('suppressLevelUpModal')
input(type='checkbox', ng-model='user.preferences.suppressModals.levelUp', ng-change='set({"preferences.suppressModals.levelUp": user.preferences.suppressModals.levelUp?true: false})')
.checkbox
label=env.t('suppressHatchPetModal')
input(type='checkbox', ng-model='user.preferences.suppressModals.hatchPet', ng-change='set({"preferences.suppressModals.hatchPet": user.preferences.suppressModals.hatchPet?true: false})')
.checkbox
label=env.t('suppressRaisePetModal')
input(type='checkbox', ng-model='user.preferences.suppressModals.raisePet', ng-change='set({"preferences.suppressModals.raisePet": user.preferences.suppressModals.raisePet?true: false})')
.checkbox
label=env.t('suppressStreakModal')
input(type='checkbox', ng-model='user.preferences.suppressModals.streak', ng-change='set({"preferences.suppressModals.streak": user.preferences.suppressModals.streak?true: false})')
hr

View file

@ -60,11 +60,11 @@ footer.footer(ng-controller='FooterCtrl')
.col-sm-3
if (env.NODE_ENV === 'production' && !env.IS_MOBILE)
h4=env.t('footerSocial')
.addthis_toolbox.addthis_default_style(addthis:url='https://habitica.com', addthis:title=env.t('socialTitle'))
.addthis_toolbox.addthis_default_style(addthis:url='https://habitica.com', addthis:title=env.t('socialTitle'), ng-init='loadWidgets()')
table
tr
td
.fb-like(data-href='https://habitica.com/static/front', data-layout='button', data-action='like', data-share='true')
.fb-like(data-href='https://habitica.com/static/front', data-layout='button', data-action='like', data-share='true', data-show-faces='true')
tr
td
a.twitter-share-button(href='https://twitter.com/intent/tweet?text=Improve+yourself+in+the+land+of+Habitica!&via=habitica&url=https://habitica.com/&count=none')=env.t('tweet')

View file

@ -1,99 +1,134 @@
include ../avatar/generated_avatar
mixin achievementFooter
- var tweet = env.t('achievementShare');
.modal-footer(style='margin-top:0', ng-init='loadWidgets()')
.container-fluid
.row.text-center
.col-xs-4
a.twitter-share-button(href='https://twitter.com/intent/tweet?text=#{tweet}&via=habitica&url=#{env.BASE_URL}/social/achievement&count=none')=env.t('tweet')
.col-xs-4
.fb-share-button(data-href='#{env.BASE_URL}/social/achievement', data-layout='button')
.col-xs-4
a.tumblr-share-button(data-href='#{env.BASE_URL}/social/achievement', data-notes='none')
mixin achievementAvatar(badge,margin)
.container-fluid
.row
.col-xs-4(style='padding:0')
div(class='achievement-#{badge}2x' style='margin: 2em auto')
.col-xs-4(style='padding:0')
.herobox(style='padding:0; width:0; height:7em; margin:auto #{margin}em')
.character-sprites(style='width:0')
+generatedAvatar
.col-xs-4(style='padding:0')
div(class='achievement-#{badge}2x' style='margin: 2em auto')
// Streak
script(id='modals/achievements/streak.html', type='text/ng-template')
.modal-header
h4=env.t('modalAchievement')
.modal-body
.achievement.achievement-thermometer
=env.t('streakerAchievement')
.modal-footer
button.btn.btn-default(ng-click='$close()')=env.t('ok')
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom: 0')=env.t('streakAchievement')
+achievementAvatar('thermometer',2.5)
h4(ng-if='user.achievements.streak === 1')=env.t('firstStreakAchievement')
h4(ng-if='user.achievements.streak > 1')=env.t('streakAchievementCount', {streaks:'{{::user.achievements.streak}}'})
p=env.t('twentyOneDays')
p=env.t('dontBreakStreak')
br
button.btn.btn-primary(ng-click='$close()')=env.t('dontStop')
.checkbox
label(style='display:inline-block')=env.t('dontShowAgain')
input(type='checkbox', ng-model='user.preferences.suppressModals.streak', ng-change='set({"preferences.suppressModals.streak": user.preferences.suppressModals.streak?true: false})')
+achievementFooter
// Max Gear
script(id='modals/achievements/ultimateGear.html', type='text/ng-template')
.modal-header
h4=env.t('modalAchievement')
.modal-body
.achievement.achievement-armor
p=env.t('gearAchievement')
br
table.multi-achievement
tr
td(ng-if='::user.achievements.ultimateGearSets.healer').multi-achievement
.achievement-ultimate-healer.multi-achievement
=env.t('healer')
td(ng-if='::user.achievements.ultimateGearSets.wizard').multi-achievement
.achievement-ultimate-mage.multi-achievement
=env.t('mage')
td(ng-if='::user.achievements.ultimateGearSets.rogue').multi-achievement
.achievement-ultimate-rogue.multi-achievement
=env.t('rogue')
td(ng-if='::user.achievements.ultimateGearSets.warrior').multi-achievement
.achievement-ultimate-warrior.multi-achievement
=env.t('warrior')
br
p(ng-if='!(user.achievements.ultimateGearSets.healer && user.achievements.ultimateGearSets.wizard && user.achievements.ultimateGearSets.rogue && user.achievements.ultimateGearSets.warrior)')!=env.t('moreGearAchievements')
br
.shop_armoire.pull-right
p!=env.t("armoireUnlocked")
.modal-footer
button.btn.btn-default(ng-click='$close()')=env.t('ok')
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0')=env.t('modalAchievement')
+achievementAvatar('armor',2.5)
p=env.t('gearAchievement')
br
table.multi-achievement
tr
td(ng-if='::user.achievements.ultimateGearSets.healer').multi-achievement
.achievement-ultimate-healer2x.multi-achievement
=env.t('healer')
td(ng-if='::user.achievements.ultimateGearSets.wizard').multi-achievement
.achievement-ultimate-mage2x.multi-achievement
=env.t('mage')
td(ng-if='::user.achievements.ultimateGearSets.rogue').multi-achievement
.achievement-ultimate-rogue2x.multi-achievement
=env.t('rogue')
td(ng-if='::user.achievements.ultimateGearSets.warrior').multi-achievement
.achievement-ultimate-warrior2x.multi-achievement
=env.t('warrior')
br
div(ng-if='!(user.achievements.ultimateGearSets.healer && user.achievements.ultimateGearSets.wizard && user.achievements.ultimateGearSets.rogue && user.achievements.ultimateGearSets.warrior)')
p!=env.t('moreGearAchievements')
br
.shop_armoire.pull-right
p!=env.t("armoireUnlocked")
br
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
+achievementFooter
// Beast Master
script(id='modals/achievements/beastMaster.html', type='text/ng-template')
.modal-header
h4=env.t('modalAchievement')
.modal-body
p
.achievement.achievement-rat
=env.t('beastAchievement')
.modal-footer
button.btn.btn-default(ng-click='$close()')=env.t('ok')
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0')=env.t('modalAchievement')
+achievementAvatar('rat',0)
p=env.t('beastAchievement')
br
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
+achievementFooter
// Mount Master
script(id='modals/achievements/mountMaster.html', type='text/ng-template')
.modal-header
h4=env.t('modalAchievement')
.modal-body
p
.achievement.achievement-wolf
=env.t('mountAchievement')
.modal-footer
button.btn.btn-default(ng-click='$close()')=env.t('ok')
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0')=env.t('modalAchievement')
+achievementAvatar('wolf',0)
p=env.t('mountAchievement')
br
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
+achievementFooter
// Triad Bingo
script(id='modals/achievements/triadBingo.html', type='text/ng-template')
.modal-header
h4=env.t('modalAchievement')
.modal-body
p
.achievement.achievement-triadbingo
=env.t('triadBingoAchievement')
.modal-footer
button.btn.btn-default(ng-click='$close()')=env.t('ok')
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0')=env.t('modalAchievement')
+achievementAvatar('triadbingo',0)
p=env.t('triadBingoAchievement')
br
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
+achievementFooter
// Contributor
// activated by user.flags.contributor
script(id='modals/achievements/contributor.html', type='text/ng-template')
.modal-header
h4=env.t('modalContribAchievement')
.modal-body
div(class="#{env.worldDmg.guide ? 'npc_justin_broken.float-left' : 'npc_justin.float-left'}")
p
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0')=env.t('modalContribAchievement')
+achievementAvatar('boot',0)
!=env.t('contribModal', {name: "{{user.profile.name}}", level: "{{user.contributor.level}}"}) + ' '
a(href='http://habitica.wikia.com/wiki/Contributor_Rewards' target='_blank')=env.t('contribLink')
.modal-footer
button.btn.btn-default(ng-click='set({"flags.contributor":false}); $close()')=env.t('ok')
br
button.btn.btn-primary(style='margin-top:1em' ng-click='set({"flags.contributor":false}); $close()')=env.t('huzzah')
+achievementFooter
//Rebirth
script(id='modals/achievements/rebirth.html', type='text/ng-template')
.modal-header
h4=env.t('modalAchievement')
.modal-body
.achievement.achievement-sun
div(ng-if='user.achievements.rebirthLevel < 100')
=env.t('rebirthAchievement', {number: "{{user.achievements.rebirths}}", level: "{{user.achievements.rebirthLevel}}"})
div(ng-if='user.achievements.rebirthLevel >= 100')
=env.t('rebirthAchievement100', {number: "{{user.achievements.rebirths}}"})
.modal-footer
button.btn.btn-default(ng-click='$close()')=env.t('ok')
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0')=env.t('modalAchievement')
+achievementAvatar('sun',0)
div(ng-if='user.achievements.rebirthLevel < 100')
=env.t('rebirthAchievement', {number: "{{user.achievements.rebirths}}", level: "{{user.achievements.rebirthLevel}}"})
div(ng-if='user.achievements.rebirthLevel >= 100')
=env.t('rebirthAchievement100', {number: "{{user.achievements.rebirths}}"})
br
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
+achievementFooter

View file

@ -0,0 +1,33 @@
include ../avatar/generated_avatar
script(type='text/ng-template', id='modals/hatchPet.html')
- var tweet = env.t('hatchPetShare');
.modal-content(style='min-width:28em')
.modal-body.text-center(style='padding-bottom:0')
h3(style='margin-bottom: 0')=env.t('hatchedPet',{egg:'{{::hatchedPet.egg}}', potion:'{{::hatchedPet.potion}}'})
.container-fluid
.row(style='margin-bottom:1em', ng-controller='UserCtrl')
.col-xs-4(style='padding:0')
div(class='{{::hatchedPet.pet}}').pull-right
.col-xs-3
.empty_bottles(style='margin-top:2.8em')
.col-xs-5(style='padding:0')
.herobox(style='padding:0; width:0; height:0')
.character-sprites(style='width:0; margin-top:.5em')
+generatedAvatar
p=env.t('earnedCompanion')
br
button.btn.btn-primary(ng-click='choosePet(hatchedPet.eggKey, hatchedPet.potion); $close()')=env.t('displayNow')
button.btn.btn-default(ng-click='$close()')=env.t('displayLater')
.checkbox
label(style='display:inline-block')=env.t('dontShowAgain')
input(type='checkbox', ng-model='user.preferences.suppressModals.hatchPet', ng-change='set({"preferences.suppressModals.hatchPet": user.preferences.suppressModals.hatchPet?true: false})')
.modal-footer(style='margin-top:0', ng-init='loadWidgets()')
.container-fluid
.row
.col-xs-3
a.twitter-share-button(href='https://twitter.com/intent/tweet?text=#{tweet}&via=habitica&url=#{env.BASE_URL}/social/hatch-pet&count=none')=env.t('tweet')
.col-xs-4(style='margin-left:.8em')
.fb-share-button(data-href='#{env.BASE_URL}/social/hatch-pet', data-layout='button')
.col-xs-4(style='margin-left:.8em')
a.tumblr-share-button(data-href='#{env.BASE_URL}/social/hatch-pet', data-notes='none')

View file

@ -14,6 +14,10 @@ include ./limited
include ./invite-friends
include ./welcome.jade
include ./low-health.jade
include ./level-up.jade
include ./hatch-pet.jade
include ./raise-pet.jade
include ./won-challenge.jade
//- Settings
script(type='text/ng-template', id='modals/change-day-start.html')

View file

@ -0,0 +1,31 @@
include ../avatar/generated_avatar
script(type='text/ng-template', id='modals/levelUp.html')
- var tweet = env.t('levelUpShare');
.modal-content(style='min-width:28em')
.modal-body.text-center(style='padding-bottom:0')
h3(style='margin-bottom: 0')=env.t('gainedLevel')
.container-fluid
.row
.herobox(style='margin:auto 8.3em; width: 6em; height: 9em; padding-top: 0')
.character-sprites(style='margin: 0; width: 0')
+generatedAvatar
.row
.herobox(style='margin:auto 8.9em; width: 6em; height: 0; padding-top: 0')
.avatar-level(ng-class='userLevelStyle(user)')=env.t('level')+' {{user.stats.lvl}}'
h4(style='margin-top: 1em')!=env.t('leveledUp', {level:'{{user.stats.lvl}}'})
p=env.t('fullyHealed')
br
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
.checkbox
label(style='display:inline-block')=env.t('dontShowAgain')
input(type='checkbox', ng-model='user.preferences.suppressModals.levelUp', ng-change='set({"preferences.suppressModals.levelUp": user.preferences.suppressModals.levelUp?true: false})')
.modal-footer(style='margin-top:0', ng-init='loadWidgets()')
.container-fluid
.row
.col-xs-3
a.twitter-share-button(href='https://twitter.com/intent/tweet?text=#{tweet}&via=habitica&url=#{env.BASE_URL}/social/level-up&count=none')=env.t('tweet')
.col-xs-4(style='margin-left:.8em')
.fb-share-button(data-href='#{env.BASE_URL}/social/level-up', data-layout='button')
.col-xs-4(style='margin-left:.8em')
a.tumblr-share-button(data-href='#{env.BASE_URL}/social/level-up', data-notes='none')

View file

@ -1,5 +1,6 @@
include ./quest-rewards
include ../mixins
include ../avatar/generated_avatar
mixin questInfo
.pull-right-sm.text-center
@ -85,19 +86,36 @@ script(type='text/ng-template', id='modals/questInvitation.html')
button.btn.btn-primary(ng-click='questAccept(); $close()')=env.t('accept')
script(type='text/ng-template', id='modals/questDrop.html')
.quest-icon.pull-right(class='inventory_quest_scroll_{{::selectedQuest.key}}')
.modal-header
h4=env.t('messageDropQuest')
.modal-body
h4 {{::selectedQuest.text()}}
+questInfo
hr
.npc_ian.pull-left
p=env.t('dropQuestCongrats')
.modal-footer
button.btn.btn-default(ng-click='closeQuest(); $close()')=env.t('questLater')
button.btn.btn-primary(ng-click='inviteOrStartParty(group); $close()', ng-if='!party.members')=env.t('startAParty')
button.btn.btn-primary(ng-click='questInit()', ng-if='party.members')=env.t('inviteParty')
- var tweet = env.t('questUnlockShare');
.modal-content(style='min-width:28em')
.modal-body.text-center
h3=env.t('unlockedAQuest')
p {{::selectedQuest.text()}}
.container-fluid
.row(style='margin-bottom:1em', ng-controller='UserCtrl')
.col-xs-4(style='padding:0')
.herobox(style='padding:0; width: 0; height: 0')
.character-sprites(style='width:0')
+generatedAvatar
.col-xs-4(style='padding:0')
.herobox(style='width: 6.7em; height: 5em; position: absolute')
.avatar-level(ng-class='userLevelStyle(user)')=env.t('level')+' {{user.stats.lvl}}'
.col-xs-4(style='margin-top:1.5em')
.quest-icon(class='inventory_quest_scroll_{{::selectedQuest.key}}')
h4!=env.t('leveledUpReceivedQuest', {level:'{{user.stats.lvl}}'})
.row(style='margin-top:2em')
button.btn.btn-primary(ng-click='inviteOrStartParty(group); $close()', ng-if='!party.members')=env.t('startAParty')
button.btn.btn-primary(ng-click='questInit(); $close()', ng-if='party.members')=env.t('inviteParty')
button.btn.btn-default(ng-click='closeQuest(); $close()')=env.t('questLater')
.modal-footer(style='margin-top:0', ng-init='loadWidgets()')
.container-fluid
.row
.col-xs-3
a.twitter-share-button(href='https://twitter.com/intent/tweet?text=#{tweet}&via=habitica&url=#{env.BASE_URL}/social/unlock-quest&count=none')=env.t('tweet')
.col-xs-4(style='margin-left:.8em')
.fb-share-button(data-href='#{env.BASE_URL}/social/unlock-quest', data-layout='button')
.col-xs-4(style='margin-left:.8em')
a.tumblr-share-button(data-href='#{env.BASE_URL}/social/unlock-quest', data-notes='none')
script(type='text/ng-template', id='modals/ownedQuests.html')
.modal-header

View file

@ -0,0 +1,33 @@
include ../avatar/generated_avatar
script(type='text/ng-template', id='modals/raisePet.html')
- var tweet = env.t('raisePetShare');
.modal-content(style='min-width:28em')
.modal-body.text-center(style='padding-bottom:0')
h3(style='margin-bottom: 0')=env.t('raisedPet',{pet:'{{::raisedPet.displayName}}'})
.container-fluid
.row(style='margin-bottom:1em', ng-controller='UserCtrl')
.col-xs-1
.col-xs-10
.herobox(style='margin:0; padding-top: 0')
.character-sprites(style='width:0; margin-top:.5em')
span(class='Mount_Body_{{::raisedPet.spriteName}}')
span
+generatedAvatar
span(class='Mount_Head_{{::raisedPet.spriteName}}')
p=env.t('earnedSteed')
br
button.btn.btn-primary(ng-click='chooseMount(raisedPet.egg, raisedPet.potion); $close()')=env.t('rideNow')
button.btn.btn-default(ng-click='$close()')=env.t('rideLater')
.checkbox
label(style='display:inline-block')=env.t('dontShowAgain')
input(type='checkbox', ng-model='user.preferences.suppressModals.raisePet', ng-change='set({"preferences.suppressModals.raisePet": user.preferences.suppressModals.raisePet?true: false})')
.modal-footer(style='margin-top:0', ng-init='loadWidgets()')
.container-fluid
.row
.col-xs-3
a.twitter-share-button(href='https://twitter.com/intent/tweet?text=#{tweet}&via=habitica&url=#{env.BASE_URL}/social/raise-pet&count=none')=env.t('tweet')
.col-xs-4(style='margin-left:.8em')
.fb-share-button(data-href='#{env.BASE_URL}/social/raise-pet', data-layout='button')
.col-xs-4(style='margin-left:.8em')
a.tumblr-share-button(data-href='#{env.BASE_URL}/social/raise-pet', data-notes='none')

View file

@ -0,0 +1,38 @@
include ../avatar/generated_avatar
script(type='text/ng-template', id='modals/wonChallenge.html')
- var tweet = env.t('wonChallengeShare');
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom: 0')=env.t('wonChallenge')
h4 {{::user.achievements.challenges[user.achievements.challenges.length - 1]}}
.container-fluid
.row(style='margin-bottom:1em', ng-controller='UserCtrl')
.col-xs-4(style='padding:0')
.container-fluid
.row
.col-xs-4(style='padding:0')
.col-xs-4(style='padding:0')
.achievement-karaoke-2x(style='margin-top: 2em')
.col-xs-4(style='padding:0')
.herobox(style='padding:0; width:0; height:7em')
.character-sprites(style='width:0')
+generatedAvatar
.col-xs-4(style='padding:0')
.container-fluid
.row
.col-xs-4(style='padding:0')
.col-xs-4(style='padding:0')
.achievement-karaoke-2x(style='margin-top: 2em')
p=env.t('congratulations')
br
button.btn.btn-primary(ng-click='$close()')=env.t('hurray')
.modal-footer(style='margin-top:0', ng-init='loadWidgets()')
.container-fluid
.row
.col-xs-3
a.twitter-share-button(href='https://twitter.com/intent/tweet?text=#{tweet}&via=habitica&url=#{env.BASE_URL}/social/won-challenge&count=none')=env.t('tweet')
.col-xs-4(style='margin-left:.8em')
.fb-share-button(data-href='#{env.BASE_URL}/social/won-challenge', data-layout='button')
.col-xs-4(style='margin-left:.8em')
a.tumblr-share-button(data-href='#{env.BASE_URL}/social/won-challenge', data-notes='none')

View file

@ -0,0 +1,9 @@
extends ./layout
block extraHead
- var socialPage = 'achievement'
- var socialTitle = 'Earned an Achievement!'
- var socialDescription = 'I earned a new Achievement on Habitica for working to improve my life!'
block content
include ./landing-page

View file

@ -0,0 +1,9 @@
extends ./layout
block extraHead
- var socialPage = 'hatch-pet'
- var socialTitle = 'New Pet!'
- var socialDescription = 'I worked hard and hatched a new pet! In Habitica, you earn cute companions as you accomplish real-world tasks.'
block content
include ./landing-page

View file

@ -0,0 +1,29 @@
.text-center
#intro(style='padding-bottom:3rem')
h1=env.t('imagine1')
ul.lead
li=env.t('landingCopy1')
li=env.t('landingCopy2')
li=env.t('landingCopy3')
.mobile-container
.row
.col-md-6
.row
img.img-rendering-auto.center-block.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/intro.png')
.row
.avatar_variety.img-rendering-auto.center-block.img-responsive
.col-md-6
+registrationForm
.row
a(ng-click='playButtonClick()')=env.t('alreadyHaveAccount')
.row
.presslogos
=env.t('featuredIn')
br
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/lifehacker.png')
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/nyt-logo.png')
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/makeuseof.png')
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/Forbes_logo.png')
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/Cnetlogo.png')
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/Fast-Company-logo.png')
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/kickstarter-logo.png')

View file

@ -0,0 +1,43 @@
include ../shared/mixins.jade
//-Trick needed to pass 'env' to ./layout
block vars
doctype html
html(ng-app='habitrpg', ng-controller='RootCtrl')
head
block extraHead
title Welcome to Habitica! Your Life, the Role Playing Game
meta(charset='utf-8')
meta(name='viewport', content='width=device-width, maximum-scale=1')
meta(property='og:title', content=socialTitle)
meta(property='og:type', content='website')
meta(property='og:site_name', content='Habitica')
meta(property='og:image', content='https://s3.amazonaws.com/habitica-assets/assets/gryphon_logo_300x300.png')
meta(property='og:url', content='https://habitica.com/social/#{socialPage}')
meta(property='og:description', content=socialDescription)
meta(property='fb:app_id', content='128307497299777')
meta(name='twitter:title' content=socialTitle)
meta(name='twitter:card' content='summary')
meta(name='twitter:site' content='@habitica')
meta(name='twitter:image' content='https://s3.amazonaws.com/habitica-assets/assets/gryphon_logo.png')
meta(name='twitter:description' content=socialDescription)
meta(name='apple-itunes-app' content='app-id=994882113')
link(rel='canonical', href='', type='text/html')
link(rel='shortcut icon', href='/favicon.ico')
link(href='//fonts.googleapis.com/css?family=Lato:400,700', rel='stylesheet', type='text/css')
link(rel='stylesheet', type='text/css', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css')
script(type='text/javascript').
window.env = !{JSON.stringify(env._.pick(env, env.clientVars))};
!= env.getManifestFiles("tmp_static_front")
script(type='text/javascript', src='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js')
script(type='text/javascript', src='https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.1/ui-bootstrap.min.js')
script(type='text/javascript', src='https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.1/ui-bootstrap-tpls.min.js')
body(ng-controller='AuthCtrl')
include ../static/login-modal
include ../shared/mixins
.container
block content

View file

@ -0,0 +1,9 @@
extends ./layout
block extraHead
- var socialPage = 'level-up'
- var socialTitle = 'Level Up!'
- var socialDescription = 'I earned a new level with my accomplishments! In Habitica, your avatar grows in strength as you improve your real-life habits.'
block content
include ./landing-page

View file

@ -0,0 +1,9 @@
extends ./layout
block extraHead
- var socialPage = 'raise-pet'
- var socialTitle = 'Raised a Pet into a Mount!'
- var socialDescription = 'I grew a pet into a trusty mount! In Habitica, collectible pets grow along with you as you advance your real-life goals.'
block content
include ./landing-page

View file

@ -0,0 +1,9 @@
extends ./layout
block extraHead
- var socialPage = 'unlock-quest'
- var socialTitle = 'Unlocked a Quest!'
- var socialDescription = 'I discovered a new Quest! In Habitica, you can battle fearsome monsters and devious villains using your real-life productivity.'
block content
include ./landing-page

View file

@ -0,0 +1,9 @@
extends ./layout
block extraHead
- var socialPage = 'won-challenge'
- var socialTitle = 'Won a Challenge!'
- var socialDescription = 'I stood out from the pack and won a Challenge! In Habitica, users can challenge one another to accomplish goals in all areas of life.'
block content
include ./landing-page

View file

@ -1,3 +1,26 @@
mixin registrationForm
form#registrationForm(ng-submit='register()', name='registrationForm')
.form-group
input.form-control(type='text', ng-model='registerVals.username', placeholder=env.t('username'), spellcheck='false', required)
.form-group
input.form-control(type='email', ng-model='registerVals.email', placeholder=env.t('email'), required)
.form-group
input.form-control(type='password', ng-model='registerVals.password', placeholder=env.t('password'), required)
.form-group
input.form-control(type='password', ng-model='registerVals.confirmPassword', placeholder=env.t('passConfirm'), required)
.form-group
small
=env.t('accept1Terms')
|&nbsp;
a(href='/static/terms' target='_blank')=env.t('terms')
|&nbsp;
=env.t('accept2Terms')
|&nbsp;
a(href='/static/privacy' target='_blank')=env.t('privacy')
| .
.form-group
input.btn.btn-block.btn-lg.btn-success(type='submit', ng-disabled='registrationForm.$invalid || registrationInProgress', value=env.t('getStartedNow'))
script(id='modals/login.html', type='text/ng-template')
.modal-header
button.close(type='button', ng-click='$close()') ×
@ -45,24 +68,4 @@ script(id='modals/login.html', type='text/ng-template')
input.btn.btn-default(type='submit', value=env.t('submit'))
tab(heading=env.t('register'))
form#registrationForm(ng-submit='register()', name='registrationForm')
.form-group
input.form-control(type='text', ng-model='registerVals.username', placeholder=env.t('username'), spellcheck='false', required)
.form-group
input.form-control(type='email', ng-model='registerVals.email', placeholder=env.t('email'), required)
.form-group
input.form-control(type='password', ng-model='registerVals.password', placeholder=env.t('password'), required)
.form-group
input.form-control(type='password', ng-model='registerVals.confirmPassword', placeholder=env.t('passConfirm'), required)
.form-group
small
=env.t('accept1Terms')
|&nbsp;
a(href='/static/terms' target='_blank')=env.t('terms')
|&nbsp;
=env.t('accept2Terms')
|&nbsp;
a(href='/static/privacy' target='_blank')=env.t('privacy')
| .
.form-group
input.btn.btn-block.btn-lg.btn-primary(type='submit', ng-disabled='registrationForm.$invalid || registrationInProgress', value=env.t('register'))
+registrationForm