Merge branch 'develop' into TheHollidayInn-challenges-clone

Take specHelper off of global scope
This commit is contained in:
Blade Barringer
2015-06-21 18:59:11 -05:00
98 changed files with 8670 additions and 8152 deletions

View File

@@ -2,12 +2,12 @@
margin-left: 1.25em;
}*/
/* Comment out for holiday events */
/* Comment out for holiday events
.npc_ian {
background: url("/common/img/sprites/npc_ian.gif") no-repeat;
width: 78px;
height: 135px;
}
} */
.Gems {
display:inline-block;

File diff suppressed because one or more lines are too long

View File

@@ -1,216 +1,216 @@
.achievement-alien {
background-image: url(spritesmith0.png);
background-position: -1949px -479px;
background-position: -1949px -1116px;
width: 24px;
height: 26px;
}
.achievement-alpha {
background-image: url(spritesmith0.png);
background-position: -1924px -182px;
background-position: -1924px -819px;
width: 24px;
height: 26px;
}
.achievement-armor {
background-image: url(spritesmith0.png);
background-position: -1924px -479px;
background-position: -1924px -1116px;
width: 24px;
height: 26px;
}
.achievement-boot {
background-image: url(spritesmith0.png);
background-position: -1899px -479px;
background-position: -1899px -1116px;
width: 24px;
height: 26px;
}
.achievement-bow {
background-image: url(spritesmith0.png);
background-position: -1949px -452px;
background-position: -1949px -1089px;
width: 24px;
height: 26px;
}
.achievement-cactus {
background-image: url(spritesmith0.png);
background-position: -1924px -452px;
background-position: -1924px -1089px;
width: 24px;
height: 26px;
}
.achievement-cake {
background-image: url(spritesmith0.png);
background-position: -1899px -452px;
background-position: -1899px -1089px;
width: 24px;
height: 26px;
}
.achievement-cave {
background-image: url(spritesmith0.png);
background-position: -1949px -425px;
background-position: -1949px -1062px;
width: 24px;
height: 26px;
}
.achievement-coffin {
background-image: url(spritesmith0.png);
background-position: -1924px -425px;
background-position: -1924px -1062px;
width: 24px;
height: 26px;
}
.achievement-comment {
background-image: url(spritesmith0.png);
background-position: -1899px -425px;
background-position: -1899px -1062px;
width: 24px;
height: 26px;
}
.achievement-costumeContest {
background-image: url(spritesmith0.png);
background-position: -1949px -398px;
background-position: -1949px -1035px;
width: 24px;
height: 26px;
}
.achievement-dilatory {
background-image: url(spritesmith0.png);
background-position: -1924px -398px;
background-position: -1924px -1035px;
width: 24px;
height: 26px;
}
.achievement-firefox {
background-image: url(spritesmith0.png);
background-position: -1899px -398px;
background-position: -1899px -1035px;
width: 24px;
height: 26px;
}
.achievement-habitBirthday {
background-image: url(spritesmith0.png);
background-position: -1949px -371px;
background-position: -1949px -1008px;
width: 24px;
height: 26px;
}
.achievement-heart {
background-image: url(spritesmith0.png);
background-position: -1924px -371px;
background-position: -1924px -1008px;
width: 24px;
height: 26px;
}
.achievement-karaoke {
background-image: url(spritesmith0.png);
background-position: -1899px -371px;
background-position: -1899px -1008px;
width: 24px;
height: 26px;
}
.achievement-ninja {
background-image: url(spritesmith0.png);
background-position: -1949px -344px;
background-position: -1949px -981px;
width: 24px;
height: 26px;
}
.achievement-nye {
background-image: url(spritesmith0.png);
background-position: -1924px -344px;
background-position: -1924px -981px;
width: 24px;
height: 26px;
}
.achievement-perfect {
background-image: url(spritesmith0.png);
background-position: -1899px -182px;
background-position: -1899px -819px;
width: 24px;
height: 26px;
}
.achievement-rat {
background-image: url(spritesmith0.png);
background-position: -1949px -317px;
background-position: -1949px -954px;
width: 24px;
height: 26px;
}
.achievement-shield {
background-image: url(spritesmith0.png);
background-position: -1924px -317px;
background-position: -1924px -954px;
width: 24px;
height: 26px;
}
.achievement-shinySeed {
background-image: url(spritesmith0.png);
background-position: -1899px -317px;
background-position: -1899px -954px;
width: 24px;
height: 26px;
}
.achievement-snowball {
background-image: url(spritesmith0.png);
background-position: -1949px -290px;
background-position: -1949px -927px;
width: 24px;
height: 26px;
}
.achievement-spookDust {
background-image: url(spritesmith0.png);
background-position: -1924px -290px;
background-position: -1924px -927px;
width: 24px;
height: 26px;
}
.achievement-stoikalm {
background-image: url(spritesmith0.png);
background-position: -1899px -290px;
background-position: -1899px -927px;
width: 24px;
height: 26px;
}
.achievement-sun {
background-image: url(spritesmith0.png);
background-position: -1949px -263px;
background-position: -1949px -900px;
width: 24px;
height: 26px;
}
.achievement-sword {
background-image: url(spritesmith0.png);
background-position: -1924px -263px;
background-position: -1924px -900px;
width: 24px;
height: 26px;
}
.achievement-thermometer {
background-image: url(spritesmith0.png);
background-position: -1899px -263px;
background-position: -1899px -900px;
width: 24px;
height: 26px;
}
.achievement-tree {
background-image: url(spritesmith0.png);
background-position: -1949px -236px;
background-position: -1949px -873px;
width: 24px;
height: 26px;
}
.achievement-triadbingo {
background-image: url(spritesmith0.png);
background-position: -1924px -236px;
background-position: -1924px -873px;
width: 24px;
height: 26px;
}
.achievement-ultimate-healer {
background-image: url(spritesmith0.png);
background-position: -1899px -236px;
background-position: -1899px -873px;
width: 24px;
height: 26px;
}
.achievement-ultimate-mage {
background-image: url(spritesmith0.png);
background-position: -1949px -209px;
background-position: -1949px -846px;
width: 24px;
height: 26px;
}
.achievement-ultimate-rogue {
background-image: url(spritesmith0.png);
background-position: -1924px -209px;
background-position: -1924px -846px;
width: 24px;
height: 26px;
}
.achievement-ultimate-warrior {
background-image: url(spritesmith0.png);
background-position: -1899px -209px;
background-position: -1899px -846px;
width: 24px;
height: 26px;
}
.achievement-valentine {
background-image: url(spritesmith0.png);
background-position: -1949px -182px;
background-position: -1949px -819px;
width: 24px;
height: 26px;
}
.achievement-wolf {
background-image: url(spritesmith0.png);
background-position: -1899px -344px;
background-position: -1899px -981px;
width: 24px;
height: 26px;
}
@@ -1890,13 +1890,13 @@
}
.hair_mustache_1_ppurple {
background-image: url(spritesmith0.png);
background-position: -708px -592px;
background-position: -182px -1434px;
width: 90px;
height: 90px;
}
.customize-option.hair_mustache_1_ppurple {
background-image: url(spritesmith0.png);
background-position: -733px -607px;
background-position: -207px -1449px;
width: 60px;
height: 60px;
}
@@ -1938,13 +1938,13 @@
}
.hair_mustache_1_rainbow {
background-image: url(spritesmith0.png);
background-position: -546px -1434px;
background-position: -708px -592px;
width: 90px;
height: 90px;
}
.customize-option.hair_mustache_1_rainbow {
background-image: url(spritesmith0.png);
background-position: -571px -1449px;
background-position: -733px -607px;
width: 60px;
height: 60px;
}
@@ -3810,431 +3810,515 @@
}
.hair_bangs_3_rainbow {
background-image: url(spritesmith0.png);
background-position: -182px -1434px;
background-position: -1899px -182px;
width: 90px;
height: 90px;
}
.customize-option.hair_bangs_3_rainbow {
background-image: url(spritesmith0.png);
background-position: -207px -1449px;
background-position: -1924px -197px;
width: 60px;
height: 60px;
}
.hair_bangs_3_red {
background-image: url(spritesmith0.png);
background-position: -637px -979px;
background-position: -1899px -273px;
width: 90px;
height: 90px;
}
.customize-option.hair_bangs_3_red {
background-image: url(spritesmith0.png);
background-position: -662px -994px;
background-position: -1924px -288px;
width: 60px;
height: 60px;
}
.hair_bangs_3_snowy {
background-image: url(spritesmith0.png);
background-position: -546px -979px;
background-position: -1899px -364px;
width: 90px;
height: 90px;
}
.customize-option.hair_bangs_3_snowy {
background-image: url(spritesmith0.png);
background-position: -571px -994px;
background-position: -1924px -379px;
width: 60px;
height: 60px;
}
.hair_bangs_3_white {
background-image: url(spritesmith0.png);
background-position: -455px -979px;
background-position: -1899px -455px;
width: 90px;
height: 90px;
}
.customize-option.hair_bangs_3_white {
background-image: url(spritesmith0.png);
background-position: -480px -994px;
background-position: -1924px -470px;
width: 60px;
height: 60px;
}
.hair_bangs_3_winternight {
background-image: url(spritesmith0.png);
background-position: -364px -979px;
background-position: -1899px -546px;
width: 90px;
height: 90px;
}
.customize-option.hair_bangs_3_winternight {
background-image: url(spritesmith0.png);
background-position: -389px -994px;
background-position: -1924px -561px;
width: 60px;
height: 60px;
}
.hair_bangs_3_winterstar {
background-image: url(spritesmith0.png);
background-position: -273px -979px;
background-position: -1899px -637px;
width: 90px;
height: 90px;
}
.customize-option.hair_bangs_3_winterstar {
background-image: url(spritesmith0.png);
background-position: -298px -994px;
background-position: -1924px -652px;
width: 60px;
height: 60px;
}
.hair_bangs_3_yellow {
background-image: url(spritesmith0.png);
background-position: -182px -979px;
background-position: -1899px -728px;
width: 90px;
height: 90px;
}
.customize-option.hair_bangs_3_yellow {
background-image: url(spritesmith0.png);
background-position: -207px -994px;
background-position: -1924px -743px;
width: 60px;
height: 60px;
}
.hair_bangs_3_zombie {
background-image: url(spritesmith0.png);
background-position: -91px -979px;
background-position: -546px -1434px;
width: 90px;
height: 90px;
}
.customize-option.hair_bangs_3_zombie {
background-image: url(spritesmith0.png);
background-position: -116px -994px;
background-position: -571px -1449px;
width: 60px;
height: 60px;
}
.hair_base_10_TRUred {
background-image: url(spritesmith0.png);
background-position: 0px -979px;
background-position: -637px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_TRUred {
background-image: url(spritesmith0.png);
background-position: -25px -994px;
background-position: -662px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_aurora {
background-image: url(spritesmith0.png);
background-position: -989px -819px;
background-position: -546px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_aurora {
background-image: url(spritesmith0.png);
background-position: -1014px -834px;
background-position: -571px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_black {
background-image: url(spritesmith0.png);
background-position: -989px -728px;
background-position: -455px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_black {
background-image: url(spritesmith0.png);
background-position: -1014px -743px;
background-position: -480px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_blond {
background-image: url(spritesmith0.png);
background-position: -989px -637px;
background-position: -364px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_blond {
background-image: url(spritesmith0.png);
background-position: -1014px -652px;
background-position: -389px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_blue {
background-image: url(spritesmith0.png);
background-position: -989px -546px;
background-position: -273px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_blue {
background-image: url(spritesmith0.png);
background-position: -1014px -561px;
background-position: -298px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_brown {
background-image: url(spritesmith0.png);
background-position: -989px -455px;
background-position: -182px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_brown {
background-image: url(spritesmith0.png);
background-position: -1014px -470px;
background-position: -207px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_candycane {
background-image: url(spritesmith0.png);
background-position: -989px -364px;
background-position: -91px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_candycane {
background-image: url(spritesmith0.png);
background-position: -1014px -379px;
background-position: -116px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_candycorn {
background-image: url(spritesmith0.png);
background-position: -989px -273px;
background-position: 0px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_candycorn {
background-image: url(spritesmith0.png);
background-position: -1014px -288px;
background-position: -25px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_festive {
background-image: url(spritesmith0.png);
background-position: -989px -182px;
background-position: -989px -819px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_festive {
background-image: url(spritesmith0.png);
background-position: -1014px -197px;
background-position: -1014px -834px;
width: 60px;
height: 60px;
}
.hair_base_10_frost {
background-image: url(spritesmith0.png);
background-position: -989px -91px;
background-position: -989px -728px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_frost {
background-image: url(spritesmith0.png);
background-position: -1014px -106px;
background-position: -1014px -743px;
width: 60px;
height: 60px;
}
.hair_base_10_ghostwhite {
background-image: url(spritesmith0.png);
background-position: -989px 0px;
background-position: -989px -637px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_ghostwhite {
background-image: url(spritesmith0.png);
background-position: -1014px -15px;
background-position: -1014px -652px;
width: 60px;
height: 60px;
}
.hair_base_10_green {
background-image: url(spritesmith0.png);
background-position: -819px -888px;
background-position: -989px -546px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_green {
background-image: url(spritesmith0.png);
background-position: -844px -903px;
background-position: -1014px -561px;
width: 60px;
height: 60px;
}
.hair_base_10_halloween {
background-image: url(spritesmith0.png);
background-position: -728px -888px;
background-position: -989px -455px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_halloween {
background-image: url(spritesmith0.png);
background-position: -753px -903px;
background-position: -1014px -470px;
width: 60px;
height: 60px;
}
.hair_base_10_holly {
background-image: url(spritesmith0.png);
background-position: -637px -888px;
background-position: -989px -364px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_holly {
background-image: url(spritesmith0.png);
background-position: -662px -903px;
background-position: -1014px -379px;
width: 60px;
height: 60px;
}
.hair_base_10_hollygreen {
background-image: url(spritesmith0.png);
background-position: -546px -888px;
background-position: -989px -273px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_hollygreen {
background-image: url(spritesmith0.png);
background-position: -571px -903px;
background-position: -1014px -288px;
width: 60px;
height: 60px;
}
.hair_base_10_midnight {
background-image: url(spritesmith0.png);
background-position: -455px -888px;
background-position: -989px -182px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_midnight {
background-image: url(spritesmith0.png);
background-position: -480px -903px;
background-position: -1014px -197px;
width: 60px;
height: 60px;
}
.hair_base_10_pblue {
background-image: url(spritesmith0.png);
background-position: -364px -888px;
background-position: -989px -91px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_pblue {
background-image: url(spritesmith0.png);
background-position: -389px -903px;
background-position: -1014px -106px;
width: 60px;
height: 60px;
}
.hair_base_10_pblue2 {
background-image: url(spritesmith0.png);
background-position: -273px -888px;
background-position: -989px 0px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_pblue2 {
background-image: url(spritesmith0.png);
background-position: -298px -903px;
background-position: -1014px -15px;
width: 60px;
height: 60px;
}
.hair_base_10_peppermint {
background-image: url(spritesmith0.png);
background-position: -182px -888px;
background-position: -819px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_peppermint {
background-image: url(spritesmith0.png);
background-position: -207px -903px;
background-position: -844px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_pgreen {
background-image: url(spritesmith0.png);
background-position: -91px -888px;
background-position: -728px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_pgreen {
background-image: url(spritesmith0.png);
background-position: -116px -903px;
background-position: -753px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_pgreen2 {
background-image: url(spritesmith0.png);
background-position: 0px -888px;
background-position: -637px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_pgreen2 {
background-image: url(spritesmith0.png);
background-position: -25px -903px;
background-position: -662px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_porange {
background-image: url(spritesmith0.png);
background-position: -889px -740px;
background-position: -546px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_porange {
background-image: url(spritesmith0.png);
background-position: -914px -755px;
background-position: -571px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_porange2 {
background-image: url(spritesmith0.png);
background-position: -798px -740px;
background-position: -455px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_porange2 {
background-image: url(spritesmith0.png);
background-position: -823px -755px;
background-position: -480px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_ppink {
background-image: url(spritesmith0.png);
background-position: -707px -740px;
background-position: -364px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_ppink {
background-image: url(spritesmith0.png);
background-position: -732px -755px;
background-position: -389px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_ppink2 {
background-image: url(spritesmith0.png);
background-position: -1080px 0px;
background-position: -273px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_ppink2 {
background-image: url(spritesmith0.png);
background-position: -1105px -15px;
background-position: -298px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_ppurple {
background-image: url(spritesmith0.png);
background-position: -910px -979px;
background-position: -182px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_ppurple {
background-image: url(spritesmith0.png);
background-position: -935px -994px;
background-position: -207px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_ppurple2 {
background-image: url(spritesmith0.png);
background-position: -819px -979px;
background-position: -91px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_ppurple2 {
background-image: url(spritesmith0.png);
background-position: -844px -994px;
background-position: -116px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_pumpkin {
background-image: url(spritesmith0.png);
background-position: -728px -979px;
background-position: 0px -888px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_pumpkin {
background-image: url(spritesmith0.png);
background-position: -25px -903px;
width: 60px;
height: 60px;
}
.hair_base_10_purple {
background-image: url(spritesmith0.png);
background-position: -889px -740px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_purple {
background-image: url(spritesmith0.png);
background-position: -914px -755px;
width: 60px;
height: 60px;
}
.hair_base_10_pyellow {
background-image: url(spritesmith0.png);
background-position: -798px -740px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_pyellow {
background-image: url(spritesmith0.png);
background-position: -823px -755px;
width: 60px;
height: 60px;
}
.hair_base_10_pyellow2 {
background-image: url(spritesmith0.png);
background-position: -707px -740px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_pyellow2 {
background-image: url(spritesmith0.png);
background-position: -732px -755px;
width: 60px;
height: 60px;
}
.hair_base_10_rainbow {
background-image: url(spritesmith0.png);
background-position: -1080px 0px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_rainbow {
background-image: url(spritesmith0.png);
background-position: -1105px -15px;
width: 60px;
height: 60px;
}
.hair_base_10_red {
background-image: url(spritesmith0.png);
background-position: -910px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_red {
background-image: url(spritesmith0.png);
background-position: -935px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_snowy {
background-image: url(spritesmith0.png);
background-position: -819px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_snowy {
background-image: url(spritesmith0.png);
background-position: -844px -994px;
width: 60px;
height: 60px;
}
.hair_base_10_white {
background-image: url(spritesmith0.png);
background-position: -728px -979px;
width: 90px;
height: 90px;
}
.customize-option.hair_base_10_white {
background-image: url(spritesmith0.png);
background-position: -753px -994px;
width: 60px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 KiB

After

Width:  |  Height:  |  Size: 306 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 80 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 152 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 156 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 696 KiB

After

Width:  |  Height:  |  Size: 733 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 KiB

After

Width:  |  Height:  |  Size: 366 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 KiB

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 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: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 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: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 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.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -129,6 +129,15 @@
"weaponSpecialSpring2015HealerText": "Cat Rattle",
"weaponSpecialSpring2015HealerNotes": "When you wave it, it makes a fascinating clickety noise that would keep ANYONE entertained for hours. Increases Intelligence by <%= int %>. Limited Edition 2015 Spring Gear.",
"weaponSpecialSummer2015RogueText": "Firing Coral",
"weaponSpecialSummer2015RogueNotes": "This relative of fire coral has the ability to propel its venom through the water. Increases Strength by <%= str %>. Limited Edition 2015 Summer Gear.",
"weaponSpecialSummer2015WarriorText": "Sun Swordfish",
"weaponSpecialSummer2015WarriorNotes": "The Sun Swordfish is a fearsome weapon, provided that it can be induced to stop wriggling. Increases Strength by <%= str %>. Limited Edition 2015 Summer Gear.",
"weaponSpecialSummer2015MageText": "Soothsayer Staff",
"weaponSpecialSummer2015MageNotes": "Hidden power glimmers in the jewels of this staff. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2015 Summer Gear.",
"weaponSpecialSummer2015HealerText": "Wand of the Waves",
"weaponSpecialSummer2015HealerNotes": "Cures seasickness and sea sickness! Increases Intelligence by <%= int %>. Limited Edition 2015 Summer Gear.",
"weaponMystery201411Text": "Pitchfork of Feasting",
"weaponMystery201411Notes": "Stab your enemies or dig in to your favorite foods - this versatile pitchfork does it all! Confers no benefit. November 2014 Subscriber Item.",
"weaponMystery201502Text": "Shimmery Winged Staff of Love and Also Truth",
@@ -260,6 +269,15 @@
"armorSpecialSpring2015HealerText": "Comforting Catsuit",
"armorSpecialSpring2015HealerNotes": "This soft catsuit is comfortable, and as comforting as mint tea. Increases Constitution by <%= con %>. Limited Edition 2015 Spring Gear.",
"armorSpecialSummer2015RogueText": "Ruby Tail",
"armorSpecialSummer2015RogueNotes": "This garment of shimmering scales transforms its wearer into a real Reef Renegade! Increases Perception by <%= per %>. Limited Edition 2015 Summer Gear.",
"armorSpecialSummer2015WarriorText": "Golden Tail",
"armorSpecialSummer2015WarriorNotes": "This garment of shimmering scales transforms its wearer into a real Sunfish Warrior! Increases Constitution by <%= con %>. Limited Edition 2015 Summer Gear.",
"armorSpecialSummer2015MageText": "Soothsayer Robes",
"armorSpecialSummer2015MageNotes": "Hidden power resides in the puffs of these sleeves. Increases Intelligence by <%= int %>. Limited Edition 2015 Summer Gear.",
"armorSpecialSummer2015HealerText": "Sailor's Armor",
"armorSpecialSummer2015HealerNotes": "This armor lets everyone know that you are an honest merchant sailor who would never dream of behaving like a scalawag. Increases Constitution by <%= con %>. Limited Edition 2015 Summer Gear.",
"armorMystery201402Text": "Messenger Robes",
"armorMystery201402Notes": "Shimmering and strong, these robes have many pockets to carry letters. Confers no benefit. February 2014 Subscriber Item.",
"armorMystery201403Text": "Forest Walker Armor",
@@ -406,6 +424,15 @@
"headSpecialSpring2015HealerText": "Comforting Crown",
"headSpecialSpring2015HealerNotes": "The pearl at the center of this crown calms and comforts those around it. Increases Intelligence by <%= int %>. Limited Edition 2015 Spring Gear.",
"headSpecialSummer2015RogueText": "Renegade Hat",
"headSpecialSummer2015RogueNotes": "This pirate hat fell overboard and has been decorated with scraps of fire coral. Increases Perception by <%= per %>. Limited Edition 2015 Summer Gear.",
"headSpecialSummer2015WarriorText": "Jeweled Oceanic Helm",
"headSpecialSummer2015WarriorNotes": "Crafted of deep-ocean metal by the artisans of Dilatory, this helm is strong and handsome. Increases Strength by <%= str %>. Limited Edition 2015 Summer Gear.",
"headSpecialSummer2015MageText": "Soothsayer Scarf",
"headSpecialSummer2015MageNotes": "Hidden power shines in the threads of this scarf. Increases Perception by <%= per %>. Limited Edition 2015 Summer Gear.",
"headSpecialSummer2015HealerText": "Sailor's Cap",
"headSpecialSummer2015HealerNotes": "With your sailor's cap set firmly on your head, you can navigate even the stormiest seas! Increases Intelligence by <%= int %>. Limited Edition 2015 Summer Gear.",
"headSpecialGaymerxText": "Rainbow Warrior Helm",
"headSpecialGaymerxNotes": "In celebration of pride season and GaymerX, this special helmet is decorated with a radiant, colorful rainbow pattern! GaymerX is a game convention celebrating LGBTQ and gaming and is open to everyone. It takes place at the InterContinental in downtown San Francisco on July 11-13! Confers no benefit.",
@@ -518,12 +545,20 @@
"shieldSpecialSpring2015HealerText": "Patterned Pillow",
"shieldSpecialSpring2015HealerNotes": "You can rest your head on this soft pillow, or you can wrestle it with your fearsome claws. Rawr! Increases Constitution by <%= con %>. Limited Edition 2015 Spring Gear.",
"shieldSpecialSummer2015RogueText": "Firing Coral",
"shieldSpecialSummer2015RogueNotes": "This relative of fire coral has the ability to propel its venom through the water. Increases Strength by <%= str %>. Limited Edition 2015 Summer Gear.",
"shieldSpecialSummer2015WarriorText": "Sunfish Shield",
"shieldSpecialSummer2015WarriorNotes": "Crafted of deep-ocean metal by the artisans of Dilatory, this shield shines like the sand and the sea. Increases Constitution by <%= con %>. Limited Edition 2015 Summer Gear.",
"shieldSpecialSummer2015HealerText": "Strapping Shield",
"shieldSpecialSummer2015HealerNotes": "Use this shield to bash away bilge rats. Increases Constitution by <%= con %>. Limited Edition 2015 Summer Gear.",
"shieldMystery301405Text": "Clock Shield",
"shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.",
"shieldArmoireGladiatorShieldText": "Gladiator Shield",
"shieldArmoireGladiatorShieldNotes": "To be a gladiator you must.... eh, whatever, just bash them with your shield. Increases Constitution by <%= con %> and Strength by <%= str %>. Enchanted Armoire: Gladiator Set (Item 3 of 3).",
"back": "Back Accessory",
"backBase0Text": "No Back Accessory",
"backBase0Notes": "No Back Accessory.",
@@ -541,6 +576,7 @@
"backSpecialWonderconBlackText": "Sneaky Cape",
"backSpecialWonderconBlackNotes": "Spun of shadows and whispers. Confers no benefit. Special Edition Convention Item.",
"body": "Body Accessory",
"bodyBase0Text": "No Body Accessory",
"bodyBase0Notes": "No Body Accessory.",
@@ -556,6 +592,15 @@
"bodySpecialSummerHealerText": "Coral Collar",
"bodySpecialSummerHealerNotes": "A stylish collar of live coral! Confers no benefit. Limited Edition 2014 Summer Gear.",
"bodySpecialSummer2015RogueText": "Renegade Sash",
"bodySpecialSummer2015RogueNotes": "You can't be a true Renegade without panache... and a sash. Confers no benefit. Limited Edition 2015 Summer Gear.",
"bodySpecialSummer2015WarriorText": "Oceanic Spikes",
"bodySpecialSummer2015WarriorNotes": "Each spike drips jellyfish venom, defending the wearer. Confers no benefit. Limited Edition 2015 Summer Gear.",
"bodySpecialSummer2015MageText": "Golden Buckle",
"bodySpecialSummer2015MageNotes": "This buckle adds no power at all, but it's shiny. Confers no benefit. Limited Edition 2015 Summer Gear.",
"bodySpecialSummer2015HealerText": "Sailor's Neckerchief",
"bodySpecialSummer2015HealerNotes": "Yo ho ho? No, no, no! Confers no benefit. Limited Edition 2015 Summer Gear.",
"headAccessory": "head accessory",
"accessories": "Accessories",
"animalEars": "Animal Ears",
@@ -609,6 +654,7 @@
"headAccessoryMystery301405Text": "Headwear Goggles",
"headAccessoryMystery301405Notes": "\"Goggles are for your eyes,\" they said. \"Nobody wants goggles that you can only wear on your head,\" they said. Hah! You sure showed them! Confers no benefit. August 3015 Subscriber Item.",
"eyewear": "Eyewear",
"eyewearBase0Text": "No Eyewear",
"eyewearBase0Notes": "No Eyewear.",

View File

@@ -25,6 +25,7 @@
"seasonalShopTitle": "<%= linkStart %>Seasonal Sorceress<%= linkEnd %>",
"seasonalShopClosedText": "The Seasonal Shop is currently closed!! I don't know where the Seasonal Sorceress is now, but I bet she'll be back during the next <%= linkStart %>Grand Gala<%= linkEnd %>!",
"seasonalShopText": "Welcome to the Seasonal Shop!! We're stocking springtime <a href='http://habitrpg.wikia.com/wiki/Item_Availability' target='_blank'>Seasonal Edition</a> goodies at the moment. Everything here will be available to purchase during the Spring Fling event each year, but we're only open until April 30th, so be sure to stock up now, or you'll have to wait a year to buy these items again!",
"seasonalShopSummerText": "Welcome to the Seasonal Shop!! We're stocking summertime <a href='http://habitrpg.wikia.com/wiki/Item_Availability' target='_blank'>Seasonal Edition</a> goodies at the moment. Everything here will be available to purchase during the Summer Splash event each year, but we're only open until July 31st, so be sure to stock up now, or you'll have to wait a year to buy these items again!",
"seasonalShopRebirth": "If you've used the Orb of Rebirth, you can repurchase this equipment in the Rewards Column after you unlock the Item Shop. Initially, you'll only be able to purchase the items for your current class (Warrior by default), but fear not, the other class-specific items will become available if you switch to that class.",
"candycaneSet": "Candy Cane (Mage)",
"skiSet": "Ski-sassin (Rogue)",
@@ -44,5 +45,9 @@
"mightyBunnySet": "Mighty Bunny (Warrior)",
"magicMouseSet": "Magic Mouse (Mage)",
"lovingPupSet": "Loving Pup (Healer)",
"stealthyKittySet": "Stealthy Kitty (Rogue)"
"stealthyKittySet": "Stealthy Kitty (Rogue)",
"daringSwashbucklerSet": "Daring Swashbuckler (Warrior)",
"emeraldMermageSet": "Emerald Mermage (Mage)",
"reefSeahealerSet": "Reef Seahealer (Healer)",
"roguishPirateSet": "Roguish Pirate (Rogue)"
}

View File

@@ -20,6 +20,9 @@ classes = ['warrior', 'rogue', 'healer', 'wizard']
gearTypes = [ 'weapon', 'armor', 'head', 'shield', 'body', 'back', 'headAccessory', 'eyewear']
events =
# IMPORTANT: The end date should be one to two days AFTER the actual end of
# the event, to allow people in different timezones to still buy the
# event gear up until at least the actual end of the event.
winter: {start:'2013-12-31',end:'2014-02-01'}
birthday: {start:'2013-01-30',end:'2014-02-01'}
spring: {start:'2014-03-21',end:'2014-05-01'}
@@ -28,9 +31,7 @@ events =
fall: {start:'2014-09-21',end:'2014-11-01'}
winter2015: {start:'2014-12-21',end:'2015-02-02'}
spring2015: {start:'2015-03-20',end:'2015-05-02'}
# IMPORTANT: The end date should be one to two days AFTER the actual end of
# the event, to allow people in different timezones to still buy the
# event gear up until at least the actual end of the event.
summer2015: {start:'2015-06-20',end:'2015-08-02'}
api.mystery =
201402: {start:'2014-02-22',end:'2014-02-28', text:'Winged Messenger Set'}
@@ -135,6 +136,11 @@ gear =
spring2015Warrior: event: events.spring2015, specialClass: 'warrior', text: t('weaponSpecialSpring2015WarriorText'), notes: t('weaponSpecialSpring2015WarriorNotes', {str: 15}), value: 90, str: 15
spring2015Mage: event: events.spring2015, specialClass: 'wizard', twoHanded:true, text: t('weaponSpecialSpring2015MageText'), notes: t('weaponSpecialSpring2015MageNotes', {int: 15, per: 7}), value: 160, int:15, per:7
spring2015Healer: event: events.spring2015, specialClass: 'healer', text: t('weaponSpecialSpring2015HealerText'), notes: t('weaponSpecialSpring2015HealerNotes', {int: 9}), value: 90, int: 9
# Summer 2015
summer2015Rogue: event: events.summer2015, specialClass: 'rogue', text: t('weaponSpecialSummer2015RogueText'), notes: t('weaponSpecialSummer2015RogueNotes', {str: 8}), value: 80, str: 8
summer2015Warrior: event: events.summer2015, specialClass: 'warrior', text: t('weaponSpecialSummer2015WarriorText'), notes: t('weaponSpecialSummer2015WarriorNotes', {str: 15}), value: 90, str: 15
summer2015Mage: event: events.summer2015, specialClass: 'wizard', twoHanded:true, text: t('weaponSpecialSummer2015MageText'), notes: t('weaponSpecialSummer2015MageNotes', {int: 15, per: 7}), value: 160, int:15, per:7
summer2015Healer: event: events.summer2015, specialClass: 'healer', text: t('weaponSpecialSummer2015HealerText'), notes: t('weaponSpecialSummer2015HealerNotes', {int: 9}), value: 90, int: 9
mystery:
201411: text: t('weaponMystery201411Text'), notes: t('weaponMystery201411Notes'), mystery:'201411', value: 0
201502: text: t('weaponMystery201502Text'), notes: t('weaponMystery201502Notes'), mystery:'201502', value: 0
@@ -211,6 +217,11 @@ gear =
spring2015Warrior: event: events.spring2015, specialClass: 'warrior', text: t('armorSpecialSpring2015WarriorText'), notes: t('armorSpecialSpring2015WarriorNotes', {con: 9}), value: 90, con: 9
spring2015Mage: event: events.spring2015, specialClass: 'wizard', text: t('armorSpecialSpring2015MageText'), notes: t('armorSpecialSpring2015MageNotes', {int: 9}), value: 90, int: 9
spring2015Healer: event: events.spring2015, specialClass: 'healer', text: t('armorSpecialSpring2015HealerText'), notes: t('armorSpecialSpring2015HealerNotes', {con: 15}), value: 90, con: 15
# Summer 2015
summer2015Rogue: event: events.summer2015, specialClass: 'rogue', text: t('armorSpecialSummer2015RogueText'), notes: t('armorSpecialSummer2015RogueNotes', {per: 15}), value: 90, per: 15
summer2015Warrior: event: events.summer2015, specialClass: 'warrior', text: t('armorSpecialSummer2015WarriorText'), notes: t('armorSpecialSummer2015WarriorNotes', {con: 9}), value: 90, con: 9
summer2015Mage: event: events.summer2015, specialClass: 'wizard', text: t('armorSpecialSummer2015MageText'), notes: t('armorSpecialSummer2015MageNotes', {int: 9}), value: 90, int: 9
summer2015Healer: event: events.summer2015, specialClass: 'healer', text: t('armorSpecialSummer2015HealerText'), notes: t('armorSpecialSummer2015HealerNotes', {con: 15}), value: 90, con: 15
# Other
gaymerx: event: events.gaymerx, text: t('armorSpecialGaymerxText'), notes: t('armorSpecialGaymerxNotes'), value: 0
mystery:
@@ -298,6 +309,11 @@ gear =
spring2015Warrior: event: events.spring2015, specialClass: 'warrior', text: t('headSpecialSpring2015WarriorText'), notes: t('headSpecialSpring2015WarriorNotes', {str: 9}),value: 60,str: 9
spring2015Mage: event: events.spring2015, specialClass: 'wizard', text: t('headSpecialSpring2015MageText'), notes: t('headSpecialSpring2015MageNotes', {per: 7}),value: 60,per: 7
spring2015Healer: event: events.spring2015, specialClass: 'healer', text: t('headSpecialSpring2015HealerText'), notes: t('headSpecialSpring2015HealerNotes', {int: 7}), value: 60, int: 7
# Summer 2015
summer2015Rogue: event: events.summer2015, specialClass: 'rogue', text: t('headSpecialSummer2015RogueText'), notes: t('headSpecialSummer2015RogueNotes', {per: 9}),value: 60,per: 9
summer2015Warrior: event: events.summer2015, specialClass: 'warrior', text: t('headSpecialSummer2015WarriorText'), notes: t('headSpecialSummer2015WarriorNotes', {str: 9}),value: 60,str: 9
summer2015Mage: event: events.summer2015, specialClass: 'wizard', text: t('headSpecialSummer2015MageText'), notes: t('headSpecialSummer2015MageNotes', {per: 7}),value: 60,per: 7
summer2015Healer: event: events.summer2015, specialClass: 'healer', text: t('headSpecialSummer2015HealerText'), notes: t('headSpecialSummer2015HealerNotes', {int: 7}), value: 60, int: 7
# Other
gaymerx: event: events.gaymerx, text: t('headSpecialGaymerxText'), notes: t('headSpecialGaymerxNotes'), value: 0
mystery:
@@ -375,6 +391,10 @@ gear =
spring2015Rogue: event: events.spring2015, specialClass: 'rogue', text: t('shieldSpecialSpring2015RogueText'), notes: t('shieldSpecialSpring2015RogueNotes', {str: 8}), value: 80, str: 8
spring2015Warrior: event: events.spring2015, specialClass: 'warrior', text: t('shieldSpecialSpring2015WarriorText'), notes: t('shieldSpecialSpring2015WarriorNotes', {con: 7}), value: 70, con: 7
spring2015Healer: event: events.spring2015, specialClass: 'healer', text: t('shieldSpecialSpring2015HealerText'), notes: t('shieldSpecialSpring2015HealerNotes', {con: 9}), value: 70, con: 9
# Summer 2015
summer2015Rogue: event: events.summer2015, specialClass: 'rogue', text: t('shieldSpecialSummer2015RogueText'), notes: t('shieldSpecialSummer2015RogueNotes', {str: 8}), value: 80, str: 8
summer2015Warrior: event: events.summer2015, specialClass: 'warrior', text: t('shieldSpecialSummer2015WarriorText'), notes: t('shieldSpecialSummer2015WarriorNotes', {con: 7}), value: 70, con: 7
summer2015Healer: event: events.summer2015, specialClass: 'healer', text: t('shieldSpecialSummer2015HealerText'), notes: t('shieldSpecialSummer2015HealerNotes', {con: 9}), value: 70, con: 9
mystery:
301405: text: t('shieldMystery301405Text'), notes: t('shieldMystery301405Notes'), mystery:'301405', value: 0
armoire:
@@ -402,6 +422,11 @@ gear =
# Summer
summerHealer: event: events.summer, specialClass: 'healer', text: t('bodySpecialSummerHealerText'), notes: t('bodySpecialSummerHealerNotes'), value: 20
summerMage: event: events.summer, specialClass: 'wizard', text: t('bodySpecialSummerMageText'), notes: t('bodySpecialSummerMageNotes'), value: 20
# Summer 2015
summer2015Healer: event: events.summer2015, specialClass: 'healer', text: t('bodySpecialSummer2015HealerText'), notes: t('bodySpecialSummer2015HealerNotes'), value: 20
summer2015Mage: event: events.summer2015, specialClass: 'wizard', text: t('bodySpecialSummer2015MageText'), notes: t('bodySpecialSummer2015MageNotes'), value: 20
summer2015Rogue: event: events.summer2015, specialClass: 'rogue', text: t('bodySpecialSummer2015RogueText'), notes: t('bodySpecialSummer2015RogueNotes'), value: 20
summer2015Warrior: event: events.summer2015, specialClass: 'warrior', text: t('bodySpecialSummer2015WarriorText'), notes: t('bodySpecialSummer2015WarriorNotes'), value: 20
headAccessory:
base:

View File

@@ -882,6 +882,7 @@ api.wrap = (user, main=true) ->
# the same seed would give one of the first five foods only.
eligibleEquipment = _.filter(content.gear.flat, ((i)->i.klass is 'armoire' and !user.items.gear.owned[i.key]))
if !_.isEmpty(eligibleEquipment) and (armoireResult < .6 or !user.flags.armoireOpened)
eligibleEquipment.sort() # https://github.com/HabitRPG/habitrpg/issues/5376#issuecomment-111799217
drop = user.fns.randomVal(eligibleEquipment)
user.items.gear.owned[drop.key] = true
user.flags.armoireOpened = true
@@ -1715,7 +1716,7 @@ api.wrap = (user, main=true) ->
owned = if window? then user.items.gear.owned else user.items.gear.owned.toObject()
user.achievements.ultimateGearSets ?= {healer: false, wizard: false, rogue: false, warrior: false}
content.classes.forEach (klass) ->
if user.achievements.ultimateGearSets[klass] is not true
if user.achievements.ultimateGearSets[klass] isnt true
user.achievements.ultimateGearSets[klass] = _.reduce ['armor', 'shield', 'head', 'weapon'], (soFarGood, type) ->
found = _.find content.gear.tree[type][klass], {last:true}
soFarGood and (!found or owned[found.key]==true) #!found only true when weapon is two-handed (mages)

View File

@@ -1,13 +1,22 @@
/**
* Created by Sabe on 6/3/2015.
*/
// var migrationName = '20150604_ultimateGearSets';
// var authorName = 'Sabe'; // in case script author needs to know when their ...
// var authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; //... own data is done
var migrationName = '20150604_ultimateGearSets';
var authorName = process.env.AUTHOR_NAME || 'Sabe'; // in case script author needs to know when their ...
var authorUuid = process.env.AUTHOR_UUID || '7f14ed62-5408-4e1b-be83-ada62d504931'; //... own data is done
var migrationName = '20150620_ultimateGearSets';
var authorName = 'Alys'; // in case script author needs to know when their ...
var authorUuid = 'd904bd62-da08-416b-a816-ba797c9ee265'; //... own data is done
/*
* grant the new ultimateGearSets achievement for existing users' collected equipment
*
*
* Changed by Alys on 20150620 to assign false values to
* 'achievements.ultimateGearSets' when true values are not appropriate,
* because of https://github.com/HabitRPG/habitrpg/issues/5427
*
* Minimal changes were made so the code isn't as efficient or clean
* as it could be, but it's (hopefully) one-use-only and minimal changes
* means minimal new testing.
*/
var dbserver = 'localhost:27017' // FOR TEST DATABASE
@@ -24,25 +33,10 @@ var fields = {
'items.gear.owned':1
};
// Changes 20150620: All users have to be processed now (non-achievers need
// false values).
var query = {
// 'auth.timestamps.loggedin':{$lte:new Date('2015-05-22')},
$or: [
{'items.gear.owned.weapon_wizard_6': {$exists: true}},
{'items.gear.owned.armor_wizard_5': {$exists: true}},
{'items.gear.owned.head_wizard_5': {$exists: true}},
{'items.gear.owned.weapon_warrior_6': {$exists: true}},
{'items.gear.owned.armor_warrior_5': {$exists: true}},
{'items.gear.owned.head_warrior_5': {$exists: true}},
{'items.gear.owned.shield_warrior_5': {$exists: true}},
{'items.gear.owned.weapon_healer_6': {$exists: true}},
{'items.gear.owned.armor_healer_5': {$exists: true}},
{'items.gear.owned.head_healer_5': {$exists: true}},
{'items.gear.owned.shield_healer_5': {$exists: true}},
{'items.gear.owned.weapon_rogue_6': {$exists: true}},
{'items.gear.owned.armor_rogue_5': {$exists: true}},
{'items.gear.owned.head_rogue_5': {$exists: true}},
{'items.gear.owned.shield_rogue_6': {$exists: true}}
]
};
console.warn('Updating users...');
@@ -58,6 +52,8 @@ dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
var achievements = {};
var changeUser = false;
// Changes 20150620: 'changeUser' now indicates that the user must have the
// Enchanted Armoire unlocked.
if ( (typeof user.items.gear.owned.weapon_wizard_6 !== 'undefined')
&& (typeof user.items.gear.owned.armor_wizard_5 !== 'undefined')
&& (typeof user.items.gear.owned.head_wizard_5 !== 'undefined')
@@ -65,6 +61,11 @@ dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
achievements['wizard'] = true;
changeUser = true;
}
else {
// Changes 20150620: false added for all classes (here and below)
achievements['wizard'] = false;
}
if ( (typeof user.items.gear.owned.weapon_warrior_6 !== 'undefined')
&& (typeof user.items.gear.owned.armor_warrior_5 !== 'undefined')
&& (typeof user.items.gear.owned.head_warrior_5 !== 'undefined')
@@ -73,6 +74,10 @@ dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
achievements['warrior'] = true;
changeUser = true;
}
else {
achievements['warrior'] = false;
}
if ( (typeof user.items.gear.owned.weapon_healer_6 !== 'undefined')
&& (typeof user.items.gear.owned.armor_healer_5 !== 'undefined')
&& (typeof user.items.gear.owned.head_healer_5 !== 'undefined')
@@ -81,6 +86,10 @@ dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
achievements['healer'] = true;
changeUser = true;
}
else {
achievements['healer'] = false;
}
if ( (typeof user.items.gear.owned.weapon_rogue_6 !== 'undefined')
&& (typeof user.items.gear.owned.armor_rogue_5 !== 'undefined')
&& (typeof user.items.gear.owned.head_rogue_5 !== 'undefined')
@@ -89,12 +98,17 @@ dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
achievements['rogue'] = true;
changeUser = true;
}
if (changeUser) {
var set = {'migration':migrationName, 'achievements.ultimateGearSets':achievements, 'flags.armoireEnabled':true};
dbUsers.update({_id:user._id}, {$set:set});
else {
achievements['rogue'] = false;
}
// Changes 20150620: $set is now run for all users.
var set = {'migration':migrationName, 'achievements.ultimateGearSets':achievements};
if (changeUser) { // user has at least one Ultimate Gear achievement
set['flags.armoireEnabled'] = true;
}
dbUsers.update({_id:user._id}, {$set:set});
if (count%progressCount == 0) console.warn(count + ' ' + user._id);
if (user._id == authorUuid) console.warn(authorName + ' processed');
if (user._id == '9' ) console.warn('lefnire' + ' processed');

View File

@@ -75,7 +75,7 @@
"www.habitrpg.com"
],
"engines": {
"node": "0.10.x"
"node": "0.12.4"
},
"scripts": {
"test": "./node_modules/.bin/gulp test",

114
test/api/score.coffee Normal file
View File

@@ -0,0 +1,114 @@
'use strict'
require("../../website/src/server")
describe "Score", ->
before (done) ->
registerNewUser done, true
context "Todos that did not previously exist", ->
it "creates a completed a todo when using up url", (done) ->
request.post(baseURL + "/user/tasks/withUp/up").send(
type: "todo"
text: "withUp"
).end (res) ->
expectCode res, 200
request.get(baseURL + "/user/tasks/withUp").end (res) ->
upTodo = res.body
expect(upTodo.completed).to.equal true
done()
it "creates an uncompleted todo when using down url", (done) ->
request.post(baseURL + "/user/tasks/withDown/down").send(
type: "todo"
text: "withDown"
).end (res) ->
expectCode res, 200
request.get(baseURL + "/user/tasks/withDown").end (res) ->
downTodo = res.body
expect(downTodo.completed).to.equal false
done()
it "creates a completed a todo overriding the complete parameter when using up url", (done) ->
request.post(baseURL + "/user/tasks/withUpWithComplete/up").send(
type: "todo"
text: "withUpWithComplete"
completed: false
).end (res) ->
expectCode res, 200
request.get(baseURL + "/user/tasks/withUpWithComplete").end (res) ->
upTodo = res.body
expect(upTodo.completed).to.equal true
done()
it "Creates an uncompleted todo overriding the completed parameter when using down url", (done) ->
request.post(baseURL + "/user/tasks/withDownWithUncomplete/down").send(
type: "todo"
text: "withDownWithUncomplete"
completed: true
).end (res) ->
expectCode res, 200
request.get(baseURL + "/user/tasks/withDownWithUncomplete").end (res) ->
downTodo = res.body
expect(downTodo.completed).to.equal false
done()
context "Todo that already exists", ->
it "It completes a todo when using up url", (done) ->
request.post(baseURL + "/user/tasks").send(
type: "todo"
text: "Sample Todo"
).end (res) ->
expectCode res, 200
unCompletedTodo = res.body
expect(unCompletedTodo.completed).to.equal false
request.post(baseURL + "/user/tasks/"+unCompletedTodo._id+"/up").end (res) ->
expectCode res, 200
request.get(baseURL + "/user/tasks/"+unCompletedTodo._id).end (res) ->
unCompletedTodo = res.body
expect(unCompletedTodo.completed).to.equal true
done()
it "It uncompletes a todo when using down url", (done) ->
request.post(baseURL + "/user/tasks").send(
type: "todo"
text: "Sample Todo"
completed: true
).end (res) ->
expectCode res, 200
completedTodo = res.body
expect(completedTodo.completed).to.equal true
request.post(baseURL + "/user/tasks/"+completedTodo._id+"/down").end (res) ->
expectCode res, 200
request.get(baseURL + "/user/tasks/"+completedTodo._id).end (res) ->
completedTodo = res.body
expect(completedTodo.completed).to.equal false
done()
it "Creates and scores up a habit when using up url", (done) ->
upHabit = undefined
request.post(baseURL + "/user/tasks/habitWithUp/up").send(
type: "habit"
text: "testTitle"
completed: true
).end (res) ->
expectCode res, 200
request.get(baseURL + "/user/tasks/habitWithUp").end (res) ->
upHabit = res.body
expect(upHabit.value).to.be.at.least(1)
expect(upHabit.type).to.equal("habit")
done()
it "Creates and scores down a habit when using down url", (done) ->
downHabit = undefined
request.post(baseURL + "/user/tasks/habitWithDown/down").send(
type: "habit"
text: "testTitle"
completed: true
).end (res) ->
expectCode res, 200
request.get(baseURL + "/user/tasks/habitWithDown").end (res) ->
downHabit = res.body
expect(downHabit.value).to.have.at.most(-1)
expect(downHabit.type).to.equal("habit")
done()

View File

@@ -183,4 +183,3 @@ describe "Todos", ->
body = res.body
expect(body.err).to.equal "Task not found."
done()

30
test/common/user.fns.js Normal file
View File

@@ -0,0 +1,30 @@
'use strict';
var shared = require('../../common/script/index.coffee');
shared.i18n.translations = require('../../website/src/i18n.js').translations
require('./test_helper');
describe('User.fns', function() {
describe('.ultimateGear', function() {
it('sets armoirEnabled when partial achievement already achieved', function() {
var user = shared.wrap({
items: { gear: { owned: {
toObject: function() { return {
armor_warrior_5: true,
shield_warrior_5: true,
head_warrior_5: true,
weapon_warrior_6: true
}}
}}},
achievements: {
ultimateGearSets: {}
},
flags: {}
});
user.fns.ultimateGear();
expect(user.flags.armoireEnabled).to.equal(true);
});
});
});

View File

@@ -4,13 +4,8 @@ describe('AppJS', function() {
describe('Automatic page refresh', function(){
var clock;
beforeEach(function () {
clock = sinon.useFakeTimers();
sinon.stub(window, "refresher", function(){return true});
});
afterEach(function () {
clock.restore();
window.refresher.restore();
clock = sandbox.useFakeTimers();
sandbox.stub(window, "refresher", function(){return true});
});
it('should not call refresher if idle time is less than 6 hours', function() {

View File

@@ -10,8 +10,8 @@ describe('Auth Controller', function() {
scope = $rootScope.$new();
scope.loginUsername = 'user';
scope.loginPassword = 'pass';
$window = { location: { href: ""}, alert: sinon.spy() };
user = { user: {}, authenticate: sinon.spy() };
$window = { location: { href: ""}, alert: sandbox.spy() };
user = { user: {}, authenticate: sandbox.spy() };
ctrl = $controller('AuthCtrl', {$scope: scope, $window: $window, User: user});
}));
@@ -20,16 +20,16 @@ describe('Auth Controller', function() {
$httpBackend.expectPOST('/api/v2/user/auth/local').respond({id: 'abc', token: 'abc'});
scope.auth();
$httpBackend.flush();
sinon.assert.calledOnce(user.authenticate);
sinon.assert.notCalled($window.alert);
expect(user.authenticate).to.be.calledOnce;
expect($window.alert).to.not.be.called;
});
it('should not log in users with incorrect uname / pass', function() {
$httpBackend.expectPOST('/api/v2/user/auth/local').respond(404, '');
scope.auth();
$httpBackend.flush();
sinon.assert.notCalled(user.authenticate);
sinon.assert.calledOnce($window.alert);
expect(user.authenticate).to.not.be.called;
expect($window.alert).to.be.calledOnce;
});
});

View File

@@ -188,10 +188,10 @@ describe('Challenges Controller', function() {
var challengeToClone = {
name: 'copyChallenge',
description: 'copyChallenge',
habits: [newHabit()],
dailys: [newDaily()],
todos: [newTodo()],
rewards: [newReward()],
habits: [specHelper.newHabit()],
dailys: [specHelper.newDaily()],
todos: [specHelper.newTodo()],
rewards: [specHelper.newReward()],
leader: 'unique-user-id',
group: { _id: "copyGroup" },
timestamp: new Date("October 13, 2014 11:13:00"),

View File

@@ -30,7 +30,7 @@ describe('Groups Controller', function() {
party.type = 'party';
party.members = []; // Ensure we wouldn't pass automatically.
var partyStub = sinon.stub(groups,"party", function() {
var partyStub = sandbox.stub(groups,"party", function() {
return party;
});
@@ -44,7 +44,7 @@ describe('Groups Controller', function() {
guild.type = 'guild';
guild.members.push(user._id);
var myGuilds = sinon.stub(groups,"myGuilds", function() {
var myGuilds = sandbox.stub(groups,"myGuilds", function() {
return [guild];
});
@@ -58,7 +58,7 @@ describe('Groups Controller', function() {
guild._id = "unique-guild-id";
guild.type = 'guild';
var myGuilds = sinon.stub(groups,"myGuilds", function() {
var myGuilds = sandbox.stub(groups,"myGuilds", function() {
return [];
});
@@ -98,7 +98,7 @@ describe("Chat Controller", function() {
name: "Princess Bride"
};
var modalSpy = sinon.spy($rootScope, "openModal");
var modalSpy = sandbox.spy($rootScope, "openModal");
var message = {
uuid: 'the-dread-pirate-roberts',
user: 'Wesley',
@@ -120,7 +120,7 @@ describe("Chat Controller", function() {
name: "Princess Bride"
};
var modalSpy = sinon.spy($rootScope, "openModal");
var modalSpy = sandbox.spy($rootScope, "openModal");
var message = {
uuid: 'system',
text: 'Wesley attacked the ROUS in the Fire Swamp'
@@ -221,7 +221,7 @@ describe("Autocomplete controller", function() {
describe("performCompletion", function() {
it('triggers autoComplete', function() {
scope.autoComplete = sinon.spy();
scope.autoComplete = sandbox.spy();
var msg = {user: "boo"}; // scope.autoComplete only cares about user
scope.query = {text: "b"};
@@ -247,7 +247,7 @@ describe("Autocomplete controller", function() {
describe("chatChanged", function() {
it('if a new chat arrives, the new user name is extracted', function() {
var chatChanged = sinon.spy(scope, 'chatChanged');
var chatChanged = sandbox.spy(scope, 'chatChanged');
scope.$watch('group.chat',scope.chatChanged); // reinstantiate watch so spy works
scope.$digest(); // trigger watch
@@ -269,11 +269,11 @@ describe("CopyMessageModal controller", function() {
user = specHelper.newUser();
user._id = "unique-user-id";
user.ops = {
addTask: sinon.spy()
addTask: sandbox.spy()
};
scope = $rootScope.$new();
scope.$close = sinon.spy();
scope.$close = sandbox.spy();
$controller = _$controller_;
@@ -283,7 +283,7 @@ describe("CopyMessageModal controller", function() {
ctrl = $controller('CopyMessageModalCtrl', {$scope: scope, User: {user: user}});
Notification = _Notification_;
Notification.text = sinon.spy();
Notification.text = sandbox.spy();
});
});

View File

@@ -22,15 +22,12 @@ describe('Hall of Heroes Controller', function() {
});
it('populates contributor input with selected hero id', function(){
var loadHero = sinon.spy(scope, "loadHero");
var scrollTo = sinon.spy(window, "scrollTo");
var loadHero = sandbox.spy(scope, "loadHero");
var scrollTo = sandbox.spy(window, "scrollTo");
scope.populateContributorInput(user._id);
expect(scope._heroID).to.eql(user._id);
expect(loadHero.callCount).to.eql(1);
expect(scrollTo.callCount).to.eql(1);
scope.loadHero.restore();
window.scrollTo.restore();
});
});

View File

@@ -26,13 +26,8 @@ describe('Header Controller', function() {
context('inviteOrStartParty', function(){
beforeEach(function(){
sinon.stub($location, 'path');
sinon.stub($rootScope, 'openModal');
});
afterEach(function(){
$location.path.restore();
$rootScope.openModal.restore();
sandbox.stub($location, 'path');
sandbox.stub($rootScope, 'openModal');
});
it('redirects to party page if user does not have a party', function(){

View File

@@ -24,13 +24,13 @@ describe('Root Controller', function() {
$httpBackend = _$httpBackend_;
notification = Notification;
sinon.stub(notification, 'text');
sinon.stub(notification, 'markdown');
sandbox.stub(notification, 'text');
sandbox.stub(notification, 'markdown');
user = specHelper.newUser();
User = {user: user};
User.save = sinon.spy();
User.sync = sinon.spy();
User.save = sandbox.spy();
User.sync = sandbox.spy();
$httpBackend.whenGET(/partials/).respond();
@@ -38,13 +38,6 @@ describe('Root Controller', function() {
});
});
afterEach(function() {
notification.text.reset();
notification.markdown.reset();
User.save.reset();
User.sync.reset();
});
describe('contribText', function(){
it('shows contributor level text', function(){
expect(scope.contribText()).to.eql(undefined);

View File

@@ -16,7 +16,7 @@ describe('focusMe Directive', function() {
it('focuses the element when appended to the DOM', function() {
inject(function($timeout) {
var focusSpy = sinon.spy();
var focusSpy = sandbox.spy();
element.appendTo(document.body);
element.on('focus', focusSpy);

View File

@@ -11,7 +11,7 @@ describe('fromNow Directive', function() {
scope = $rootScope.$new();
scope.message = {};
sinon.stub(window, 'moment').returns({
sandbox.stub(window, 'moment').returns({
fromNow: function() { return fromNow },
diff: function() { return diff }
});

View File

@@ -1,10 +1,11 @@
'use strict';
describe('Task Ordering Filters', function() {
var filter
, orderBySpy = sinon.spy();
var filter, orderBySpy;
beforeEach(function() {
orderBySpy = sandbox.spy();
module(function($provide) {
$provide.value('orderByFilter', orderBySpy);
});

View File

@@ -3,13 +3,11 @@
describe('notificationServices', function() {
var notification;
before(function(){
sinon.stub($, 'pnotify', function(){
beforeEach(function() {
sandbox.stub($, 'pnotify', function(){
return { click: function(){}}
});
});
beforeEach(function() {
module(function($provide){
$provide.value('User', {});
});
@@ -19,10 +17,6 @@ describe('notificationServices', function() {
});
});
afterEach(function() {
$.pnotify.reset();
});
it('notifies coins amount', function() {
var SILVER_COIN = "<span class='notification-icon shop_silver'></span>";
var GOLD_COIN = "<span class='notification-icon shop_gold'></span>";

View File

@@ -22,7 +22,7 @@ describe('Tasks Service', function() {
var task;
beforeEach(function(){
task = newTask();
task = specHelper.newTask();
});
it('toggles the _editing property', function() {
@@ -71,7 +71,7 @@ describe('Tasks Service', function() {
context('generic tasks', function() {
it('clones the data from a task', function() {
var task = newTask();
var task = specHelper.newTask();
var clonedTask = tasks.cloneTask(task);
expect(clonedTask.text).to.eql(task.text);
@@ -83,7 +83,7 @@ describe('Tasks Service', function() {
});
it('does not clone original task\'s id or _id', function() {
var task = newTask();
var task = specHelper.newTask();
var clonedTask = tasks.cloneTask(task);
expect(clonedTask.id).to.exist;
@@ -93,7 +93,7 @@ describe('Tasks Service', function() {
});
it('does not clone original task\'s dateCreated attribute', function() {
var task = newTask({
var task = specHelper.newTask({
dateCreated: new Date(2014, 5, 1, 1, 1, 1, 1),
});
var clonedTask = tasks.cloneTask(task);
@@ -103,7 +103,7 @@ describe('Tasks Service', function() {
});
it('does not clone original task\'s value', function() {
var task = newTask({
var task = specHelper.newTask({
value: 130
});
var clonedTask = tasks.cloneTask(task);
@@ -116,7 +116,7 @@ describe('Tasks Service', function() {
context('Habits', function() {
it('clones a habit', function() {
var habit = newHabit({
var habit = specHelper.newHabit({
up: true,
down: false
});
@@ -131,7 +131,7 @@ describe('Tasks Service', function() {
context('Dailys', function() {
it('clones a daily', function() {
var daily = newDaily({
var daily = specHelper.newDaily({
frequency: 'daily',
everyX: 3,
startDate: new Date(2014, 5, 1, 1, 1, 1, 1),
@@ -146,7 +146,7 @@ describe('Tasks Service', function() {
});
it('does not clone streak', function() {
var daily = newDaily({
var daily = specHelper.newDaily({
streak: 11
});
@@ -159,14 +159,14 @@ describe('Tasks Service', function() {
context('Todos', function() {
it('clones a todo', function() {
var todo = newTodo();
var todo = specHelper.newTodo();
var clonedTodo = tasks.cloneTask(todo);
expect(clonedTodo.type).to.eql('todo');
});
it('does not clone due date', function() {
var todo = newTodo({
var todo = specHelper.newTodo({
date: '2015-06-20'
});
@@ -176,7 +176,7 @@ describe('Tasks Service', function() {
});
it('does not clone date completed', function() {
var todo = newTodo({
var todo = specHelper.newTodo({
dateCompleted: new Date()
});
@@ -189,14 +189,14 @@ describe('Tasks Service', function() {
context('Rewards', function() {
it('clones a reward', function() {
var reward = newReward();
var reward = specHelper.newReward();
var clonedReward = tasks.cloneTask(reward);
expect(clonedReward.type).to.eql('reward');
});
it('does clone a reward\'s value', function() {
var reward = newReward({
it('does clone a reward\'s vaue', function() {
var reward = specHelper.newReward({
value: 20
});
var clonedReward = tasks.cloneTask(reward);
@@ -207,7 +207,7 @@ describe('Tasks Service', function() {
context('complete', function() {
it('does not clone completed status', function() {
var todo = newTodo({
var todo = specHelper.newTodo({
completed: true
});
@@ -220,7 +220,7 @@ describe('Tasks Service', function() {
context('history', function() {
it('does not clone history', function() {
var habit = newHabit({
var habit = specHelper.newHabit({
history: [
{ date: Date.now, value: 3.1 },
{ date: Date.now, value: 2.7 }
@@ -236,7 +236,7 @@ describe('Tasks Service', function() {
context('checklists', function() {
it('clones checklist text', function() {
var todo = newTodo({
var todo = specHelper.newTodo({
checklist: [{
completed: true,
text: 'checklist 1',
@@ -255,7 +255,7 @@ describe('Tasks Service', function() {
});
it('does not clone complete or id attribute of checklist', function() {
var todo = newTodo({
var todo = specHelper.newTodo({
checklist: [{
completed: true,
text: 'checklist 1',

View File

@@ -7,7 +7,7 @@ describe('userServices', function() {
beforeEach(function(){
module(function($provide){
$window = {href: '', alert: sinon.spy(), location: {search: '', pathname: ''}};
$window = {href: '', alert: sandbox.spy(), location: {search: '', pathname: ''}};
$provide.value('$window', $window);
});

View File

@@ -1,144 +1,156 @@
beforeEach(module('habitrpg'));
function newUser() {
var buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false};
user = {
auth:{timestamps: {}},
stats: {str:1, con:1, per:1, int:1, mp: 32, class: 'warrior', buffs: buffs, gp: 0},
items:{
lastDrop:{count: 0},
hatchingPotions: {},
eggs: {},
food: {},
pets: {},
mounts: {},
gear: {equipped: {}, costume: {}, owned: {}},
},
party: {
quest: {
progress: {down: 0}
}
},
preferences: {},
dailys: [],
todos: [],
rewards: [],
flags: {},
filters: {},
achievements: {},
};
return user;
}
var sandbox;
beforeEach(function() {
sandbox = sinon.sandbox.create();
});
function newGroup(leader) {
var quest = { progress: { }, active: false };
group = {
"leader" : leader,
"quest" : quest,
"memberCount" : 1,
"chat" : [],
"privacy" : "public",
"invites" : [],
"members" : [
leader
]
};
return group;
}
afterEach(function() {
sandbox.restore();
});
function newTask(overrides) {
var task = {
id: 'task-id',
_id: 'task-id',
dateCreated: Date.now,
text: 'task text',
notes: 'task notes',
tags: { },
value: 0,
priority: 1,
attribute: 'str',
challenge: { }
};
var specHelper = {};
for(var key in overrides) {
task[key] = overrides[key];
(function(){
specHelper.newUser = newUser;
specHelper.newGroup = newGroup;
specHelper.newTask = newTask;
specHelper.newHabit = newHabit;
specHelper.newDaily = newDaily;
specHelper.newTodo = newTodo;
specHelper.newReward = newReward;
function newUser() {
var buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false};
user = {
auth:{timestamps: {}},
stats: {str:1, con:1, per:1, int:1, mp: 32, class: 'warrior', buffs: buffs, gp: 0},
items:{
lastDrop:{count: 0},
hatchingPotions: {},
eggs: {},
food: {},
pets: {},
mounts: {},
gear: {equipped: {}, costume: {}, owned: {}},
},
party: {
quest: {
progress: {down: 0}
}
},
preferences: {},
dailys: [],
todos: [],
rewards: [],
flags: {},
filters: {},
achievements: {},
};
return user;
}
return task;
}
function newHabit(overrides) {
var habit = newTask();
habit.type = 'habit';
habit.history = [];
habit.up = true;
habit.down = true;
for(var key in overrides) {
habit[key] = overrides[key];
function newGroup(leader) {
var quest = { progress: { }, active: false };
group = {
"leader" : leader,
"quest" : quest,
"memberCount" : 1,
"chat" : [],
"privacy" : "public",
"invites" : [],
"members" : [
leader
]
};
return group;
}
return habit;
}
function newTask(overrides) {
var task = {
id: 'task-id',
_id: 'task-id',
dateCreated: Date.now,
text: 'task text',
notes: 'task notes',
tags: { },
value: 0,
priority: 1,
attribute: 'str',
challenge: { }
};
function newDaily(overrides) {
var daily = newTask();
daily.type = 'daily';
daily.frequency = 'weekly';
daily.repeat = {
m: true,
t: true,
w: true,
th: true,
f: true,
s: true,
su: true
};
daily.startDate = Date.now;
daily.history = [];
daily.completed = false;
daily.collapseChecklist = false;
daily.checklist = [];
daily.streak = 0;
for(var key in overrides) {
task[key] = overrides[key];
}
for(var key in overrides) {
daily[key] = overrides[key];
return task;
}
return daily;
}
function newHabit(overrides) {
var habit = newTask();
habit.type = 'habit';
habit.history = [];
habit.up = true;
habit.down = true;
function newTodo(overrides) {
var todo = newTask();
todo.type = 'todo';
todo.completed = false;
todo.collapseChecklist = false;
todo.checklist = [];
for(var key in overrides) {
habit[key] = overrides[key];
}
for(var key in overrides) {
todo[key] = overrides[key];
return habit;
}
return todo;
}
function newDaily(overrides) {
var daily = newTask();
daily.type = 'daily';
daily.frequency = 'weekly';
daily.repeat = {
m: true,
t: true,
w: true,
th: true,
f: true,
s: true,
su: true
};
daily.startDate = Date.now;
daily.history = [];
daily.completed = false;
daily.collapseChecklist = false;
daily.checklist = [];
daily.streak = 0;
function newReward(overrides) {
var reward = newTask();
reward.type = 'reward';
for(var key in overrides) {
daily[key] = overrides[key];
}
for(var key in overrides) {
reward[key] = overrides[key];
return daily;
}
return reward;
}
function newTodo(overrides) {
var todo = newTask();
todo.type = 'todo';
todo.completed = false;
todo.collapseChecklist = false;
todo.checklist = [];
specHelper = {
newUser: newUser,
newGroup: newGroup,
newTask: newTask,
newHabit: newHabit,
newDaily: newDaily,
newTodo: newTodo,
newRward: newReward
}
for(var key in overrides) {
todo[key] = overrides[key];
}
return todo;
}
function newReward(overrides) {
var reward = newTask();
reward.type = 'reward';
for(var key in overrides) {
reward[key] = overrides[key];
}
return reward;
}
})();

View File

@@ -214,9 +214,10 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
var gems = User.user.balance * 4;
var string = (type == 'weapon') ? window.env.t('weapon') : (type == 'armor') ? window.env.t('armor') : (type == 'head') ? window.env.t('headgear') : (type == 'shield') ? window.env.t('offhand') : (type == 'headAccessory') ? window.env.t('headAccessory') : (type == 'hatchingPotions') ? window.env.t('hatchingPotion') : (type == 'eggs') ? window.env.t('eggSingular') : (type == 'quests') ? window.env.t('quest') : (item.key == 'Saddle') ? window.env.t('foodSaddleText').toLowerCase() : type; // FIXME this is ugly but temporary, once the purchase modal is done this will be removed
var string = (type == 'weapon') ? window.env.t('weapon') : (type == 'armor') ? window.env.t('armor') : (type == 'head') ? window.env.t('headgear') : (type == 'shield') ? window.env.t('offhand') : (type == 'back') ? window.env.t('back') : (type == 'body') ? window.env.t('body') : (type == 'headAccessory') ? window.env.t('headAccessory') : (type == 'eyewear') ? window.env.t('eyewear') : (type == 'hatchingPotions') ? window.env.t('hatchingPotion') : (type == 'eggs') ? window.env.t('eggSingular') : (type == 'quests') ? window.env.t('quest') : (item.key == 'Saddle') ? window.env.t('foodSaddleText').toLowerCase() : type; // FIXME this is ugly but temporary, once the purchase modal is done this will be removed
var price = ((((item.specialClass == "wizard") && (item.type == "weapon")) || item.gearSet == "animal") + 1);
if (type == 'weapon' || type == 'armor' || type == 'head' || type == 'shield' || type == 'headAccessory') {
if (type == 'weapon' || type == 'armor' || type == 'head' || type == 'shield' || type == 'headAccessory' || type == 'body' || type == 'back' || type == 'eyewear' ) {
if (User.user.items.gear.owned[item.key]) {
if (User.user.preferences.costume) return User.user.ops.equip({params:{type: 'costume', key: item.key}});
else {

View File

@@ -1,3 +1,4 @@
'use strict';
// @see ../routes for routing
function clone(a) {
@@ -195,7 +196,7 @@ api.create = function(req, res, next) {
group = user = null;
});
}else{
} else{
async.waterfall([
function(cb){
Group.findOne({type:'party',members:{$in:[user._id]}},cb);
@@ -210,8 +211,8 @@ api.create = function(req, res, next) {
], function(err, populated){
if (err == 'Already in a party, try refreshing.') return res.json(400,{err:err});
if (err) return next(err);
return res.json(populated);
group = user = null;
return res.json(populated);
})
}
}
@@ -285,7 +286,7 @@ api.postChat = function(req, res, next) {
group.save(function(err, saved){
if (err) return next(err);
return chatUpdated ? res.json({chat: group.chat}) : res.json({message: saved.chat[0]});
chatUpdated ? res.json({chat: group.chat}) : res.json({message: saved.chat[0]});
group = chatUpdated = null;
});
}
@@ -549,8 +550,8 @@ api.leave = function(req, res, next) {
}
],function(err){
if (err) return next(err);
return res.send(204);
user = group = keep = null;
return res.send(204);
})
}
@@ -786,8 +787,8 @@ api.removeMember = function(req, res, next){
});
}else{
return res.json(400, {err: "User not found among group's members!"});
group = uuid = null;
return res.json(400, {err: "User not found among group's members!"});
}
}
@@ -795,7 +796,7 @@ api.removeMember = function(req, res, next){
// Quests
// ------------------------------------
questStart = function(req, res, next) {
function questStart(req, res, next) {
var group = res.locals.group;
var force = req.query.force;

View File

@@ -99,9 +99,11 @@ api.score = function(req, res, next) {
text: req.body && req.body.text,
notes: (req.body && req.body.notes) || "This task was created by a third-party service. Feel free to edit, it won't harm the connection to that service. Additionally, multiple services may piggy-back off this task."
};
task = user.ops.addTask({body:task});
if (task.type === 'daily' || task.type === 'todo')
task.completed = direction === 'up';
task = user.ops.addTask({body:task});
}
var delta = user.ops.score({params:{id:task.id, direction:direction}, language: req.language});

View File

@@ -296,7 +296,6 @@ var UserSchema = new Schema({
}
},
preferences: {
armorSet: String,
dayStart: {type:Number, 'default': 0, min: 0, max: 23},
size: {type:String, enum: ['broad','slim'], 'default': 'slim'},
hair: {

View File

@@ -28,32 +28,28 @@ script(type='text/ng-template', id='partials/options.inventory.seasonalshop.html
.container-fluid
.stable.row
.col-md-2
.seasonalshop_closed
.seasonalshop_summer2015
.col-md-10
.popover.static-popover.fade.right.in
.arrow
h3.popover-title!=env.t('seasonalShopClosedTitle', {linkStart:"<a href='http://blog.habitrpg.com/who' target='_blank'>", linkEnd: "</a>"})
h3.popover-title!=env.t('seasonalShopTitle', {linkStart:"<a href='http://blog.habitrpg.com/who' target='_blank'>", linkEnd: "</a>"})
.popover-content
p!=env.t('seasonalShopClosedText', {linkStart:"<a href='http://habitrpg.wikia.com/wiki/Grand_Galas' target='_blank'>", linkEnd: "</a>"})
// .well(ng-if='User.user.achievements.rebirths > 0')=env.t('seasonalShopRebirth')
// li.customize-menu.inventory-gear
menu.pets-menu(label='{{::label}}', ng-repeat='(set,label) in ::{springWarrior:env.t("mightyBunnySet"), springMage:env.t("magicMouseSet"), springHealer:env.t("lovingPupSet"), springRogue:env.t("stealthyKittySet")}')
// The `if true || false` conditional for applying the transparent class is necessary because
// when a user activates the orb of rebirth, the seasonal items are still in their inventory, but
// they have each have a value of false. The item can be purchased for gold in the rewards column,
// not the seasonal shop. This makes that more clear.
p!=env.t('seasonalShopSummerText')
.well(ng-if='User.user.achievements.rebirths > 0')=env.t('seasonalShopRebirth')
li.customize-menu.inventory-gear
menu.pets-menu(label='{{::label}}', ng-repeat='(set,label) in ::{summerWarrior:env.t("daringSwashbucklerSet"), summerMage:env.t("emeraldMermageSet"), summerHealer:env.t("reefSeahealerSet"), summerRogue:env.t("roguishPirateSet")}')
div(ng-repeat='item in ::getSeasonalShopArray(set)' ng-class="{transparent: user.items.gear.owned[item.key] === true ||user.items.gear.owned[item.key] === false}")
button.customize-option(popover='{{::item.notes()}}', popover-title='{{::item.text()}}', popover-trigger='mouseenter', popover-placement='right', popover-append-to-body='true', ng-click='purchase(item.type,item)', class='shop_{{::item.key}}')
.text-left
| {{((item.specialClass == "wizard") && (item.type == "weapon")) + 1}}&nbsp;
span.Pet_Currency_Gem1x.inline-gems
menu.pets-menu(label=env.t('quests'))
// menu.pets-menu(label=env.t('quests'))
div(ng-repeat='quest in ::getSeasonalShopQuests()')
button.customize-option(data-popover-html="{{::quest.previous && !user.achievements.quests[quest.previous] ? env.t('scrollsPre') : questPopover(quest) | markdown}}", popover-append-to-body='true', popover-title='{{::quest.text()}}', popover-trigger='mouseenter', popover-placement='right', ng-click='buyQuest(quest.key)', ng-class='(quest.previous && !user.achievements.quests[quest.previous]) ? "inventory_quest_scroll_locked inventory_quest_scroll_{{::quest.key}}_locked locked" : "inventory_quest_scroll inventory_quest_scroll_{{::quest.key}}"')
p
| {{::quest.value}}&nbsp;
span.Pet_Currency_Gem1x.inline-gems
menu.pets-menu(label=env.t('seasonalItems'))
// menu.pets-menu(label=env.t('seasonalItems'))
div
button.customize-option(popover='{{::Content.spells.special.shinySeed.notes()}}', popover-title='{{::Content.spells.special.shinySeed.text()}}', popover-trigger='mouseenter', popover-placement='right', popover-append-to-body='true', ng-click='purchase("special", Content.spells.special.shinySeed)', class='inventory_special_shinySeed')
p

View File

@@ -1,23 +1,45 @@
h5 6/17/2015 - CUTTLEFISH PET QUEST AND QUEST DISPLAY IMPROVEMENTS
h5 6/20/2015 - SUMMER SPLASH EVENT: LIMITED EDITION OUTFITS, SEASONAL SHOP OPENS, AND SUMMER NPCS!
hr
tr
td
.quest_kraken.pull-right
h5 Cuttlefish Pet Quest
p A new pet quest is available in the <a href='/#/options/inventory/drops' target='_blank'>Market</a>: The Kraken of Inkomplete! A pleasant day sailing is ruined when a Kraken attacks. Can you strike down the tasks and tentacles that keep cropping up? If so, you'll be awarded with some cuttlefish eggs!
p.small.muted art by Lemoness and Wolvenhalo
p.small.muted writing by Lemoness
h5 Summer Splash Begins!
p The Summer Splash festival has arrived, and Habitica has moved to the undersea city of Dilatory for the summer! From today until July 31st, join us for fun in the sun.
tr
td
h5 Quest Display Improvements
p Now you can see the details of a pending quest on the Party Page by clicking the new "Quest Details" tab above the quest invitations. We hope this helps you decide whether or not you want to accept the quest!
p.small.muted by hairlessbear
.promo_summer_classes_2015.pull-right
h5 Limited Edition Class Outfits
p From now until July 31st, limited edition outfits are available in the Rewards column. Depending on your class, you can be a Reef Renegade, Sunfish Warrior, Strapping Sailor, or Ship Soothsayer! You'd better get productive to earn enough gold before they disappear. Good luck!
p.small.muted by Lemoness
tr
td
.promo_summer_classes_2014.pull-right
h5 Seasonal Shop Opens
p The <a href='/#/options/inventory/seasonalshop'>Seasonal Shop</a> has opened! It's stocking summertime Seasonal Edition goodies at the moment, including last year's summer outfits. Everything there will be available to purchase during the Summer Splash event each year, but it's only open until July 31st, so be sure to stock up now, or you'll have to wait a year to buy these items again.
p.small.muted by Lemoness
tr
td
.seasonalshop_summer2015.pull-right
h5 Summer NPCs
p Looks like the NPCs are really getting in to the summer spirit. Ian, Bailey, Matt, and the Seasonal Sorceress are having fun under the sea in the sunken city of Dilatory, and Alex and Daniel have moved down to the beach. Even the Time Travelers are getting into the fun, although... oh dear... they seem to have overshot the season...
p.small.muted by Lemoness
hr
a(href='/static/old-news', target='_blank') Read older news
mixin oldNews
h5 6/17/2015 - CUTTLEFISH PET QUEST AND QUEST DISPLAY IMPROVEMENTS
tr
td
.quest_kraken.pull-right
h5 Cuttlefish Pet Quest
p A new pet quest is available in the <a href='/#/options/inventory/drops' target='_blank'>Market</a>: The Kraken of Inkomplete! A pleasant day sailing is ruined when a Kraken attacks. Can you strike down the tasks and tentacles that keep cropping up? If so, you'll be awarded with some cuttlefish eggs!
p.small.muted art by Lemoness and Wolvenhalo
p.small.muted writing by Lemoness
tr
td
h5 Quest Display Improvements
p Now you can see the details of a pending quest on the Party Page by clicking the new "Quest Details" tab above the quest invitations. We hope this helps you decide whether or not you want to accept the quest!
p.small.muted by hairlessbear
h5 6/16/2015 - SEARCH BAR, CHALLENGES FILTER, INTERMITTENT REFRESH, AND VISUAL TWEAKS
tr
td

View File

@@ -75,8 +75,8 @@ html(ng-app='habitrpg', ng-controller='RootCtrl')
a(href='/static/contact')=env.t('contactUs')
li
button#header-play-button.btn.btn-primary.navbar-btn.navbar-right(ng-click='playButtonClick()')= env.t('playButtonFull')
#intro
h1(ng-cloak) {{ variant==0 ? "#{env.t('motivate')}" : (variant==1 ? "#{env.t('motivate1')}" : "#{env.t('motivate2')}") }}
#intro(ng-cloak)
h1 {{ variant==0 ? "#{env.t('motivate')}" : (variant==1 ? "#{env.t('motivate1')}" : "#{env.t('motivate2')}") }}
img.center-block.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/intro.png')
// insert intro images
.introcall.bg-success