Spaces:
Running
Running
| function DynamicObject(map, type, x, y, __game) { | |
| /* private variables */ | |
| var __x = x; | |
| var __y = y; | |
| var __type = type; | |
| var __definition = __game._callUnexposedMethod(function () { | |
| return map._getObjectDefinition(type); | |
| }); | |
| var __inventory = []; | |
| var __destroyed = false; | |
| var __myTurn = true; | |
| var __timer = null; | |
| this._map = map; | |
| /* wrapper */ | |
| function wrapExposedMethod(f, object) { | |
| return function () { | |
| var args = arguments; | |
| return __game._callUnexposedMethod(function () { | |
| return f.apply(object, args); | |
| }); | |
| }; | |
| }; | |
| /* unexposed methods */ | |
| this._computeDestination = function (startX, startY, direction) { | |
| if (__game._isPlayerCodeRunning()) { throw 'Forbidden method call: object._computeDestination()';} | |
| switch (direction) { | |
| case 'up': | |
| return {'x': startX, 'y': startY - 1}; | |
| case 'down': | |
| return {'x': startX, 'y': startY + 1}; | |
| case 'left': | |
| return {'x': startX - 1, 'y': startY}; | |
| case 'right': | |
| return {'x': startX + 1, 'y': startY}; | |
| default: | |
| return {'x': startX, 'y': startY}; | |
| } | |
| }; | |
| this._onTurn = function () { | |
| if (__game._isPlayerCodeRunning()) { throw 'Forbidden method call: object._onTurn()';} | |
| var me = this; | |
| var player = map.getPlayer(); | |
| function executeTurn() { | |
| if (map._callbackValidationFailed) { | |
| clearInterval(__timer); | |
| return; | |
| } | |
| __myTurn = true; | |
| try { | |
| //we need to check for a collision with the player *after* | |
| //the player has moved but *before* the object itself moves | |
| //this prevents a bug where players and objects can 'pass through' | |
| //each other | |
| if (__x === player.getX() && __y === player.getY()) { | |
| if (__definition.pushable) { | |
| me.move(player.getLastMoveDirection()); | |
| } | |
| if (__definition.onCollision) { | |
| map._validateCallback(function () { | |
| __definition.onCollision(player, me); | |
| }); | |
| } | |
| } | |
| if (__myTurn && __definition.behavior) { | |
| map._validateCallback(function () { | |
| __definition.behavior(me, player); | |
| }); | |
| } | |
| } catch (e) { | |
| // throw e; // for debugging | |
| map.writeStatus(e.toString()); | |
| } | |
| } | |
| if (__definition.interval) { | |
| // start timer if not already set | |
| if (!__timer) { | |
| __timer = setInterval(executeTurn, __definition.interval); | |
| } | |
| // don't move on regular turn, but still check for player collision | |
| if (map.getPlayer().atLocation(__x, __y) && | |
| (__definition.onCollision || __definition.projectile)) { | |
| // trigger collision | |
| if (__definition.projectile) { | |
| // projectiles automatically kill | |
| map.getPlayer().killedBy('a ' + __type); | |
| } else { | |
| var thing = this; | |
| map._validateCallback(function () { | |
| __definition.onCollision(map.getPlayer(), thing); | |
| }); | |
| } | |
| } | |
| } else { | |
| executeTurn(); | |
| } | |
| }; | |
| this._afterMove = function () { | |
| if (__game._isPlayerCodeRunning()) { throw 'Forbidden method call: object._afterMove()';} | |
| // try to pick up items | |
| var objectName = map._getGrid()[__x][__y].type; | |
| var object = map._getObjectDefinition(objectName); | |
| if (object.type === 'item' && !__definition.projectile) { | |
| __inventory.push(objectName); | |
| map._removeItemFromMap(__x, __y, objectName); | |
| map._playSound('pickup'); | |
| } else if (object.type === 'trap') { | |
| // this part is used by janosgyerik's bonus levels | |
| if (object.deactivatedBy && object.deactivatedBy.indexOf(__type) > -1) { | |
| if (typeof(object.onDeactivate) === 'function') { | |
| __game.validateCallback(function(){ | |
| object.onDeactivate(); | |
| }); | |
| } | |
| map._removeItemFromMap(__x, __y, objectName); | |
| } | |
| } | |
| }; | |
| this._destroy = function (onMapReset) { | |
| if (__game._isPlayerCodeRunning()) { throw 'Forbidden method call: object._destroy()';} | |
| var me = this; | |
| __destroyed = true; | |
| clearInterval(__timer); | |
| // remove this object from map's __dynamicObjects list | |
| map._refreshDynamicObjects(); | |
| // unless the map is being reset, play an explosion | |
| // and call this object's onDestroy method | |
| if (__definition.onDestroy && !onMapReset) { | |
| if (!__definition.projectile) { | |
| map._playSound('explosion'); | |
| } | |
| map._validateCallback(function () { | |
| __definition.onDestroy(me); | |
| }); | |
| } | |
| }; | |
| /* exposed methods */ | |
| this.getX = function () { return __x; }; | |
| this.getY = function () { return __y; }; | |
| this.getType = function () { return __type; }; | |
| this.isDestroyed = function () { return __destroyed; }; | |
| this.giveItemTo = wrapExposedMethod(function (player, itemType) { | |
| var pl_at = player.atLocation; | |
| if (!(pl_at(__x, __y) || pl_at(__x+1, __y) || pl_at(__x-1, __y) || | |
| pl_at(__x, __y+1) || pl_at(__x, __y-1))) { | |
| throw (type + ' says: Can\'t give an item unless I\'m touching the player!'); | |
| } | |
| if (__inventory.indexOf(itemType) < 0) { | |
| throw (type + ' says: I don\'t have that item!'); | |
| } | |
| player._pickUpItem(itemType, map._getObjectDefinition(itemType)); | |
| }, this); | |
| this.move = wrapExposedMethod(function (direction) { | |
| var dest = this._computeDestination(__x, __y, direction); | |
| if (!__myTurn) { | |
| throw 'Can\'t move when it isn\'t your turn!'; | |
| } | |
| var nearestObj = map._findNearestToPoint("anyDynamic", dest.x, dest.y); | |
| // check for collision with player | |
| if (map.getPlayer().atLocation(dest.x, dest.y) && | |
| (__definition.onCollision || __definition.projectile)) { | |
| // trigger collision | |
| if (__definition.projectile) { | |
| // projectiles automatically kill | |
| map.getPlayer().killedBy('a ' + __type); | |
| } else { | |
| var thing = this; | |
| map._validateCallback(function() { | |
| __definition.onCollision(map.getPlayer(), thing); | |
| }); | |
| } | |
| } else if (map._canMoveTo(dest.x, dest.y, __type) && | |
| !map._isPointOccupiedByDynamicObject(dest.x, dest.y)) { | |
| // move the object | |
| __x = dest.x; | |
| __y = dest.y; | |
| this._afterMove(__x, __y); | |
| } else { | |
| // cannot move | |
| if (__definition.projectile) { | |
| // projectiles disappear when they cannot move | |
| this._destroy(); | |
| // projectiles also destroy any dynamic objects they touch | |
| if (map._isPointOccupiedByDynamicObject(dest.x, dest.y)) { | |
| map._findDynamicObjectAtPoint(dest.x, dest.y)._destroy(); | |
| } | |
| } | |
| } | |
| __myTurn = false; | |
| }, this); | |
| this.canMove = wrapExposedMethod(function (direction) { | |
| var dest = this._computeDestination(__x, __y, direction); | |
| // check if the object can move there and will not collide with | |
| // another dynamic object | |
| return (map._canMoveTo(dest.x, dest.y, __type) && | |
| !map._isPointOccupiedByDynamicObject(dest.x, dest.y)); | |
| }, this); | |
| this.findNearest = wrapExposedMethod(function (type) { | |
| return map._findNearestToPoint(type, __x, __y); | |
| }, this); | |
| // only for teleporters | |
| this.setTarget = wrapExposedMethod(function (target) { | |
| if (__type != 'teleporter') { | |
| throw 'setTarget() can only be called on a teleporter!'; | |
| } | |
| if (target === this) { | |
| throw 'Teleporters cannot target themselves!'; | |
| } | |
| this.target = target; | |
| }, this); | |
| // call secureObject to prevent user code from tampering with private attributes | |
| __game.secureObject(this, type); | |
| // constructor | |
| if (!map._dummy && __definition.interval) { | |
| this._onTurn(); | |
| } | |
| } | |