mirror of
https://github.com/id-Software/wolf3d-browser.git
synced 2026-03-19 16:39:27 +01:00
Wolfenstein 3D browser version
This is the code for the browser version of Wolfenstein 3D which is playable on http://www.wolfenstein.com/game_NA.php
This commit is contained in:
814
js/player.js
Normal file
814
js/player.js
Normal file
@@ -0,0 +1,814 @@
|
||||
/*
|
||||
* ===========================================================================
|
||||
*
|
||||
* Wolf3D Browser Version GPL Source Code
|
||||
* Copyright (C) 2012 id Software LLC, a ZeniMax Media company.
|
||||
*
|
||||
* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code").
|
||||
*
|
||||
* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Wolf3D Browser Source Code is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version 2
|
||||
* along with Wolf3D Browser Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you have questions concerning this license, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
*
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
* @description Player management
|
||||
*/
|
||||
Wolf.Player = (function() {
|
||||
|
||||
Wolf.setConsts({
|
||||
PLAYERSIZE : Wolf.MINDIST, // player radius
|
||||
STOPSPEED : 0x0D00,
|
||||
FRICTION : 0.25,
|
||||
MAXMOVE : (Wolf.MINDIST*2-1),
|
||||
EXTRAPOINTS : 40000, // points for an extra life
|
||||
ITEM_KEY_1 : 1,
|
||||
ITEM_KEY_2 : 2,
|
||||
ITEM_KEY_3 : 4,
|
||||
ITEM_KEY_4 : 8,
|
||||
ITEM_WEAPON_1 : 16,
|
||||
ITEM_WEAPON_2 : 32,
|
||||
ITEM_WEAPON_3 : 64,
|
||||
ITEM_WEAPON_4 : 128,
|
||||
ITEM_WEAPON_5 : 256,
|
||||
ITEM_WEAPON_6 : 512,
|
||||
ITEM_WEAPON_7 : 1024,
|
||||
ITEM_WEAPON_8 : 2048,
|
||||
ITEM_BACKPACK : (1<<12), // doubles carrying capacity
|
||||
ITEM_AUGMENT : (1<<13), // adds 50 to maximum health
|
||||
ITEM_UNIFORM : (1<<14), // allows you to pass guards
|
||||
ITEM_AUTOMAP : (1<<15), // shows unknown map ares in other color (as in DooM)
|
||||
ITEM_FREE : (1<<16), // - unused -
|
||||
PL_FLAG_REUSE : 1, // use button pressed
|
||||
PL_FLAG_ATTCK : 2, // attacking
|
||||
// debug (cheat codes) flags
|
||||
FL_GODMODE : (1<<4),
|
||||
FL_NOTARGET : (1<<6),
|
||||
|
||||
WEAPON_KNIFE : 0,
|
||||
WEAPON_PISTOL : 1,
|
||||
WEAPON_AUTO : 2,
|
||||
WEAPON_CHAIN : 3,
|
||||
WEAPON_TYPES : 4,
|
||||
|
||||
KEY_GOLD : 0,
|
||||
KEY_SILVER : 1,
|
||||
KEY_FREE1 : 2,
|
||||
KEY_FREE2 : 3,
|
||||
KEY_TYPES : 4,
|
||||
|
||||
AMMO_BULLETS : 0,
|
||||
AMMO_TYPES : 1,
|
||||
|
||||
ex_notingame : 0,
|
||||
ex_playing : 1,
|
||||
ex_dead : 2,
|
||||
ex_secretlevel : 3,
|
||||
ex_victory : 4,
|
||||
ex_complete : 5,
|
||||
|
||||
// victory animation
|
||||
BJRUNSPEED : 2048,
|
||||
BJJUMPSPEED : 680
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
/*
|
||||
struct atkinf
|
||||
{
|
||||
char tics, attack, frame; // attack is 1 for gun, 2 for knife
|
||||
}
|
||||
*/
|
||||
var attackinfo = [ // 4 guns, 14 frames max for every gun!
|
||||
[ {tics:6,attack:0,frame:1},{tics:6,attack:2,frame:2},{tics:6,attack:0,frame:3},{tics:6,attack:-1,frame:0}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ],
|
||||
[ {tics:6,attack:0,frame:1},{tics:6,attack:1,frame:2},{tics:6,attack:0,frame:3},{tics:6,attack:-1,frame:0}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ],
|
||||
[ {tics:6,attack:0,frame:1},{tics:6,attack:1,frame:2},{tics:6,attack:3,frame:3},{tics:6,attack:-1,frame:0}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ],
|
||||
[ {tics:6,attack:0,frame:1},{tics:6,attack:1,frame:2},{tics:6,attack:4,frame:3},{tics:6,attack:-1,frame:0}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ]
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* @description Spawn the player
|
||||
* @memberOf Wolf.Player
|
||||
* @param {object} location The location to spawn the player {origin, angle}
|
||||
* @param {object} level The level object
|
||||
* @param {number} skill The difficulty level
|
||||
* @param {object} [oldPlayer] A player object to copy score and weapons from
|
||||
* @returns {object} The new player object
|
||||
*/
|
||||
function spawn(location, level, skill, oldPlayer) {
|
||||
|
||||
var x = location.x,
|
||||
y = location.y,
|
||||
angle = location.angle,
|
||||
tileX = Wolf.POS2TILE(x),
|
||||
tileY = Wolf.POS2TILE(y),
|
||||
areanumber = level.areas[tileX][tileY];
|
||||
|
||||
// Player structure: Holds all info about player
|
||||
var player = {
|
||||
episode : -1,
|
||||
level : -1,
|
||||
health : 100,
|
||||
frags : 0,
|
||||
ammo : [
|
||||
],
|
||||
score : 0,
|
||||
lives : 0,
|
||||
startScore : 0,
|
||||
nextExtra : 0,
|
||||
items : 0, // (keys, weapon)
|
||||
weapon : 0,
|
||||
pendingWeapon : -1,
|
||||
previousWeapon : -1,
|
||||
position : {
|
||||
x : x,
|
||||
y : y
|
||||
},
|
||||
angle : angle,
|
||||
tile : {
|
||||
x : tileX,
|
||||
y : tileY
|
||||
},
|
||||
mov : {
|
||||
x : 0,
|
||||
y : 0
|
||||
},
|
||||
speed : 0,
|
||||
armor : 0, // there are 2 types. The better one is indicated by high bit set
|
||||
cmd : { // movement / action command
|
||||
forwardMove : 0,
|
||||
sideMove : 0,
|
||||
buttons : 0,
|
||||
impulse : 0
|
||||
},
|
||||
attackFrame : 0, // attack info
|
||||
attackCount : 0,
|
||||
weaponFrame : 0,
|
||||
|
||||
madenoise : false,
|
||||
lastAttacker : null,
|
||||
|
||||
faceFrame : 0,
|
||||
faceCount : 0, // bj's face in the HUD // FIXME decide something!
|
||||
faceGotGun : false,
|
||||
faceOuch : false,
|
||||
|
||||
flags : 0,
|
||||
areanumber : areanumber,
|
||||
playstate : 0,
|
||||
|
||||
attackDirection : [0,0],
|
||||
|
||||
skill : skill
|
||||
};
|
||||
|
||||
if (player.areanumber < 0) {
|
||||
player.areanumber = 36;
|
||||
}
|
||||
|
||||
Wolf.Areas.init(level, player.areanumber);
|
||||
Wolf.Areas.connect(level, player.areanumber);
|
||||
|
||||
if (oldPlayer) {
|
||||
copyPlayer(player, oldPlayer);
|
||||
} else {
|
||||
newGame(player);
|
||||
}
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description Copy player variables from another player object
|
||||
* @private
|
||||
* @param {object} player The player object
|
||||
* @param {object} copyPlayer The player object to copy from
|
||||
*/
|
||||
function copyPlayer(player, copyPlayer) {
|
||||
player.health = copyPlayer.health;
|
||||
player.ammo = copyPlayer.ammo;
|
||||
player.score = copyPlayer.score;
|
||||
player.startScore = copyPlayer.startScore;
|
||||
player.lives = copyPlayer.lives;
|
||||
player.previousWeapon = copyPlayer.previousWeapon;
|
||||
player.weapon = copyPlayer.weapon;
|
||||
player.pendingWeapon = copyPlayer.pendingWeapon;
|
||||
player.items = (copyPlayer.items & Wolf.ITEM_WEAPON_1) |
|
||||
(copyPlayer.items & Wolf.ITEM_WEAPON_2) |
|
||||
(copyPlayer.items & Wolf.ITEM_WEAPON_3) |
|
||||
(copyPlayer.items & Wolf.ITEM_WEAPON_4);
|
||||
player.nextExtra = copyPlayer.nextExtra;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Set up player for the new game
|
||||
* @memberOf Wolf.Player
|
||||
* @param {object} player The player object
|
||||
*/
|
||||
function newGame(player) {
|
||||
player.health = 100;
|
||||
player.ammo[Wolf.AMMO_BULLETS] = 8;
|
||||
player.score = 0;
|
||||
player.startScore = 0;
|
||||
player.lives = 3;
|
||||
player.previousWeapon = Wolf.WEAPON_KNIFE; //gsh
|
||||
player.weapon = player.pendingWeapon = Wolf.WEAPON_PISTOL;
|
||||
player.items = Wolf.ITEM_WEAPON_1 | Wolf.ITEM_WEAPON_2;
|
||||
player.nextExtra = Wolf.EXTRAPOINTS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description Try to move player
|
||||
* @private
|
||||
* @param {object} player The player object.
|
||||
* @param {object} level The level object.
|
||||
* @returns {boolean} Returns true if move was ok
|
||||
*/
|
||||
function tryMove(player, level) {
|
||||
var xl, yl, xh, yh, x, y,
|
||||
d, n;
|
||||
|
||||
xl = Wolf.POS2TILE(player.position.x - Wolf.PLAYERSIZE );
|
||||
yl = Wolf.POS2TILE(player.position.y - Wolf.PLAYERSIZE );
|
||||
xh = Wolf.POS2TILE(player.position.x + Wolf.PLAYERSIZE );
|
||||
yh = Wolf.POS2TILE(player.position.y + Wolf.PLAYERSIZE );
|
||||
|
||||
// Cheching for solid walls:
|
||||
for (y = yl; y <= yh; ++y) {
|
||||
for (x = xl; x <= xh; ++x) {
|
||||
if (level.tileMap[x][y] & Wolf.SOLID_TILE) {
|
||||
return false;
|
||||
}
|
||||
if (level.tileMap[x][y] & Wolf.DOOR_TILE && Wolf.Doors.opened(level.state.doorMap[x][y]) != Wolf.DOOR_FULLOPEN) {
|
||||
// iphone hack to allow player to move halfway into door tiles
|
||||
// if the player bounds doesn't cross the middle of the tile, let the move continue
|
||||
if (Math.abs(player.position.x - Wolf.TILE2POS(x)) <= 0x9000 && Math.abs(player.position.y - Wolf.TILE2POS(y)) <= 0x9000) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for actors
|
||||
for (n = 0; n < level.state.numGuards; ++n) {
|
||||
if (level.state.guards[n].state >= Wolf.st_die1) {
|
||||
continue;
|
||||
}
|
||||
if (!(level.state.guards[n].flags & Wolf.FL_SHOOTABLE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
d = player.position.x - level.state.guards[n].x;
|
||||
if (d < -Wolf.MINACTORDIST || d > Wolf.MINACTORDIST) {
|
||||
continue;
|
||||
}
|
||||
|
||||
d = player.position.y - level.state.guards[n].y;
|
||||
if (d < -Wolf.MINACTORDIST || d > Wolf.MINACTORDIST) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Clips movement
|
||||
* @private
|
||||
* @param {object} self The player object.
|
||||
* @param {number} xmove Movement in x direction
|
||||
* @param {number} ymove Movement in y direction
|
||||
* @param {object} level The level object.
|
||||
*/
|
||||
function clipMove(self, xmove, ymove, level) {
|
||||
var basex, basey;
|
||||
|
||||
basex = self.position.x;
|
||||
basey = self.position.y;
|
||||
|
||||
self.position.x += xmove;
|
||||
self.position.y += ymove;
|
||||
if (tryMove(self, level)) {
|
||||
return; // we moved as we wanted
|
||||
}
|
||||
|
||||
if (xmove) { // don't bother if we don't move x!
|
||||
self.position.x = basex + xmove;
|
||||
self.position.y = basey;
|
||||
if (tryMove(self, level)) {
|
||||
return; // May be we'll move only X direction?
|
||||
}
|
||||
}
|
||||
if (ymove) { // don't bother if we don't move y!
|
||||
self.position.x = basex;
|
||||
self.position.y = basey + ymove;
|
||||
if (tryMove(self, level)) {
|
||||
return; // May be we'll move only Y direction?
|
||||
}
|
||||
}
|
||||
|
||||
// movement blocked; we must stay on one place... :(
|
||||
self.position.x = basex;
|
||||
self.position.y = basey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description Changes player's angle and position
|
||||
* @memberOf Wolf.Player
|
||||
* @param {object} game The game object.
|
||||
* @param {object} self The player object.
|
||||
* @param {object} level The level object.
|
||||
* @param {object} tics Number of tics.
|
||||
*/
|
||||
function controlMovement(game, self, level, tics) {
|
||||
var angle, speed;
|
||||
|
||||
// rotation
|
||||
angle = self.angle;
|
||||
|
||||
self.mov.x = self.mov.y = 0; // clear accumulated movement
|
||||
|
||||
if (self.cmd.forwardMove ) {
|
||||
speed = tics * self.cmd.forwardMove;
|
||||
self.mov.x += (speed * Wolf.Math.CosTable[angle])>>0;
|
||||
self.mov.y += (speed * Wolf.Math.SinTable[angle])>>0;
|
||||
}
|
||||
if (self.cmd.sideMove) {
|
||||
speed = tics * self.cmd.sideMove;
|
||||
self.mov.x += (speed * Wolf.Math.SinTable[angle])>>0;
|
||||
self.mov.y -= (speed * Wolf.Math.CosTable[angle])>>0;
|
||||
}
|
||||
|
||||
if (!self.mov.x && !self.mov.y) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.speed = self.mov.x + self.mov.y;
|
||||
|
||||
// bound movement
|
||||
if (self.mov.x > Wolf.MAXMOVE) {
|
||||
self.mov.x = Wolf.MAXMOVE;
|
||||
} else if (self.mov.x < -Wolf.MAXMOVE) {
|
||||
self.mov.x = -Wolf.MAXMOVE;
|
||||
}
|
||||
|
||||
if (self.mov.y > Wolf.MAXMOVE) {
|
||||
self.mov.y = Wolf.MAXMOVE;
|
||||
} else if (self.mov.y < -Wolf.MAXMOVE) {
|
||||
self.mov.y = -Wolf.MAXMOVE;
|
||||
}
|
||||
|
||||
// move player and clip movement to walls (check for no-clip mode here)
|
||||
clipMove(self, self.mov.x, self.mov.y, level);
|
||||
self.tile.x = Wolf.POS2TILE(self.position.x);
|
||||
self.tile.y = Wolf.POS2TILE(self.position.y);
|
||||
|
||||
// Powerup_PickUp( self.tilex, self.tiley );
|
||||
|
||||
// pick up items easier -- any tile you touch, instead of
|
||||
// just the midpoint tile
|
||||
var x, y, tileX, tileY;
|
||||
for (x = -1 ;x <= 1; x+= 2) {
|
||||
tilex = Wolf.POS2TILE(self.position.x + x * Wolf.PLAYERSIZE);
|
||||
for (y = -1; y <= 1; y+= 2) {
|
||||
tiley = Wolf.POS2TILE(self.position.y + y * Wolf.PLAYERSIZE);
|
||||
Wolf.Powerups.pickUp(level, self, tilex, tiley);
|
||||
}
|
||||
}
|
||||
|
||||
// Checking for area change, ambush tiles and doors will have negative values
|
||||
if (level.areas[self.tile.x][self.tile.y] >= 0 && level.areas[self.tile.x][self.tile.y] != self.areanumber) {
|
||||
self.areanumber = level.areas[self.tile.x][self.tile.y];
|
||||
// assert( self.areanumber >= 0 && self.areanumber < Wolf.NUMAREAS );
|
||||
Wolf.Areas.connect(level, self.areanumber);
|
||||
}
|
||||
|
||||
if (level.tileMap[self.tile.x][self.tile.y] & Wolf.EXIT_TILE) {
|
||||
//Wolf.Game.startIntermission(0);
|
||||
Wolf.Game.victory(game);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description Called if player pressed USE button
|
||||
* @private
|
||||
* @param {object} self The player object.
|
||||
* @param {object} level The level object.
|
||||
* @returns {boolean} True if the player used something.
|
||||
*/
|
||||
function use(self, game) {
|
||||
var x, y, dir, newtex,
|
||||
level = game.level;
|
||||
|
||||
dir = Wolf.Math.get4dir(Wolf.FINE2RAD(self.angle));
|
||||
x = self.tile.x + Wolf.Math.dx4dir[dir];
|
||||
y = self.tile.y + Wolf.Math.dy4dir[dir];
|
||||
|
||||
if (level.tileMap[x][y] & Wolf.DOOR_TILE) {
|
||||
return Wolf.Doors.tryUse(level, self, level.state.doorMap[x][y]);
|
||||
}
|
||||
|
||||
if (level.tileMap[x][y] & Wolf.SECRET_TILE) {
|
||||
return Wolf.PushWall.push(level, x, y, dir);
|
||||
}
|
||||
|
||||
if (level.tileMap[x][y] & Wolf.ELEVATOR_TILE) {
|
||||
switch (dir) {
|
||||
case Wolf.Math.dir4_east:
|
||||
case Wolf.Math.dir4_west:
|
||||
newtex = level.wallTexX[x][y] += 2;
|
||||
break;
|
||||
case Wolf.Math.dir4_north:
|
||||
case Wolf.Math.dir4_south:
|
||||
return false; // don't allow to press elevator rails
|
||||
}
|
||||
|
||||
if (level.tileMap[self.tile.x][self.tile.y] & Wolf.SECRETLEVEL_TILE) {
|
||||
self.playstate = Wolf.ex_secretlevel;
|
||||
} else {
|
||||
self.playstate = Wolf.ex_complete;
|
||||
}
|
||||
Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_BODY, "lsfx/040.wav", 1, Wolf.ATTN_NORM, 0 );
|
||||
|
||||
Wolf.Game.startIntermission(game);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Attack
|
||||
* @memberOf Wolf.Player
|
||||
* @param {object} game The game object.
|
||||
* @param {object} player The player object.
|
||||
* @param {boolean} reAttack True if re-attack
|
||||
* @param {number} tics The number of tics
|
||||
*/
|
||||
function attack(game, player, reAttack, tics) {
|
||||
var cur,
|
||||
level = game.level;
|
||||
|
||||
player.attackCount -= tics;
|
||||
while (player.attackCount <= 0) {
|
||||
cur = attackinfo[player.weapon][player.attackFrame];
|
||||
switch (cur.attack) {
|
||||
case -1:
|
||||
player.flags &= ~Wolf.PL_FLAG_ATTCK;
|
||||
if (!player.ammo[Wolf.AMMO_BULLETS]) {
|
||||
player.weapon = Wolf.WEAPON_KNIFE;
|
||||
} else if (player.weapon != player.pendingWeapon) {
|
||||
player.weapon = player.pendingWeapon;
|
||||
}
|
||||
player.attackFrame = player.weaponFrame = 0;
|
||||
return;
|
||||
case 4:
|
||||
if (!player.ammo[Wolf.AMMO_BULLETS]) {
|
||||
break;
|
||||
}
|
||||
if (reAttack) {
|
||||
player.attackFrame -= 2;
|
||||
}
|
||||
case 1:
|
||||
if (!player.ammo[Wolf.AMMO_BULLETS]) { // can only happen with chain gun
|
||||
player.attackFrame++;
|
||||
break;
|
||||
}
|
||||
Wolf.Weapon.fireLead(game, player);
|
||||
player.ammo[Wolf.AMMO_BULLETS]--;
|
||||
break;
|
||||
case 2:
|
||||
Wolf.Weapon.fireHit(game, player);
|
||||
break;
|
||||
case 3:
|
||||
if (player.ammo[Wolf.AMMO_BULLETS] && reAttack) {
|
||||
player.attackFrame -= 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
player.attackCount += cur.tics;
|
||||
player.attackFrame++;
|
||||
player.weaponFrame = attackinfo[player.weapon][player.attackFrame].frame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Award points to the player
|
||||
* @memberOf Wolf.Player
|
||||
* @param {object} player The player object.
|
||||
* @param {number} points The number of points.
|
||||
*/
|
||||
function givePoints(player, points) {
|
||||
player.score += points;
|
||||
while (player.score >= player.nextExtra) {
|
||||
player.nextExtra += Wolf.EXTRAPOINTS;
|
||||
giveLife(player);
|
||||
Wolf.log("Extra life!");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Returns: returns true if player needs this health.
|
||||
|
||||
Notes:
|
||||
gives player some HP
|
||||
max can be:
|
||||
0 - natural player's health limit (100 or 150 with augment)
|
||||
>0 - indicates the limit
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
function giveHealth(player, points, max) {
|
||||
if (max == 0) {
|
||||
max = (player.items & Wolf.ITEM_AUGMENT) ? 150 : 100;
|
||||
}
|
||||
|
||||
if (player.health >= max) {
|
||||
return false; // doesn't need this health
|
||||
}
|
||||
|
||||
player.health += points;
|
||||
|
||||
if (player.health > max) {
|
||||
player.health = max;
|
||||
}
|
||||
|
||||
player.faceGotGun = false;
|
||||
|
||||
return true; // took it
|
||||
}
|
||||
|
||||
function giveLife(player) {
|
||||
if (player.lives < 9) {
|
||||
player.lives++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function giveKey(player, key) {
|
||||
player.items |= Wolf.ITEM_KEY_1 << key;
|
||||
}
|
||||
|
||||
|
||||
function giveWeapon(player, weapon) {
|
||||
var itemflag;
|
||||
|
||||
giveAmmo(player, Wolf.AMMO_BULLETS, 6); // give some ammo with a weapon
|
||||
|
||||
itemflag = Wolf.ITEM_WEAPON_1 << weapon;
|
||||
if (player.items & itemflag) {
|
||||
return; // player owns this weapon
|
||||
} else {
|
||||
player.items |= itemflag;
|
||||
|
||||
// don't switch if already using better weapon
|
||||
if (player.weapon < weapon ) {
|
||||
player.weapon = player.pendingWeapon = weapon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function giveAmmo(player, type, ammo) {
|
||||
var maxAmmo = 99;
|
||||
|
||||
if (player.items & Wolf.ITEM_BACKPACK) {
|
||||
maxAmmo *= 2;
|
||||
}
|
||||
|
||||
if (player.ammo[type] >= maxAmmo) {
|
||||
return false; // don't need
|
||||
}
|
||||
|
||||
if (!player.ammo[type] && !player.attackFrame) {
|
||||
// knife was out
|
||||
player.weapon = player.pendingWeapon;
|
||||
}
|
||||
|
||||
player.ammo[type] += ammo;
|
||||
if (player.ammo[type] > maxAmmo) {
|
||||
player.ammo[type] = maxAmmo;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description Award points to the player
|
||||
* @memberOf Wolf.Player
|
||||
* @param {object} player The player object.
|
||||
* @param {object} attacker The attacker actor object.
|
||||
* @param {number} points The number of damage points.
|
||||
* @param {number} skill The difficulty level.
|
||||
*/
|
||||
function damage(player, attacker, points, skill) {
|
||||
var dx, dy,
|
||||
angle, playerAngle, deltaAngle;
|
||||
|
||||
if (player.playstate == Wolf.ex_dead || player.playstate == Wolf.ex_complete || self.playstate == Wolf.ex_victory) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.lastAttacker = attacker;
|
||||
|
||||
if (skill == Wolf.gd_baby) {
|
||||
points >>= 2;
|
||||
}
|
||||
|
||||
// note the direction of the last hit for the directional blends
|
||||
dx = attacker.x - player.position.x;
|
||||
dy = attacker.y - player.position.y;
|
||||
|
||||
// probably won't ever have damage from self, but check anyway
|
||||
if (dx != 0 || dy != 0) {
|
||||
angle = Math.atan2(dy, dx);
|
||||
playerAngle = player.angle * 360.0 / Wolf.ANG_360;
|
||||
|
||||
angle = angle * 180.0 / Math.PI;
|
||||
|
||||
if (angle < 0) {
|
||||
angle = 360 + angle;
|
||||
}
|
||||
|
||||
deltaAngle = angle - playerAngle;
|
||||
|
||||
if (deltaAngle > 180) {
|
||||
deltaAngle = deltaAngle - 360;
|
||||
}
|
||||
if (deltaAngle < -180) {
|
||||
deltaAngle = 360 + deltaAngle;
|
||||
}
|
||||
if (deltaAngle > 40) {
|
||||
player.attackDirection[0] = 1;
|
||||
} else if (deltaAngle < -40) {
|
||||
player.attackDirection[1] = 1;
|
||||
}
|
||||
}
|
||||
// do everything else but subtract health in god mode, to ease
|
||||
// testing of damage feedback
|
||||
if (!(player.flags & Wolf.FL_GODMODE) ) {
|
||||
player.health -= points;
|
||||
}
|
||||
|
||||
if (player.health <= 0) {
|
||||
// dead
|
||||
Wolf.Game.notify("You have died");
|
||||
player.health = 0;
|
||||
player.playstate = Wolf.ex_dead;
|
||||
Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_BODY, "lsfx/009.wav", 1, Wolf.ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
// red screen flash
|
||||
Wolf.Game.startDamageFlash(points);
|
||||
|
||||
// stop the happy grin face if shot before it times out
|
||||
player.faceGotGun = false;
|
||||
|
||||
// make BJ's eyes bulge on huge hits
|
||||
if (points > 30 && player.health != 0) {
|
||||
player.faceOuch = true;
|
||||
player.faceCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function victorySpin(game, player, tics) {
|
||||
var desty;
|
||||
|
||||
if (player.angle > Wolf.ANG_270) {
|
||||
player.angle -= tics * Wolf.ANG_1 * 3;
|
||||
if (player.angle < Wolf.ANG_270) {
|
||||
player.angle = Wolf.ANG_270;
|
||||
}
|
||||
} else if (player.angle < Wolf.ANG_270) {
|
||||
player.angle += tics * Wolf.ANG_1 * 3;
|
||||
if (player.angle > Wolf.ANG_270) {
|
||||
player.angle = Wolf.ANG_270;
|
||||
}
|
||||
}
|
||||
|
||||
//desty = ((player.tile.y-5) << Wolf.TILESHIFT) - 0x3000;
|
||||
desty = Wolf.TILE2POS(player.tile.y+7)
|
||||
|
||||
if (player.position.y < desty) {
|
||||
player.position.y += tics * 3072;
|
||||
if (player.position.y > desty) {
|
||||
player.position.y = desty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Process player actions
|
||||
* @memberOf Wolf.Player
|
||||
* @param {object} self The player object.
|
||||
* @param {object} game The game object.
|
||||
* @param {number} tics Tics since last processing.
|
||||
*/
|
||||
function process(game, self, tics) {
|
||||
var level = game.level,
|
||||
n;
|
||||
|
||||
|
||||
if (self.playstate == Wolf.ex_victory) {
|
||||
victorySpin(game, self, tics);
|
||||
return;
|
||||
}
|
||||
|
||||
self.attackDirection = [0,0];
|
||||
self.madenoise = false;
|
||||
|
||||
controlMovement(game, self, level, tics);
|
||||
|
||||
if (self.flags & Wolf.PL_FLAG_ATTCK) {
|
||||
attack(game, self, self.cmd.buttons & Wolf.BUTTON_ATTACK, tics);
|
||||
} else {
|
||||
if (self.cmd.buttons & Wolf.BUTTON_USE) {
|
||||
if (!(self.flags & Wolf.PL_FLAG_REUSE) && use(self, game)) {
|
||||
self.flags |= Wolf.PL_FLAG_REUSE;
|
||||
}
|
||||
} else {
|
||||
self.flags &= ~Wolf.PL_FLAG_REUSE;
|
||||
}
|
||||
if (self.cmd.buttons & Wolf.BUTTON_ATTACK) {
|
||||
self.flags |= Wolf.PL_FLAG_ATTCK;
|
||||
|
||||
self.attackFrame = 0;
|
||||
self.attackCount = attackinfo[self.weapon][0].tics;
|
||||
self.weaponFrame = attackinfo[self.weapon][0].frame;
|
||||
}
|
||||
}
|
||||
|
||||
// process impulses
|
||||
switch (self.cmd.impulse) {
|
||||
case 0:
|
||||
break; // no impulse
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
changeWeapon(self, self.cmd.impulse - 1);
|
||||
break;
|
||||
|
||||
case 10: // next weapon /like in Quake/ FIXME: weapprev, weapnext
|
||||
self.pendingWeapon = self.weapon;
|
||||
for (n = 0; n < 4; ++n) {
|
||||
if (++self.weapon > Wolf.WEAPON_CHAIN) {
|
||||
self.weapon = Wolf.WEAPON_KNIFE;
|
||||
}
|
||||
if (changeWeapon(self, self.weapon)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.weapon = self.pendingWeapon;
|
||||
break;
|
||||
|
||||
default:
|
||||
Wolf.log("Unknown Impulse: ", + self.cmd.impulse);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
spawn : spawn,
|
||||
newGame : newGame,
|
||||
controlMovement : controlMovement,
|
||||
process : process,
|
||||
damage : damage,
|
||||
givePoints : givePoints,
|
||||
giveHealth : giveHealth,
|
||||
giveAmmo : giveAmmo,
|
||||
giveWeapon : giveWeapon,
|
||||
giveLife : giveLife,
|
||||
giveKey : giveKey
|
||||
};
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user