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(); | |
} | |
} | |