Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/typescript #25

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions src/Angle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
export const DEG2RAD = (a: number) => a * 0.01745329251994329576; // a * M_PI / 180.0f
export const RAD2DEG = (a: number) => a / 0.01745329251994329576; // a * 180.0f / M_PI
export const ANGLE2SHORT = (x: number) => ((x * 65536 / 360) >> 0) & 65535;
export const SHORT2ANGLE = (x: number) => x * 360.0 / 65536;

/**
* @description Finds the difference between two angles.
* @memberOf Wolf.Angle
* @param angle1 Angle in radians.
* @param angle2 Angle in radians.
* @returns The absolute difference between two angles, this will always be between 0 and 180 degrees.
*/
export const diff = (angle1: number, angle2: number) => {
var diff: number;

if (angle1 > angle2) {
diff = angle1 - angle2;
} else {
diff = angle2 - angle1;
}

if (diff > Math.PI) {
return 2 * Math.PI - diff;
} else {
return diff;
}
}

/**
* @description Clockwise distance between two angles.
* @memberOf Wolf.Angle
* @param angle1 Angle in radians.
* @param angle2 Angle in radians.
* @returns The clockwise distance from angle2 to angle1, this may be greater than 180 degrees.
*/
export const distCW = (angle1: number, angle2: number) => {
if (angle1 > angle2) {
return angle1 - angle2;
} else {
return angle1 + 2 * Math.PI - angle2;
}
}

/**
* @description Linear interpolate between angle from and to by fraction frac.
* @memberOf Wolf.Angle
* @param from Angle in radians.
* @param to Angle in radians.
* @param frac Fraction.
*/
export const interpolate = (from: number, to: number, frac: number) => {
var d = diff(from, to) * frac;

if (distCW(to, from) >= Math.PI) {
return from - d;
} else {
return from + d;
}
}

/**
* @description Normalize angle.
* @memberOf Wolf.Angle
* @param {number} angle
*/
export const normalize = (angle: number) => {
while (angle < 0) {
angle += (2 * Math.PI);
}
while (angle >= (2 * Math.PI)) {
angle -= (2 * Math.PI);
}
return angle;
}

/**
* @description Linear interpolate allowing for the Modulo 360 problem.
* @memberOf Wolf.Angle
* @param {number} from Angle in radians.
* @param {number} to Angle in radians.
* @param {number} frac fraction.
*/
export const lerp = (from: number, to: number, frac: number) => {
if (to - from > 180) {
to -= 360;
}
if (to - from < -180) {
to += 360;
}
return from + frac * (to - from);
}
106 changes: 106 additions & 0 deletions src/Areas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
let Wolf: any; // TODO (al) Remove in the future.

export const init = (
level: { state: { areaconnect: number[][]; areabyplayer: boolean[]; }; },
areanumber: string | number
) => {
level.state.areaconnect = [];
level.state.areabyplayer = [];
for (var i = 0; i < Wolf.NUMAREAS; i++) {
level.state.areaconnect[i] = [];
for (var j = 0; j < Wolf.NUMAREAS; j++) {
level.state.areaconnect[i][j] = 0;
}
level.state.areabyplayer[i] = false;
}
level.state.areabyplayer[areanumber] = true;
}


/**
* @private
* @description Scans outward from playerarea, marking all connected areas.
* @param {object} level The level object
* @param {number} areanumber Area
*/
export const recursiveConnect = (
level: { state: { areaconnect: number[][]; areabyplayer: boolean[]; }; },
areanumber: number
) => {
for (var i = 0; i < Wolf.NUMAREAS; ++i) {
if (level.state.areaconnect[areanumber][i] && !level.state.areabyplayer[i]) {
level.state.areabyplayer[i] = true;
recursiveConnect(level, i);
}
}
}

/**
* @description Connect area.
* @memberOf Wolf.Areas
* @param {object} level The level object
* @param {number} areanumber New area
*/
export const connect = (
level: { state: { areaconnect: number[][]; areabyplayer: boolean[]; }; },
areanumber: number
) => {
var i: number, c = 0;

if (areanumber >= Wolf.NUMAREAS) {
throw new Error("areanumber >= Wolf.NUMAREAS");
}

level.state.areabyplayer = [];
level.state.areabyplayer[areanumber] = true;

recursiveConnect(level, areanumber);
for (i = 0; i < Wolf.NUMAREAS; i++) {
if (level.state.areabyplayer[i]) {
c++;
}
}
}

/**
* @description Join ares
* @memberOf Wolf.Areas
* @param {object} level The level object
* @param {number} area1 Area 1
* @param {number} area2 Area 2
*/
export const join = (
level: { state: { areaconnect: number[][]; areabyplayer: boolean[]; }; },
area1: number, area2: number
) => {
if (area1 < 0 || area1 >= Wolf.NUMAREAS) {
throw new Error("area1 < 0 || area1 >= Wolf.NUMAREAS");
}
if (area2 < 0 || area2 >= Wolf.NUMAREAS) {
throw new Error("area2 < 0 || area2 >= Wolf.NUMAREAS");
}
level.state.areaconnect[area1][area2]++;
level.state.areaconnect[area2][area1]++;
}

/**
* @description Disconnect ares
* @memberOf Wolf.Areas
* @param {object} level The level object
* @param {number} area1 Area 1
* @param {number} area2 Area 2
*/
export const disconnect = (
level: { state: { areaconnect: number[][]; areabyplayer: boolean[]; }; },
area1: number,
area2: number
) => {
if (area1 < 0 || area1 >= Wolf.NUMAREAS) {
throw new Error("area1 < 0 || area1 >= Wolf.NUMAREAS");
}
if (area2 < 0 || area2 >= Wolf.NUMAREAS) {
throw new Error("area2 < 0 || area2 >= Wolf.NUMAREAS");
}
level.state.areaconnect[area1][area2]--;
level.state.areaconnect[area2][area1]--;
}
62 changes: 62 additions & 0 deletions src/Episodes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
export type Level = {
file: string;
partime: number;
secret?: boolean;
};

export type Episode = {
name: string;
enabled: boolean;
levels: Array<Level>;
};

export const Episodes: Array<Episode> = [
{
name: "Escape from Wolfenstein",
enabled: true,
levels: [
{ file: "maps/w00.map", partime: 1.5 },
{ file: "maps/w01.map", partime: 2.0 },
{ file: "maps/w02.map", partime: 2.0 },
{ file: "maps/w03.map", partime: 3.5 },
{ file: "maps/w04.map", partime: 3.0 },
{ file: "maps/w05.map", partime: 3.0 },
{ file: "maps/w06.map", partime: 2.5 },
{ file: "maps/w07.map", partime: 2.5 },
{ file: "maps/w08.map", partime: 0.0 },
{ file: "maps/w09.map", partime: 0.0, secret: true }
]
},
{
name: "Operation: Eisenfaust",
enabled: true,
levels: [
{ file: "maps/w10.map", partime: 1.5 },
{ file: "maps/w11.map", partime: 3.5 },
{ file: "maps/w12.map", partime: 3.0 },
{ file: "maps/w13.map", partime: 2.0 },
{ file: "maps/w14.map", partime: 4.0 },
{ file: "maps/w15.map", partime: 6.0 },
{ file: "maps/w16.map", partime: 1.0 },
{ file: "maps/w17.map", partime: 3.0 },
{ file: "maps/w18.map", partime: 0.0 },
{ file: "maps/w19.map", partime: 0.0, secret: true }
]
},
{
name: "Die, Fuhrer, Die!",
enabled: true,
levels: [
{ file: "maps/w20.map", partime: 1.5 },
{ file: "maps/w21.map", partime: 1.5 },
{ file: "maps/w22.map", partime: 2.5 },
{ file: "maps/w23.map", partime: 2.5 },
{ file: "maps/w24.map", partime: 3.5 },
{ file: "maps/w25.map", partime: 2.5 },
{ file: "maps/w26.map", partime: 2.0 },
{ file: "maps/w27.map", partime: 6.0 },
{ file: "maps/w28.map", partime: 0.0 },
{ file: "maps/w29.map", partime: 0.0, secret: true }
]
}
];
108 changes: 108 additions & 0 deletions src/Pushwall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
export type PushWall = {
active: boolean;
tilesMoved: number;
pointsMoved: number;
dir: number;
x: number;
y: number;
dx: number;
dy: number;
texX: number;
texY: number;
}

let PWall: PushWall;
let Wolf: any; // TODO (al) Remove in the future.

export const push = (
level: { tileMap: { [x: string]: { [x: string]: number; }; }; state: { foundSecrets: number; totalSecrets: number; }; wallTexX: { [x: string]: { [x: string]: number; }; }; wallTexY: { [x: string]: { [x: string]: number; }; }; },
x: number,
y: number,
dir: number
) => {
var dx: number, dy: number;

if (PWall.active) {
return false; // another PWall is moving [only one at a time!]
}

dx = Wolf.Math.dx4dir[dir];
dy = Wolf.Math.dy4dir[dir];

if (level.tileMap[x + dx][y + dy] & (Wolf.SOLID_TILE | Wolf.DOOR_TILE)) {
// noway (smth is blocking)
return true;
}

// remove secret flag & make everything needed when pushwall used!
level.tileMap[x][y] &= (~Wolf.SECRET_TILE);
level.tileMap[x][y] &= (~Wolf.WALL_TILE);
level.tileMap[x][y] |= Wolf.PUSHWALL_TILE;

if (++level.state.foundSecrets == level.state.totalSecrets) {
Wolf.Game.notify("You found the last secret!");
} else {
Wolf.Game.notify("You found a secret!");
}

Wolf.Sound.startSound(null, null, 1, Wolf.CHAN_AUTO, "sfx/034.wav", 1, Wolf.ATTN_STATIC, 0);

// good way to avoid stuckness; [un]comment one more down!
// it makes a tile behind pushwall unpassable
level.tileMap[x + dx][y + dy] |= Wolf.PUSHWALL_TILE;
level.wallTexX[x + dx][y + dy] = level.wallTexX[x][y];
level.wallTexY[x + dx][y + dy] = level.wallTexY[x][y];

// write down PWall info
PWall.active = true;
PWall.tilesMoved = PWall.pointsMoved = 0;
PWall.dir = dir;
PWall.x = x;
PWall.y = y;
PWall.dx = dx;
PWall.dy = dy;
PWall.texX = level.wallTexX[x][y];
PWall.texY = level.wallTexY[x][y];

return true;
}

export const process = (
level: { tileMap: number[][]; wallTexX: number[][]; wallTexY: number[][]; },
tics: number
) => {
if (!PWall.active) {
return; // no active PWall to work with
}

PWall.pointsMoved += tics;

if (PWall.pointsMoved < 128) {
return;
}

PWall.pointsMoved -= 128;
PWall.tilesMoved++;
// Free tile
level.tileMap[PWall.x][PWall.y] &= (~Wolf.PUSHWALL_TILE);
// Occupy new tile
PWall.x += PWall.dx;
PWall.y += PWall.dy;

// Shall we move further?
if (level.tileMap[PWall.x + PWall.dx][PWall.y + PWall.dy] & (Wolf.SOLID_TILE | Wolf.DOOR_TILE | Wolf.ACTOR_TILE | Wolf.POWERUP_TILE) || PWall.tilesMoved == 3) {
level.tileMap[PWall.x][PWall.y] &= (~Wolf.PUSHWALL_TILE); // wall now
level.tileMap[PWall.x][PWall.y] |= Wolf.WALL_TILE; // wall now
level.wallTexX[PWall.x][PWall.y] = PWall.texX;
level.wallTexY[PWall.x][PWall.y] = PWall.texY;
PWall.active = false; // Free Push Wall
} else {
level.tileMap[PWall.x + PWall.dx][PWall.y + PWall.dy] |= Wolf.PUSHWALL_TILE;

// Not sure if this is right but it fixed an issue with the pushwall texture changing mid-slide.
level.wallTexX[PWall.x + PWall.dx][PWall.y + PWall.dy] = PWall.texX;
level.wallTexY[PWall.x + PWall.dx][PWall.y + PWall.dy] = PWall.texY;
}
}

export const get = () => PWall;
Loading