untrusted-test-only / scripts /dynamicObject.js
lychees's picture
Upload 569 files
87b3b3a
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();
}
}