This commit is contained in:
Scott Erickson 2014-10-02 14:43:08 -07:00
commit 987061cec6
61 changed files with 40207 additions and 40282 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,12 @@
#employers-view
.deprecation-warning
text-align: center
margin-bottom: 50px
.deprecated
cursor: default
opacity: 0.25
.artisanal-claim
background: transparent url(/images/pages/employer/artisanal_claim.png) no-repeat center
margin-bottom: 5px

View file

@ -5,7 +5,8 @@ $mapHeight: 1536
$forestMapWidth: 2500
$dungeonMapWidth: 2350
$forestMapSeaBackground: #71bad0
$dungeonMapCaveBackground: rgb(54, 43, 34)
$dungeonMapCaveBackground: rgba(68, 54, 45, 1)
$dungeonMapCaveBackgroundTransparent: rgba(68, 54, 45, 0)
$levelDotWidth: 2%
$levelDotHeight: $levelDotWidth * $forestMapWidth / $mapHeight
$levelDotZ: $levelDotHeight * 0.25
@ -30,6 +31,7 @@ $gameControlMargin: 30px
#world-map-view
width: 100%
height: 100%
position: absolute
&.forest
background-color: $forestMapSeaBackground
@ -37,6 +39,36 @@ $gameControlMargin: 30px
&.dungeon
background-color: $dungeonMapCaveBackground
.gradient
position: absolute
z-index: 0
&.horizontal-gradient
left: 0
right: 0
height: 3%
&.vertical-gradient
top: 0
bottom: 0
width: 3%
&.top-gradient
top: 0
background: linear-gradient(to bottom, $dungeonMapCaveBackground 0%, $dungeonMapCaveBackgroundTransparent 100%)
&.right-gradient
right: 0
background: linear-gradient(to left, $dungeonMapCaveBackground 0%, $dungeonMapCaveBackgroundTransparent 100%)
&.bottom-gradient
bottom: 0
background: linear-gradient(to top, $dungeonMapCaveBackground 0%, $dungeonMapCaveBackgroundTransparent 100%)
&.left-gradient
left: 0
background: linear-gradient(to right, $dungeonMapCaveBackground 0%, $dungeonMapCaveBackgroundTransparent 100%)
.map
position: relative

View file

@ -104,11 +104,11 @@ block content
h3.panel-title
i.glyphicon.glyphicon-wrench
a(href="account/settings#password" data-i18n="general.password") Password
.panel.panel-default
.panel-heading
h3.panel-title
i.glyphicon.glyphicon-briefcase
a(href="account/settings#job-profile" data-i18n="account_settings.job_profile") Job Profile
//.panel.panel-default
// .panel-heading
// h3.panel-title
// i.glyphicon.glyphicon-briefcase
// a(href="account/settings#job-profile" data-i18n="account_settings.job_profile") Job Profile
.col-sm-6
h2(data-i18n="user.recently_played") Recently Played
hr

View file

@ -63,10 +63,7 @@ body
.footer.clearfix
.content
p.footer-link-text
if pathname == "/" || (me.get('permissions', true)).indexOf('employer') != -1
a(href='/employers', tabindex=-1, data-i18n="nav.employers") Employers
else
a(href='/', tabindex=-1, data-i18n="nav.home") Home
a(href='/', tabindex=-1, data-i18n="nav.home") Home
a(href='/play/ladder', tabindex=-1, data-i18n="home.multiplayer") Multiplayer
a(href='/community', tabindex=-1, data-i18n="nav.community") Community
a(href='/contribute', tabindex=-1, data-i18n="nav.contribute") Contribute

View file

@ -1,183 +1,188 @@
extends /templates/recruitment_base
block content
.artisanal-claim
if me.get('anonymous')
a#login-link(data-i18n="login.log_in") Log In
br
if !isEmployer && !me.isAdmin()
#tagline
h1(data-i18n="employers.hire_developers_not_credentials") Hire developers, not credentials.
button.btn.get-started-button.employer-button(data-i18n="employers.get_started") Get Started
else
if !me.get('anonymous')
a#logout-link(data-i18n="login.log_out") Log Out
.deprecation-warning
h1(data-i18n="employers.deprecation_warning_title") Sorry, CodeCombat is not recruiting right now.
p(data-i18n="employers.deprecation_warning") We are focusing on beginner levels instead of finding expert developers for the time being.
.deprecated
.artisanal-claim
if me.get('anonymous')
a#login-link(data-i18n="login.log_in") Log In
br
.row
- var fullProfiles = isEmployer || me.isAdmin();
if fullProfiles
#filter-column.col-md-3
#filter
.panel-group#filter_panel
a#filter-link(data-toggle="collapse" data-target="#collapseOne")
.panel.panel-default
.panel-heading
h4.panel-title
span.glyphicon.glyphicon-folder-open#folder-icon
| Filter
.panel-collapse.collapse.in#collapseOne
.panel-body
p
strong(data-i18n="employers.already_screened") We've already technically screened all our candidates
span(data-i18n="employers.filter_further") , but you can also filter further:
form#filters
.filter_section#visa_filter
h4(data-i18n="employers.filter_visa") Visa
label
input(type="checkbox" name="visa" value="Authorized to work in the US")
span(data-i18n="employers.filter_visa_yes") US Authorized
| (#{candidatesInFilter("visa","Authorized to work in the US")})
label
input(type="checkbox" name="visa" value="Need visa sponsorship")
span(data-i18n="employers.filter_visa_no") Not Authorized
| (#{candidatesInFilter("visa","Need visa sponsorship")})
.filter_section#school_filter
h4(data-i18n="account_profile.education") Education
label
input(type="checkbox" name="schoolFilter" value="Top School")
span(data-i18n="employers.filter_education_top") Top School
| (#{candidatesInFilter("schoolFilter","Top School")})
label
input(type="checkbox" name="schoolFilter" value="Other")
span(data-i18n="employers.filter_education_other") Other
| (#{candidatesInFilter("schoolFilter","Other")})
.filter_section#role_filter
h4(data-i18n="employers.candidate_role") Role
label
input(type="checkbox" name="roleFilter" value="Web Developer")
span(data-i18n="employers.filter_role_web_developer") Web Developer
| (#{candidatesInFilter("roleFilter","Web Developer")})
label
input(type="checkbox" name="roleFilter" value="Software Developer")
span(data-i18n="employers.filter_role_software_developer") Software Developer
| (#{candidatesInFilter("roleFilter","Software Developer")})
label
input(type="checkbox" name="roleFilter" value="Mobile Developer")
span(data-i18n="employers.filter_role_mobile_developer") Mobile Developer
| (#{candidatesInFilter("roleFilter","Mobile Developer")})
.filter_section#seniority_filter
h4(data-i18n="employers.filter_experience") Experience
label
input(type="checkbox" name="seniorityFilter" value="Senior")
span(data-i18n="employers.filter_experience_senior") Senior
| (#{candidatesInFilter("seniorityFilter","Senior")})
label
input(type="checkbox" name="seniorityFilter" value="Junior")
span(data-i18n="employers.filter_experience_junior") Junior
| (#{candidatesInFilter("seniorityFilter","Junior")})
label
input(type="checkbox" name="seniorityFilter" value="Recent Grad")
span(data-i18n="employers.filter_experience_recent_grad") Recent Grad
| (#{candidatesInFilter("seniorityFilter","Recent Grad")})
label
input(type="checkbox" name="seniorityFilter" value="College Student")
span(data-i18n="employers.filter_experience_student") College Student
| (#{candidatesInFilter("seniorityFilter","College Student")})
//input#select_all_checkbox(type="checkbox" name="select_all" checked)
//| Select all
p#results
| #{numberOfCandidates}
span(data-i18n="employers.results") results
h4#filter-alerts-heading Filter Email Alerts
p Get an email whenever a candidate meeting certain criteria enters the system.
table#saved-filter-table
thead
tr
th Filters
th Remove
tbody
button.btn#create-alert-button Create Alert with Current Filters
#candidates-column(class=fullProfiles ? "full-profiles col-md-9" : "teaser-profiles col-md-12")
if candidates.length
#candidate-table
table
tbody
for candidate, index in featuredCandidates
- var profile = candidate.get('jobProfile');
- var authorized = candidate.id; // If we have the id, then we are authorized.
- var profileAge = (new Date() - new Date(profile.updated)) / 86400 / 1000;
- var expired = profileAge > 2 * 30.4;
- var curated = profile.curated;
- var photoSize = fullProfiles ? 75 : 50;
tr.candidate-row(data-candidate-id=candidate.id, id=candidate.id, class=expired ? "expired" : "")
td(rowspan=3)
- var photoURL = candidate.getPhotoURL(photoSize, false, true);
div(class="candidate-picture " + (/^\/file/.test(photoURL) ? "" : "anonymous"), style='background-image: url(' + encodeURI(photoURL) + ')')
if fullProfiles
td.candidate-name-cell
strong= profile.name
| -
span= profile.jobTitle
tr.description_row(data-candidate-id=candidate.id)
if curated && curated.shortDescription
td.candidate-description
div #{curated.shortDescription}
else
td.candidate-description
div #{profile.shortDescription}
tr.border_row(data-candidate-id=candidate.id)
if curated
- var workHistory = curated.workHistory.join(",");
if !fullProfiles
td.tag_column
img(src="/images/pages/employer/tag.png")
| #{profile.jobTitle}
td.location_column
img(src="/images/pages/employer/location.png")
| #{curated.location}
td.education_column
img(src="/images/pages/employer/education.png")
| #{curated.education}
td.work_column
if workHistory
img(src="/images/pages/employer/briefcase.png")
| #{workHistory}
if !fullProfiles
div#info_wrapper
span.hiring-call-to-action
h2#start-hiring(data-i18n="employers.start_hiring") Start hiring.
if !isEmployer && !me.isAdmin()
#tagline
h1(data-i18n="employers.hire_developers_not_credentials") Hire developers, not credentials.
button.btn.get-started-button.employer-button(data-i18n="employers.get_started") Get Started
h2#hiring-reasons.hiring-call-to-action(data-i18n="employers.reasons") Three reasons you should hire through us:
.reasons#top_row
.reason
img.employer_icon(src="/images/pages/employer/employer_icon2.png")
h3(data-i18n="employers.everyone_looking") Everyone here is looking for their next opportunity.
p(data-i18n="employers.everyone_looking_blurb") Forget about 20% LinkedIn InMail response rates. Everyone that we list on this site wants to find their next position and will respond to your request for an introduction.
.reason
img.employer_icon(src="/images/pages/employer/employer_icon6.png")
h3(data-i18n="employers.weeding") Sit back; we've done the weeding for you.
p(data-i18n="employers.weeding_blurb") Every player that we list has been screened for technical ability. We also perform phone screens for select candidates and make notes on their profiles to save you time.
.reason
img(class="employer_icon" src="/images/pages/employer/employer_icon3.png")
h3(data-i18n="employers.pass_screen") They will pass your technical screen.
p(data-i18n="employers.pass_screen_blurb") Review each candidate's code before reaching out. One employer found that 5x as many of our devs passed their technical screen than hiring from Hacker News.
span.hiring-call-to-action
h2(data-i18n="employers.make_hiring_easier") Make my hiring easier, please.
button.btn.get-started-button.employer-button(data-i18n="employers.get_started") Get Started
.reasons#bottom_row
.reason_long
img.employer_icon(src="/images/pages/employer/employer_icon1.png")
.reason_text
h3(data-i18n="employers.what") What is CodeCombat?
p(data-i18n="employers.what_blurb") CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. We support JavaScript, Python, Lua, Clojure, CoffeeScript, and Io.
.reason_long
img.employer_icon(src="/images/pages/employer/employer_icon5.png")
.reason_text
h3(data-i18n="employers.cost") How much do we charge?
p(data-i18n="employers.cost_blurb") We charge 15% of first year's salary and offer a 100% money back guarantee for 90 days. We don't charge for candidates who are already actively being interviewed at your company.
else
if !me.get('anonymous')
a#logout-link(data-i18n="login.log_out") Log Out
br
.row
- var fullProfiles = isEmployer || me.isAdmin();
if fullProfiles
#filter-column.col-md-3
#filter
.panel-group#filter_panel
a#filter-link(data-toggle="collapse" data-target="#collapseOne")
.panel.panel-default
.panel-heading
h4.panel-title
span.glyphicon.glyphicon-folder-open#folder-icon
| Filter
.panel-collapse.collapse.in#collapseOne
.panel-body
p
strong(data-i18n="employers.already_screened") We've already technically screened all our candidates
span(data-i18n="employers.filter_further") , but you can also filter further:
form#filters
.filter_section#visa_filter
h4(data-i18n="employers.filter_visa") Visa
label
input(type="checkbox" name="visa" value="Authorized to work in the US")
span(data-i18n="employers.filter_visa_yes") US Authorized
| (#{candidatesInFilter("visa","Authorized to work in the US")})
label
input(type="checkbox" name="visa" value="Need visa sponsorship")
span(data-i18n="employers.filter_visa_no") Not Authorized
| (#{candidatesInFilter("visa","Need visa sponsorship")})
.filter_section#school_filter
h4(data-i18n="account_profile.education") Education
label
input(type="checkbox" name="schoolFilter" value="Top School")
span(data-i18n="employers.filter_education_top") Top School
| (#{candidatesInFilter("schoolFilter","Top School")})
label
input(type="checkbox" name="schoolFilter" value="Other")
span(data-i18n="employers.filter_education_other") Other
| (#{candidatesInFilter("schoolFilter","Other")})
.filter_section#role_filter
h4(data-i18n="employers.candidate_role") Role
label
input(type="checkbox" name="roleFilter" value="Web Developer")
span(data-i18n="employers.filter_role_web_developer") Web Developer
| (#{candidatesInFilter("roleFilter","Web Developer")})
label
input(type="checkbox" name="roleFilter" value="Software Developer")
span(data-i18n="employers.filter_role_software_developer") Software Developer
| (#{candidatesInFilter("roleFilter","Software Developer")})
label
input(type="checkbox" name="roleFilter" value="Mobile Developer")
span(data-i18n="employers.filter_role_mobile_developer") Mobile Developer
| (#{candidatesInFilter("roleFilter","Mobile Developer")})
.filter_section#seniority_filter
h4(data-i18n="employers.filter_experience") Experience
label
input(type="checkbox" name="seniorityFilter" value="Senior")
span(data-i18n="employers.filter_experience_senior") Senior
| (#{candidatesInFilter("seniorityFilter","Senior")})
label
input(type="checkbox" name="seniorityFilter" value="Junior")
span(data-i18n="employers.filter_experience_junior") Junior
| (#{candidatesInFilter("seniorityFilter","Junior")})
label
input(type="checkbox" name="seniorityFilter" value="Recent Grad")
span(data-i18n="employers.filter_experience_recent_grad") Recent Grad
| (#{candidatesInFilter("seniorityFilter","Recent Grad")})
label
input(type="checkbox" name="seniorityFilter" value="College Student")
span(data-i18n="employers.filter_experience_student") College Student
| (#{candidatesInFilter("seniorityFilter","College Student")})
//input#select_all_checkbox(type="checkbox" name="select_all" checked)
//| Select all
p#results
| #{numberOfCandidates}
span(data-i18n="employers.results") results
h4#filter-alerts-heading Filter Email Alerts
p Get an email whenever a candidate meeting certain criteria enters the system.
table#saved-filter-table
thead
tr
th Filters
th Remove
tbody
button.btn#create-alert-button Create Alert with Current Filters
#candidates-column(class=fullProfiles ? "full-profiles col-md-9" : "teaser-profiles col-md-12")
if candidates.length
#candidate-table
table
tbody
for candidate, index in featuredCandidates
- var profile = candidate.get('jobProfile');
- var authorized = candidate.id; // If we have the id, then we are authorized.
- var profileAge = (new Date() - new Date(profile.updated)) / 86400 / 1000;
- var expired = profileAge > 2 * 30.4;
- var curated = profile.curated;
- var photoSize = fullProfiles ? 75 : 50;
tr.candidate-row(data-candidate-id=candidate.id, id=candidate.id, class=expired ? "expired" : "")
td(rowspan=3)
- var photoURL = candidate.getPhotoURL(photoSize, false, true);
div(class="candidate-picture " + (/^\/file/.test(photoURL) ? "" : "anonymous"), style='background-image: url(' + encodeURI(photoURL) + ')')
if fullProfiles
td.candidate-name-cell
strong= profile.name
| -
span= profile.jobTitle
tr.description_row(data-candidate-id=candidate.id)
if curated && curated.shortDescription
td.candidate-description
div #{curated.shortDescription}
else
td.candidate-description
div #{profile.shortDescription}
tr.border_row(data-candidate-id=candidate.id)
if curated
- var workHistory = curated.workHistory.join(",");
if !fullProfiles
td.tag_column
img(src="/images/pages/employer/tag.png")
| #{profile.jobTitle}
td.location_column
img(src="/images/pages/employer/location.png")
| #{curated.location}
td.education_column
img(src="/images/pages/employer/education.png")
| #{curated.education}
td.work_column
if workHistory
img(src="/images/pages/employer/briefcase.png")
| #{workHistory}
if !fullProfiles
div#info_wrapper
span.hiring-call-to-action
h2#start-hiring(data-i18n="employers.start_hiring") Start hiring.
button.btn.get-started-button.employer-button(data-i18n="employers.get_started") Get Started
h2#hiring-reasons.hiring-call-to-action(data-i18n="employers.reasons") Three reasons you should hire through us:
.reasons#top_row
.reason
img.employer_icon(src="/images/pages/employer/employer_icon2.png")
h3(data-i18n="employers.everyone_looking") Everyone here is looking for their next opportunity.
p(data-i18n="employers.everyone_looking_blurb") Forget about 20% LinkedIn InMail response rates. Everyone that we list on this site wants to find their next position and will respond to your request for an introduction.
.reason
img.employer_icon(src="/images/pages/employer/employer_icon6.png")
h3(data-i18n="employers.weeding") Sit back; we've done the weeding for you.
p(data-i18n="employers.weeding_blurb") Every player that we list has been screened for technical ability. We also perform phone screens for select candidates and make notes on their profiles to save you time.
.reason
img(class="employer_icon" src="/images/pages/employer/employer_icon3.png")
h3(data-i18n="employers.pass_screen") They will pass your technical screen.
p(data-i18n="employers.pass_screen_blurb") Review each candidate's code before reaching out. One employer found that 5x as many of our devs passed their technical screen than hiring from Hacker News.
span.hiring-call-to-action
h2(data-i18n="employers.make_hiring_easier") Make my hiring easier, please.
button.btn.get-started-button.employer-button(data-i18n="employers.get_started") Get Started
.reasons#bottom_row
.reason_long
img.employer_icon(src="/images/pages/employer/employer_icon1.png")
.reason_text
h3(data-i18n="employers.what") What is CodeCombat?
p(data-i18n="employers.what_blurb") CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. We support JavaScript, Python, Lua, Clojure, CoffeeScript, and Io.
.reason_long
img.employer_icon(src="/images/pages/employer/employer_icon5.png")
.reason_text
h3(data-i18n="employers.cost") How much do we charge?
p(data-i18n="employers.cost_blurb") We charge 15% of first year's salary and offer a 100% money back guarantee for 90 days. We don't charge for candidates who are already actively being interviewed at your company.

View file

@ -1,8 +1,8 @@
extends /templates/modal/modal_base
block modal-header-content
h1#choose-hero-header(data-i18n="choose_hero.choose_hero") Choose Your Hero
h1#choose-inventory-header.secret(data-i18n="inventory.choose_inventory") Equip Items
h1#choose-hero-header.choose-hero-active.secret(data-i18n="choose_hero.choose_hero") Choose Your Hero
h1#choose-inventory-header.choose-inventory-active.secret(data-i18n="inventory.choose_inventory") Equip Items
block modal-body-content
#choose-hero-view
@ -10,7 +10,7 @@ block modal-body-content
#inventory-view
block modal-footer-content
button#choose-inventory-button.btn.btn-lg.btn-success(data-i18n="play.next") Next
button#choose-hero-button.btn.btn-lg.btn-primary.secret.pull-left(data-i18n="play.previous") Previous
button#play-level-button.btn.btn-lg.btn-success.secret(data-i18n="common.play") Play
button#choose-inventory-button.btn.btn-lg.btn-success.choose-hero-active.secret(data-i18n="play.next") Next
button#choose-hero-button.btn.btn-lg.btn-primary.choose-inventory-active.secret.pull-left(data-i18n="play.change_hero") Change Hero
button#play-level-button.btn.btn-lg.btn-success.choose-inventory-active.secret(data-i18n="common.play") Play

View file

@ -1,4 +1,8 @@
.map
.gradient.horizontal-gradient.top-gradient
.gradient.vertical-gradient.right-gradient
.gradient.horizontal-gradient.bottom-gradient
.gradient.vertical-gradient.left-gradient
img.map-background(src="/images/pages/play/map_" + mapType + ".jpg", alt="")
- var seenNext = false;
@ -17,7 +21,7 @@
each i in Array(level.difficulty)
i.icon-star
- var playCount = levelPlayCountMap[level.id]
if playCount && playCount > 20
if playCount && playCount.sessions > 20
div
span.spr #{playCount.sessions}
span(data-i18n="play.players") players

View file

@ -115,6 +115,9 @@ module.exports = class InventoryView extends CocoView
@$el.find('#selected-items').hide() # Hide until one is selected
@delegateEvents()
if @selectedHero and not @startedLoadingFirstHero
@loadHero()
afterInsert: ->
super()
@canvasWidth = @$el.find('canvas').innerWidth()
@ -329,7 +332,8 @@ module.exports = class InventoryView extends CocoView
@loadHero()
loadHero: ->
return unless @selectedHero and not @$el.hasClass 'secret'
return unless @supermodel.finished() and @selectedHero and not @$el.hasClass 'secret'
@startedLoadingFirstHero = true
@stage?.removeAllChildren()
if @selectedHero.loaded and movieClip = @movieClips?[@selectedHero.get('original')]
@stage.addChild(movieClip)

View file

@ -17,6 +17,7 @@ class LevelSessionsCollection extends CocoCollection
module.exports = class WorldMapView extends RootView
id: 'world-map-view'
template: template
terrain: 'Dungeon' # or Grass
events:
'click .map-background': 'onClickMap'
@ -36,6 +37,7 @@ module.exports = class WorldMapView extends RootView
$(window).on 'resize', @onWindowResize
@playAmbientSound()
@preloadTopHeroes()
@hadEverChosenHero = me.get('heroConfig')?.thangType
destroy: ->
$(window).off 'resize', @onWindowResize
@ -75,7 +77,7 @@ module.exports = class WorldMapView extends RootView
context.levelStatusMap = @levelStatusMap
context.levelPlayCountMap = @levelPlayCountMap
context.isIPadApp = application.isIPadApp
context.mapType = 'dungeon'
context.mapType = _.string.slugify @terrain
context
afterRender: ->
@ -84,6 +86,7 @@ module.exports = class WorldMapView extends RootView
unless application.isIPadApp
_.defer => @$el.find('.game-controls .btn').tooltip() # Have to defer or i18n doesn't take effect.
@$el.find('.level').tooltip()
@$el.addClass _.string.slugify @terrain
onSessionsLoaded: (e) ->
for session in @sessions.models
@ -113,7 +116,7 @@ module.exports = class WorldMapView extends RootView
@startLevel $(e.target).parents('.level-info-container')
startLevel: (levelElement) ->
playLevelModal = new PlayLevelModal supermodel: @supermodel, levelID: levelElement.data('level-id'), levelPath: levelElement.data('level-path'), levelName: levelElement.data('level-name')
playLevelModal = new PlayLevelModal supermodel: @supermodel, levelID: levelElement.data('level-id'), levelPath: levelElement.data('level-path'), levelName: levelElement.data('level-name'), hadEverChosenHero: @hadEverChosenHero
@openModalView playLevelModal
@$levelInfo?.hide()
@ -148,28 +151,45 @@ module.exports = class WorldMapView extends RootView
@$levelInfo.css('top', top)
onWindowResize: (e) =>
mapHeight = 1536
mapWidth = 2350 # 2500 for forest
mapHeight = iPadHeight = 1536
mapWidth = if @terrain is 'Dungeon' then 2350 else 2500
iPadWidth = 2048
aspectRatio = mapWidth / mapHeight
iPadAspectRatio = iPadWidth / iPadHeight
pageWidth = $(window).width()
pageHeight = $(window).height()
widthRatio = pageWidth / mapWidth
heightRatio = pageHeight / mapHeight
if widthRatio > heightRatio
resultingWidth = pageWidth
resultingHeight = resultingWidth / aspectRatio
iPadWidthRatio = pageWidth / iPadWidth
if @terrain is 'Dungeon'
# Make sure we can see almost the whole map, fading to background in one dimension.
if heightRatio <= iPadWidthRatio
# Full width, full height, left and right margin
resultingHeight = pageHeight
resultingWidth = resultingHeight * aspectRatio
else if iPadWidthRatio < heightRatio * (iPadAspectRatio / aspectRatio)
# Cropped width, full height, left and right margin
resultingWidth = pageWidth
resultingHeight = resultingWidth / aspectRatio
else
# Cropped width, full height, top and bottom margin
resultingWidth = pageWidth * aspectRatio / iPadAspectRatio
resultingHeight = resultingWidth / aspectRatio
else
resultingHeight = pageHeight
resultingWidth = resultingHeight * aspectRatio
# Scale it in either dimension so that we're always full on one of the dimensions.
if heightRatio > widthRatio
resultingHeight = pageHeight
resultingWidth = resultingHeight * aspectRatio
else
resultingWidth = pageWidth
resultingHeight = resultingWidth / aspectRatio
resultingMarginX = (pageWidth - resultingWidth) / 2
resultingMarginY = (pageHeight - resultingHeight) / 2
@$el.find('.map').css(width: resultingWidth, height: resultingHeight, 'margin-left': resultingMarginX, 'margin-top': resultingMarginY)
playAmbientSound: ->
return if @ambientSound
#terrain = 'Grass'
terrain = 'Dungeon'
return unless file = {Dungeon: 'ambient-dungeon', Grass: 'ambient-map-grass'}[terrain]
return unless file = {Dungeon: 'ambient-dungeon', Grass: 'ambient-map-grass'}[@terrain]
src = "/file/interface/#{file}#{AudioPlayer.ext}"
unless AudioPlayer.getStatus(src)?.loaded
AudioPlayer.preloadSound src
@ -531,8 +551,8 @@ hero = [
id: 'dungeons-of-kithgard'
original: '528110f30268d018e3000001'
description: 'Grab the gem, but touch nothing else. Start here.'
x: 20.24
y: 32.93
x: 14
y: 15.5
}
{
name: 'Gems in the Deep'
@ -541,8 +561,8 @@ hero = [
id: 'gems-in-the-deep'
original: '54173c90844506ae0195a0b4'
description: 'Quickly collect the gems; you will need them.'
x: 18.47
y: 49.78
x: 32
y: 15.5
}
{
name: 'Shadow Guard'
@ -551,8 +571,8 @@ hero = [
id: 'shadow-guard'
original: '54174347844506ae0195a0b8'
description: 'Evade the Kithgard minion.'
x: 30.89
y: 61.30
x: 54
y: 9
}
{
name: 'True Names'
@ -561,8 +581,8 @@ hero = [
id: 'true-names'
original: '541875da4c16460000ab990f'
description: 'Learn an enemy\'s true name to defeat it.'
x: 44.39
y: 57.39
x: 74
y: 12
}
{
name: 'The Raised Sword'
@ -571,8 +591,8 @@ hero = [
id: 'the-raised-sword'
original: '5418aec24c16460000ab9aa6'
description: 'Learn to equip yourself for combat.'
x: 41.83
y: 41.74
x: 85
y: 20
}
{
name: 'The First Kithmaze'
@ -581,8 +601,8 @@ hero = [
id: 'the-first-kithmaze'
original: '5418b9d64c16460000ab9ab4'
description: 'The builders of Kith constructed many mazes to confuse travelers.'
x: 57.39
y: 48.15
x: 70
y: 28
}
{
name: 'The Second Kithmaze'
@ -591,8 +611,8 @@ hero = [
id: 'the-second-kithmaze'
original: '5418cf256bae62f707c7e1c3'
description: 'Many have tried, few have found their way through this maze.'
x: 61.72
y: 37.07
x: 67
y: 41
}
{
name: 'New Sight'
@ -611,8 +631,8 @@ hero = [
id: 'lowly-kithmen'
original: '541b24511ccc8eaae19f3c1f'
description: 'Use your glasses to seek out and attack the Kithmen.'
x: 70.53
y: 27.93
x: 74
y: 48
}
{
name: 'A Bolt in the Dark'
@ -621,8 +641,8 @@ hero = [
id: 'a-bolt-in-the-dark'
original: '541b288e1ccc8eaae19f3c25'
description: 'Kithmen are not the only ones to stand in your way.'
x: 86.08
y: 40.76
x: 76
y: 60
}
{
name: 'The Final Kithmaze'
@ -631,8 +651,8 @@ hero = [
id: 'the-final-kithmaze'
original: '541b434e1ccc8eaae19f3c33'
description: 'To escape you must find your way through an Elder Kithman\'s maze.'
x: 96.95
y: 58.15
x: 82
y: 70
}
{
name: 'Kithgard Gates'
@ -642,8 +662,8 @@ hero = [
original: '541c9a30c6362edfb0f34479'
description: 'Escape the Kithgard dungeons and don\'t let the guardians get you.'
disabled: true
x: 84.02
y: 72.39
x: 89
y: 82
}
{
name: 'Defence of Plainswood'

View file

@ -45,8 +45,14 @@ module.exports = class PlayLevelModal extends ModalView
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
@insertSubView @chooseHeroView = new ChooseHeroView @options
@insertSubView @inventoryView = new InventoryView @options
@inventoryView.$el.addClass 'secret'
@chooseHeroView.onShown()
if @options.hadEverChosenHero
@$el.find('.choose-hero-active').add(@chooseHeroView.$el).addClass 'secret'
@$el.find('.choose-inventory-active').removeClass 'secret'
@inventoryView.onShown()
else
@$el.find('.choose-inventory-active').add(@inventoryView.$el).addClass 'secret'
@$el.find('.choose-hero-active').removeClass 'secret'
@chooseHeroView.onShown()
onHidden: ->
unless @navigatingToPlay

View file

@ -21,20 +21,20 @@ module.exports.setup = (app) ->
setupScheduledEmails = ->
testForLockManager()
mailTasks = [
taskFunction: candidateUpdateProfileTask
frequencyMs: 10 * 60 * 1000 #10 minutes
,
taskFunction: internalCandidateUpdateTask
frequencyMs: 10 * 60 * 1000 #10 minutes
,
taskFunction: employerNewCandidatesAvailableTask
frequencyMs: 10 * 60 * 1000 #10 minutes
,
taskFunction: unapprovedCandidateFinishProfileTask
frequencyMs: 10 * 60 * 1000
,
taskFunction: emailUserRemarkTaskRemindersTask
frequencyMs: 10 * 60 * 1000
# taskFunction: candidateUpdateProfileTask
# frequencyMs: 10 * 60 * 1000 #10 minutes
#,
# taskFunction: internalCandidateUpdateTask
# frequencyMs: 10 * 60 * 1000 #10 minutes
#,
# taskFunction: employerNewCandidatesAvailableTask
# frequencyMs: 10 * 60 * 1000 #10 minutes
#,
# taskFunction: unapprovedCandidateFinishProfileTask
# frequencyMs: 10 * 60 * 1000
#,
# taskFunction: emailUserRemarkTaskRemindersTask
# frequencyMs: 10 * 60 * 1000
]
for mailTask in mailTasks