mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 23:58:02 -05:00
Started implementing web-dev goals
This commit is contained in:
parent
69f21514b9
commit
c44c16e5d2
5 changed files with 93 additions and 7 deletions
|
@ -14,18 +14,20 @@ function receiveMessage(event) {
|
|||
switch (event.data.type) {
|
||||
case 'create':
|
||||
create(event.data.dom);
|
||||
checkGoals(event.data.goals);
|
||||
break;
|
||||
case 'update':
|
||||
if (virtualDOM)
|
||||
update(event.data.dom);
|
||||
else
|
||||
create(event.data.dom);
|
||||
create(event.data.dom);
|
||||
checkGoals(event.data.goals);
|
||||
break;
|
||||
case 'log':
|
||||
console.log(event.data.text);
|
||||
break;
|
||||
default:
|
||||
console.log('Unknown message type:', event.data.type);
|
||||
console.log('Unknown message type:', event.data.type);
|
||||
}
|
||||
|
||||
//event.source.postMessage("hi there yourself! the secret response is: rheeeeet!", event.origin);
|
||||
|
@ -45,3 +47,73 @@ function update(dom) {
|
|||
changes.reduce(deku.dom.update(dispatch, context), concreteDOM) // Rerender
|
||||
virtualDOM = event.data.dom;
|
||||
}
|
||||
|
||||
function checkGoals(goals) {
|
||||
goals.forEach(function(goal) {
|
||||
var $result = $(goal.html.selector);
|
||||
//console.log('ran selector', goal.html.selector, 'to find element(s)', $result);
|
||||
var success = true;
|
||||
goal.html.valueChecks.forEach(function(check) {
|
||||
//console.log(' ... and should make sure that the value of', check.eventProps, 'is', _.omit(check, 'eventProps'), '?', matchesCheck($result, check))
|
||||
success = success && matchesCheck($result, check)
|
||||
});
|
||||
console.log('HTML', goal.id, '-', goal.name, '- succeeds?', success)
|
||||
});
|
||||
}
|
||||
|
||||
function downTheChain(obj, keyChain) {
|
||||
if (!obj)
|
||||
return null;
|
||||
if (!_.isArray(keyChain))
|
||||
return obj[keyChain];
|
||||
var value = obj;
|
||||
while (keyChain.length && value) {
|
||||
if (keyChain[0].match(/\(.*\)$/)) {
|
||||
var args, argsString = keyChain[0].match(/\((.*)\)$/)[1];
|
||||
if (argsString)
|
||||
args = eval(argsString).split(/, ?/g).filter(function(x) { return x !== ""; }); // TODO: can/should we avoid eval here?
|
||||
else
|
||||
args = [];
|
||||
value = value[keyChain[0].split('(')[0]].apply(value, args); // value.text(), value.css('background-color'), etc.
|
||||
}
|
||||
else
|
||||
value = value[keyChain[0]];
|
||||
keyChain = keyChain.slice(1);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
function matchesCheck(value, check) {
|
||||
var v = downTheChain(value, check.eventProps);
|
||||
if ((check.equalTo != null) && v !== check.equalTo) {
|
||||
return false;
|
||||
}
|
||||
if ((check.notEqualTo != null) && v === check.notEqualTo) {
|
||||
return false;
|
||||
}
|
||||
if ((check.greaterThan != null) && !(v > check.greaterThan)) {
|
||||
return false;
|
||||
}
|
||||
if ((check.greaterThanOrEqualTo != null) && !(v >= check.greaterThanOrEqualTo)) {
|
||||
return false;
|
||||
}
|
||||
if ((check.lessThan != null) && !(v < check.lessThan)) {
|
||||
return false;
|
||||
}
|
||||
if ((check.lessThanOrEqualTo != null) && !(v <= check.lessThanOrEqualTo)) {
|
||||
return false;
|
||||
}
|
||||
if ((check.containingString != null) && (!v || v.search(check.containingString) === -1)) {
|
||||
return false;
|
||||
}
|
||||
if ((check.notContainingString != null) && (v != null ? v.search(check.notContainingString) : void 0) !== -1) {
|
||||
return false;
|
||||
}
|
||||
if ((check.containingRegexp != null) && (!v || v.search(new RegExp(check.containingRegexp)) === -1)) {
|
||||
return false;
|
||||
}
|
||||
if ((check.notContainingRegexp != null) && (v != null ? v.search(new RegExp(check.notContainingRegexp)) : void 0) !== -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ module.exports = class GoalManager extends CocoClass
|
|||
subscriptions:
|
||||
'god:new-world-created': 'onNewWorldCreated'
|
||||
'level:restarted': 'onLevelRestarted'
|
||||
#'tome:html-updated': 'onHTMLUpdated'
|
||||
|
||||
backgroundSubscriptions:
|
||||
'world:thang-died': 'onThangDied'
|
||||
|
@ -114,7 +115,7 @@ module.exports = class GoalManager extends CocoClass
|
|||
goalStates: @goalStates
|
||||
goals: @goals
|
||||
overallStatus: overallStatus
|
||||
timedOut: @world.totalFrames is @world.maxTotalFrames and overallStatus not in ['success', 'failure']
|
||||
timedOut: @world? and (@world.totalFrames is @world.maxTotalFrames and overallStatus not in ['success', 'failure'])
|
||||
Backbone.Mediator.publish('goal-manager:new-goal-states', event)
|
||||
|
||||
checkOverallStatus: (ignoreIncomplete=false) ->
|
||||
|
@ -220,6 +221,11 @@ module.exports = class GoalManager extends CocoClass
|
|||
return unless linesAllowed = who[thang.id] ? who[thang.team]
|
||||
@updateGoalState goalID, thang.id, 'lines', frameNumber if linesUsed > linesAllowed
|
||||
|
||||
#checkHTML: (goal, html) ->
|
||||
# console.log 'should run selector', goal.html.selector, 'to find element(s)'
|
||||
# console.log ' ... and should make sure that the value of', check.eventProps, 'is', _.omit(check, 'eventProps') for check in goal.html.valueChecks
|
||||
# console.log 'should do it with cheerio', window.cheerio
|
||||
|
||||
wrapUpGoalStates: (finalFrame) ->
|
||||
for goalID, state of @goalStates
|
||||
if state.status is null
|
||||
|
@ -264,7 +270,7 @@ module.exports = class GoalManager extends CocoClass
|
|||
mostEagerGoal = _.min matchedGoals, 'worldEndsAfter'
|
||||
victory = overallStatus is 'success'
|
||||
tentative = overallStatus is 'success'
|
||||
@world.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
|
||||
@world?.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
|
||||
|
||||
updateGoalState: (goalID, thangID, progressObjectName, frameNumber) ->
|
||||
# A thang has done something related to the goal!
|
||||
|
@ -291,7 +297,7 @@ module.exports = class GoalManager extends CocoClass
|
|||
mostEagerGoal = _.min matchedGoals, 'worldEndsAfter'
|
||||
victory = overallStatus is 'success'
|
||||
tentative = overallStatus is 'success'
|
||||
@world.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
|
||||
@world?.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
|
||||
|
||||
goalIsPositive: (goalID) ->
|
||||
# Positive goals are completed when all conditions are true (kill all these thangs)
|
||||
|
@ -314,6 +320,9 @@ module.exports = class GoalManager extends CocoClass
|
|||
linesOfCode: 0
|
||||
codeProblems: 0
|
||||
|
||||
#onHTMLUpdated: (e) ->
|
||||
# @checkHTML goal, e.html for goal in @goals when goal.html
|
||||
|
||||
updateCodeGoalStates: ->
|
||||
# TODO
|
||||
|
||||
|
|
|
@ -114,6 +114,9 @@ GoalSchema = c.object {title: 'Goal', description: 'A goal that the player can a
|
|||
targets: c.array {title: 'Targets', description: 'The target items which the Thangs must not collect.', minItems: 1}, thang
|
||||
codeProblems: c.array {title: 'Code Problems', description: 'A list of Thang IDs that should not have any code problems, or team names.', uniqueItems: true, minItems: 1, 'default': ['humans']}, thang
|
||||
linesOfCode: {title: 'Lines of Code', description: 'A mapping of Thang IDs or teams to how many many lines of code should be allowed (well, statements).', type: 'object', default: {humans: 10}, additionalProperties: {type: 'integer', description: 'How many lines to allow for this Thang.'}}
|
||||
html: c.object {title: 'HTML', description: 'A jQuery selector and what its result should be'},
|
||||
selector: {type: 'string', description: 'jQuery selector to run on the user HTML, like "h1:first-child"'}
|
||||
valueChecks: c.array {title: 'Value checks', description: 'Logical checks on the resulting value for this goal to pass.', format: 'event-prereqs'}, EventPrereqSchema
|
||||
|
||||
ResponseSchema = c.object {title: 'Dialogue Button', description: 'A button to be shown to the user with the dialogue.', required: ['text']},
|
||||
text: {title: 'Title', description: 'The text that will be on the button', 'default': 'Okay', type: 'string', maxLength: 30}
|
||||
|
|
|
@ -269,7 +269,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
@insertSubView new DuelStatsView level: @level, session: @session, otherSession: @otherSession, supermodel: @supermodel, thangs: @world.thangs if @level.isType('hero-ladder', 'course-ladder')
|
||||
@insertSubView @controlBar = new ControlBarView {worldName: utils.i18n(@level.attributes, 'name'), session: @session, level: @level, supermodel: @supermodel, courseID: @courseID, courseInstanceID: @courseInstanceID}
|
||||
@insertSubView @hintsView = new HintsView({ @session, @level, @hintsState }), @$('.hints-view')
|
||||
@insertSubView @webSurface = new WebSurfaceView level: @level if @level.isType('web-dev')
|
||||
@insertSubView @webSurface = new WebSurfaceView {level: @level, @goalManager} if @level.isType('web-dev')
|
||||
#_.delay (=> Backbone.Mediator.publish('level:set-debug', debug: true)), 5000 if @isIPadApp() # if me.displayName() is 'Nick'
|
||||
|
||||
initVolume: ->
|
||||
|
|
|
@ -12,6 +12,8 @@ module.exports = class WebSurfaceView extends CocoView
|
|||
initialize: (options) ->
|
||||
@state = new State
|
||||
blah: 'blah'
|
||||
@goals = (goal for goal in options.goalManager.goals when goal.html)
|
||||
# Consider https://www.npmjs.com/package/css-select to do this on virtualDOM instead of in iframe on concreteDOM
|
||||
super(options)
|
||||
|
||||
afterRender: ->
|
||||
|
@ -34,7 +36,7 @@ module.exports = class WebSurfaceView extends CocoView
|
|||
# TODO: pull out the actual scripts, styles, and body/elements they are doing so we can merge them with our initial structure on the other side
|
||||
virtualDOM = @dekuify html
|
||||
messageType = if e.create or not @virtualDOM then 'create' else 'update'
|
||||
@iframe.contentWindow.postMessage {type: messageType, dom: virtualDOM}, '*'
|
||||
@iframe.contentWindow.postMessage {type: messageType, dom: virtualDOM, goals: @goals}, '*'
|
||||
@virtualDOM = virtualDOM
|
||||
|
||||
checkGoals: (dom) ->
|
||||
|
|
Loading…
Reference in a new issue