1 /* DooM2D: Midnight on the Firing Line
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 import apiActor, apiMap, stdlib;
21 import apiPlayer, apiMonster;
27 // ////////////////////////////////////////////////////////////////////////// //
28 /// check area, half of height
29 public int Z_checkerRHHalf (int x, int y, int r, int h, int function (int tiletype) ccb) {
31 int sx = max((x-r)/TileSize, 0);
32 int sy = max((y-h+1)/TileSize, 0);
34 x = min((x+r)/TileSize, MapWidth-1);
35 y = min((y-h/2)/TileSize, MapHeight-1);
36 if (sx > x || sy > y) return -1; // counts as true anyway
38 for (int j = sy; j <= y; ++j) {
39 int res = ccb(mapGetTypeTile(sx, j));
48 public int Z_checkerRHHalfEx (int x, int y, int r, int h, int function (int tilefg, int tiletype) ccb) {
50 int sx = max((x-r)/TileSize, 0);
51 int sy = max((y-h+1)/TileSize, 0);
53 x = min((x+r)/TileSize, MapWidth-1);
54 y = min((y-h/2)/TileSize, MapHeight-1);
55 if (sx > x || sy > y) return -1; // counts as true anyway
57 for (int j = sy; j <= y; ++j) {
58 int res = ccb(mapGetTile(LAYER_FRONT, sx, j), mapGetTypeTile(sx, j));
67 // check "under feet" / "above head"
68 public int Z_checkerRHFeetHead (int x, int y, int r, int h, int function (int tiletype) ccb) {
70 int i = max((x-r)/TileSize, 0);
71 x = min((x+r)/TileSize, MapWidth-1);
73 //if (origx >= 160 && origx <= 168 && h > 2) { writeln("Z_checkerRHFeetHead: i=", i, "; x=", x, "; y=", y); }
74 if (y >= MapHeight || y < 0) return 0;
76 //if (origx >= 160 && origx <= 168 && h > 2) { writeln(" i=", i, "; y=", y, "; tt=", mapGetTypeTile(i, y)); }
77 int res = ccb(mapGetTypeTile(i, y));
78 //writeln(" Z_checkerRHFeetHead(", i, ", ", y, ") = ", res);
85 // check the whole occupied area
86 public int Z_checkerRHWhole (int x, int y, int r, int h, int dy, int function (int tiletype) ccb) {
87 int sx = max((x-r)/TileSize, 0);
88 int sy = max((y-h+1)/TileSize, 0);
89 x = min((x+r)/TileSize, MapWidth-1);
90 y = min((y+dy)/TileSize, MapHeight-1);
91 if (sx > x || sy > y) return -1; // counts as true anyway
92 for (int i = sx; i <= x; ++i) {
93 for (int j = sy; j <= y; ++j) {
94 int res = ccb(mapGetTypeTile(i, j));
95 //writeln(" Z_checkerRHWhole(", i, ", ", j, ") = ", res);
103 // ////////////////////////////////////////////////////////////////////////// //
104 int Z_canbreatheCCB (int fv) {
116 public int Z_canbreathe (int x, int y, int r, int h) { return (Z_checkerRHHalf(x, y, r, h, &Z_canbreatheCCB) != 0); }
119 // ////////////////////////////////////////////////////////////////////////// //
120 int Z_canstandCCB (int fv) { return (fv == TILE_WALL || fv == TILE_DOORC || fv == TILE_STEP ? 1 : 0); }
122 public int Z_canstand (int x, int y, int r) { return Z_checkerRHFeetHead(x, y, r, 0, &Z_canstandCCB); }
125 // ////////////////////////////////////////////////////////////////////////// //
126 int Z_cangodownCCB (int fv) { return (fv == TILE_STEP ? 1 : 0); }
128 public int Z_cangodown (int x, int y, int r) { return Z_checkerRHFeetHead(x, y, r, 0, &Z_cangodownCCB); }
131 // ////////////////////////////////////////////////////////////////////////// //
132 int Z_hitceilCCB (int fv) {
133 return (getCheatNoDoors ? (fv == TILE_WALL ? 1 : 0) : (fv == TILE_WALL || fv == TILE_DOORC ? 1 : 0));
136 public int Z_hitceil (int x, int y, int r, int h) {
137 //if (x >= 160 && x <= 168) writeln("=== hitceil: x=", x, "; y=", y, "; r=", r, "; h=", h);
138 return Z_checkerRHFeetHead(x, y, r, h+1, &Z_hitceilCCB); // `+1` due to checker specific
142 // ////////////////////////////////////////////////////////////////////////// //
143 int Z_canfitCCB (int fv) { return (fv == TILE_WALL || fv == TILE_DOORC ? 1 : 0); }
145 public int Z_canfit (int x, int y, int r, int h) { return 1-Z_checkerRHWhole(x, y, r, h, 0, &Z_canfitCCB); }
148 // ////////////////////////////////////////////////////////////////////////// //
149 int Z_inliftCCB (int fv) {
150 if (fv == TILE_LIFTU || fv == TILE_LIFTD) return fv-TILE_LIFTU+1;
154 public int Z_inlift (int x, int y, int r, int h) { return Z_checkerRHWhole(x, y, r, h, -1, &Z_inliftCCB); }
157 // ////////////////////////////////////////////////////////////////////////// //
158 int Z_isblockedCCB (int fv) { return (fv == TILE_MBLOCK ? 1 : 0); }
160 public int Z_isblocked (int x, int y, int r, int h, int xv) { return Z_checkerRHWhole(x, y, r, h, -1, &Z_isblockedCCB); }
163 // ////////////////////////////////////////////////////////////////////////// //
164 int Z_istrappedCCB (int fv) { return (fv == TILE_ACTTRAP ? 1 : 0); }
166 public int Z_istrapped (int x, int y, int r, int h) { return Z_checkerRHWhole(x, y, r, h, -1, &Z_istrappedCCB); }
169 // ////////////////////////////////////////////////////////////////////////// //
170 //static uint8_t wfront; // for splash
171 int Z_inwaterCCB (int fv) {
172 //return (fv >= TILE_WATER && fv <= TILE_ACID2 ? 1 : 0); /* wfront = fv;*/
174 case TILE_WATER: return Z_WATER_0;
175 case TILE_ACID1: return Z_WATER_1;
176 case TILE_ACID2: return Z_WATER_2;
182 public int Z_inwater (int x, int y, int r, int h/*, ref int wfront*/) { return Z_checkerRHHalf(x, y, r, h, &Z_inwaterCCB); }
185 int Z_inwaterCCBEx (int fg, int fv) {
186 //return (fv >= TILE_WATER && fv <= TILE_ACID2 ? 1 : 0); /* wfront = fv;*/
189 case TILE_WATER: res = Z_WATER_0; break;
190 case TILE_ACID1: res = Z_WATER_1; break;
191 case TILE_ACID2: res = Z_WATER_2; break;
195 int wt = mapGetWaterTexture(fg);
197 case 1: res |= Z_WATER_T0; break;
198 case 2: res |= Z_WATER_T1; break;
199 case 3: res |= Z_WATER_T2; break;
206 public int Z_inwaterEx (int x, int y, int r, int h/*, ref int wfront*/) { return Z_checkerRHHalfEx(x, y, r, h, &Z_inwaterCCBEx); }
209 // ////////////////////////////////////////////////////////////////////////// //
210 int clamp7 (int v) { return (abs(v) <= 7 ? v : (v > 0 ? 7 : -7)); }
212 //int is_dot (Actor me) { return false; }
213 //int is_ghost_player (Actor me) { return false; }
216 public int Z_dec (int n, int delta) {
217 if (abs(n) > delta) {
218 if (n > 0) return n-delta;
219 if (n < 0) return n+delta;
224 //#define wvel(v) if ((xv = abs(v)+1) > 5) v = Z_dec(v, xv/2-2)
227 public int Z_moveobj (Actor me) {
228 if (me.dead) return 0;
239 auto cheatNWC = (me.isPlayer ? getCheatNoWallClip() : false);
240 auto cheatNCC = (me.isPlayer ? getCheatNoCeilClip() : false);
241 auto cheatNLC = (me.isPlayer ? getCheatNoLiftClip() : false);
244 switch (Z_inlift(x, y, r, h)) {
246 if (++me.yv > MAX_YV) --me.yv;
249 if (--me.yv < -5) ++me.yv;
252 if (me.yv > 5) --me.yv; else ++me.yv;
258 inw = Z_inwater(x, y, r, h);
259 //writeln("x=", x, "; y=", y, "; r=", r, "; h=", h, "; inw=", inw);
262 if ((xv = abs(me.xv)+1) > 5) me.xv = Z_dec(me.xv, xv/2-2);
263 if ((xv = abs(me.yv)+1) > 5) me.yv = Z_dec(me.yv, xv/2-2);
264 if ((xv = abs(me.vx)+1) > 5) me.vx = Z_dec(me.vx, xv/2-2);
265 if ((xv = abs(me.vy)+1) > 5) me.vy = Z_dec(me.vy, xv/2-2);
268 //writeln(" vx=", me.vx, "; vy=", me.vy);
269 me.vx = Z_dec(me.vx, 1);
270 me.vy = Z_dec(me.vy, 1);
271 //writeln(" vx=", me.vx, "; vy=", me.vy);
273 //writeln(" xv=", me.xv, "; yv=", me.yv);
277 //writeln(" xv=", xv, "; yv=", yv);
280 //writeln(" *xv=", xv, "; yv=", yv);
281 if (x < -100 || x >= MapWidth*TileSize+100 || y < -100 || y >= MapHeight*TileSize+100) {
286 //writeln(" x=", x, "; xv=", xv, "; c7(xv)=", clamp7(xv));
293 if (Z_isblocked(x, y, r, h, xv)) st |= Z_BLOCK;
296 if (!Z_canfit(/*is_dot(me),*/ x, y, r, h)) {
299 if (gm_climb_stairs && is_player(me)) {
300 // check if we can climb upstairs
301 if (yv == 1 && (xv == 1 || xv == -1)) {
302 if (Z_canfit(me.type, x, y-TileSize, r, h) && Z_canfit(me.type, x+Z_sign(xv)*(TileSize-1), y-TileSize, r, h)) {
304 return Z_moveobj(me);
310 else if (xv < 0) x = ((lx-r)&0xFFF8)+r;
311 else x = ((lx+r)&0xFFF8)-r+7;
312 xv = me.xv = me.vx = 0;
317 //writeln(" xv=", xv);
322 // moving up and hit the ceiling
324 if (yv < 0 && Z_hitceil(/*me.type,*/ x, y, r, h)) {
325 //writeln("hitceil: x=", x, "; y=", y);
326 y = ((ly-h+1)&0xFFF8)+h-1;
327 //writeln(" newy=", y);
332 if (yv > 0 && Z_canstand(/*me.type,*/ x, y, r)) {
333 y = ((y+1)&0xFFF8)-1;
334 yv = me.yv = me.vy = 0;
339 //writeln(" yv=", yv);
344 //writeln(" x=", x, "; y=", y);
346 int wtr = Z_inwaterEx(x, y, r, h);
349 if (!inw) st |= Z_HITWATER;
359 // ////////////////////////////////////////////////////////////////////////// //
360 public void Z_splash (Actor me, int n, int st) {
362 //Z_sound(bulsnd[0], 128);
363 //DOT_water(p->x, p->y-p->h/2, p->xv+p->vx, p->yv+p->vy, n, /*(int)walp[wfront]*/walp[wfront]->wanim-1);
364 //writeln("Z_splash: n=", n, "; wtx=", (st&(Z_WATER_0|Z_WATER_1|Z_WATER_2)));
366 if (st&Z_WATER_T0) wtt = 0;
367 else if (st&Z_WATER_T1) wtt = 1;
368 else if (st&Z_WATER_T2) wtt = 2;
370 //writeln("Z_splash: n=", n, "; wtt=", wtt);
371 dotAddWater(me.x, me.y-me.height/2, me.xv+me.vx, me.yv+me.vy, n, wtt);
375 // ////////////////////////////////////////////////////////////////////////// //
376 public void Z_simpleGravity (Actor me) {
378 if (me.flags&AF_NOGRAVITY) return;
379 auto st = Z_moveobj(me);
380 if (st&Z_FALLOUT) { me.actorMarkDead(); return; }
381 if (st&Z_HITWATER) Z_splash(me, me.radius+me.height, st);
385 // ////////////////////////////////////////////////////////////////////////// //
386 public void Z_teleobj (Actor me, int x, int y) {
389 //FX_tfog((p.x = x), (p.y = y));
390 //Z_sound(telesnd, 128);
393 me.flags |= AF_TELEPORT;
397 // ////////////////////////////////////////////////////////////////////////// //
398 public int Z_chktrap (int deadlyTrap, int damage, Actor owner, int hittype) {
401 //hit_xv = hit_yv = 0;
404 int pcount = getPlayerCount();
405 for (int pnum = 1; pnum <= pcount; ++pnum) {
406 act = getPlayerActor(pnum);
407 if (!act.isPlayer || act.isDead) continue; // this player is dead
408 if (Z_istrapped(act.x, act.y, act.radius, act.height)) {
410 if (!deadlyTrap) return true;
411 if (deadlyTrap) PL_hit(act, damage, owner, hittype);
417 while ((act = actorListNext())) {
418 if (!act.isMonster || act.isDead) continue;
419 /+if (/*act.t??? &&*/ act.animname != MNST_DEAD)+/ {
420 if (Z_istrapped(act.x, act.y, act.radius, act.height)) {
422 if (!deadlyTrap) return true;
423 if (deadlyTrap) MN_hit(act, damage, owner, hittype);