NXEngine v1.0.0.6
[NXEngine.git] / slope.cpp
blobb3d34d76ba3c4abbca7d61f96a8cd9bd225cff68
2 #include "nx.h"
3 #include "slope.fdh"
5 //#define DEBUG_SLOPE
6 static SlopeTable slopetable[SLOPE_LAST+1];
8 // creates the slope tables
9 bool initslopetable(void)
11 int x, y, ya, mx;
12 int curtable, opposing_table;
13 int inverttable, invertfliptable;
14 int flipmx, flipy;
16 stat("initslopetable: generating slopetables.");
17 memset(slopetable, 0, sizeof(slopetable));
19 ya = TILE_H-1;
20 for(x=0;x<TILE_W*2;x++)
22 if (x < TILE_W)
24 mx = x;
25 curtable = SLOPE_FWD1;
26 opposing_table = SLOPE_BACK2;
27 inverttable = SLOPE_CEIL_BACK1;
28 invertfliptable = SLOPE_CEIL_FWD2;
30 else
32 mx = x - TILE_W;
33 curtable = SLOPE_FWD2;
34 opposing_table = SLOPE_BACK1;
35 inverttable = SLOPE_CEIL_BACK2;
36 invertfliptable = SLOPE_CEIL_FWD1;
39 for(y=ya;y<TILE_H;y++)
41 flipmx = TILE_W-1-mx;
42 flipy = TILE_H-1-y;
44 slopetable[curtable].table[mx][y] = 1;
45 slopetable[opposing_table].table[flipmx][y] = 1;
46 slopetable[inverttable].table[mx][flipy] = 1;
47 slopetable[invertfliptable].table[flipmx][flipy] = 1;
50 if (x & 1) ya--;
53 return 0;
57 void c------------------------------() {}
60 // X and Y are non-CSFd pixel coordinates relative to the upper-left of the map.
61 // if the given pixel is inside of a slope, returns the slope type 1-8. else, returns 0.
62 uint8_t ReadSlopeTable(int x, int y)
64 int mx, my;
65 int slopetype;
66 uint8_t t;
68 #ifdef DEBUG_SLOPE
69 DrawSlopeTablesOnTiles();
70 #endif
72 // convert coordinates into a tile and check if the tile is a slope tile
73 mx = (x / TILE_W);
74 my = (y / TILE_H);
76 if (mx < 0 || my < 0 || mx >= map.xsize || my >= map.ysize)
77 return 0;
79 t = map.tiles[mx][my];
81 if (tileattr[t] & TA_SLOPE)
83 slopetype = (tilecode[t] & 0x07) + 1; // extract slope type from tile code
85 // get offset from the tile
86 x %= TILE_W; y %= TILE_H;
88 if (slopetable[slopetype].table[x][y])
89 return slopetype;
92 return 0;
95 // returns true if any of the points in the given point list
96 // are on the solid portion of a slope tile.
97 bool IsSlopeAtPointList(Object *o, SIFPointList *points)
99 int x, y, i;
101 for(i=0;i<points->count;i++)
103 x = (o->x >> CSF) + points->point[i].x;
104 y = (o->y >> CSF) + points->point[i].y;
105 if (ReadSlopeTable(x, y)) return 1;
108 return 0;
112 void c------------------------------() {}
115 // returns nonzero (the slope type) if the object is standing on a slope.
116 int CheckStandOnSlope(Object *o)
118 int x, y, st;
120 y = (o->y >> CSF) + sprites[o->sprite].slopebox.y2 + 1;
121 x = (o->x >> CSF);
123 if ((st = ReadSlopeTable(x + sprites[o->sprite].slopebox.x1, y))) return st;
124 if ((st = ReadSlopeTable(x + sprites[o->sprite].slopebox.x2, y))) return st;
126 return 0;
129 // returns nonzero (the slope type) if the objects blocku should be set
130 // because of a ceiling slope.
131 int CheckBoppedHeadOnSlope(Object *o)
133 int x, y, st;
135 y = (o->y >> CSF) + sprites[o->sprite].slopebox.y1 - 1;
136 x = (o->x >> CSF);
138 // without this, you get stuck in the save area below Gum Door in Grasstown
139 //if (o == player) y += 4;
141 if ((st = ReadSlopeTable(x + sprites[o->sprite].slopebox.x1, y))) return st;
142 if ((st = ReadSlopeTable(x + sprites[o->sprite].slopebox.x2, y))) return st;
144 return 0;
148 // move an object laterally, and have it climb slopes as it approaches them.
149 // We also have to move the object down as it goes down the slope.
150 // Otherwise, it would "skip" down the slope ungracefully.
151 // returns 1 if the object was blocked by a wall.
152 bool movehandleslope(Object *o, int xinertia)
154 int xoff, opposing_x;
155 int newx, newy, oldy;
156 char blocked_wall;
158 if (!xinertia) return 0;
160 // for objects which don't follow slope, just treat the slope as a blockl/r
161 if (!(o->nxflags & NXFLAG_FOLLOW_SLOPE))
163 if (xinertia > 0)
165 if (o->blockr) return 1;
167 else
169 if (o->blockl) return 1;
172 o->x += xinertia;
173 return 0;
176 newx = o->x;
177 newy = o->y;
179 // determine which side of the bounding box to use based on which way
180 // we're traveling
181 if (xinertia > 0)
182 { // moving right (right side of slopebox hits slopes first)
183 opposing_x = sprites[o->sprite].slopebox.x1;
184 xoff = sprites[o->sprite].slopebox.x2;
186 else
187 { // move left (left side of slopebox hits slopes first)
188 opposing_x = sprites[o->sprite].slopebox.x2;
189 xoff = sprites[o->sprite].slopebox.x1;
192 // check the opposing side at y+1 to see if we were standing on a slope before the move.
193 uint8_t old_floor_slope, old_ceil_slope;
194 old_floor_slope = ReadSlopeTable((newx>>CSF) + opposing_x, \
195 (newy>>CSF) + sprites[o->sprite].slopebox.y2 + 1);
197 old_ceil_slope = ReadSlopeTable((newx>>CSF) + opposing_x, \
198 (newy>>CSF) + sprites[o->sprite].slopebox.y1 - 1);
200 // move the object
201 newx += xinertia;
203 // check the opposing side again and if now we're not standing any more,
204 // we moved down the slope, so add +1 to the object's Y coordinate.
205 if (old_floor_slope && !ReadSlopeTable((newx>>CSF) + opposing_x, \
206 (newy>>CSF) + sprites[o->sprite].slopebox.y2 + 1))
208 bool walking_down = false;
210 // only trigger if it's the correct slope type so that we would be walking down it if
211 // we were going in the direction we're going. prevents being shoved down 1px when
212 // exiting the top of a slope.
213 if (xinertia < 0)
215 if (old_floor_slope == SLOPE_FWD1 || \
216 old_floor_slope == SLOPE_FWD2)
218 walking_down = true;
221 else if (xinertia > 0)
223 if (old_floor_slope == SLOPE_BACK1 || \
224 old_floor_slope == SLOPE_BACK2)
226 walking_down = true;
230 if (walking_down)
232 newy += (1<<CSF);
236 // the same for ceiling slopes
237 if (old_ceil_slope && !ReadSlopeTable((newx>>CSF) + opposing_x, \
238 (newy>>CSF) + sprites[o->sprite].slopebox.y1 - 1))
240 bool moveme = false;
242 if (xinertia < 0)
244 if (old_ceil_slope == SLOPE_CEIL_BACK1 || \
245 old_ceil_slope == SLOPE_CEIL_BACK2)
247 moveme = true;
250 else if (xinertia > 0)
252 if (old_ceil_slope == SLOPE_CEIL_FWD1 || \
253 old_ceil_slope == SLOPE_CEIL_FWD2)
255 moveme = true;
259 if (moveme)
260 { // moving down (actually up) the "descending" (closer to real ceil) portion
261 // of a ceiling slope tile. Reverse of floor slope thingy above.
262 newy -= (1<<CSF);
266 // check the coordinate and see if it's inside a slope tile.
267 // if so, move the object up 1 Y pixel.
268 uint8_t moved_into_ceil_slope = ReadSlopeTable((newx>>CSF) + xoff, \
269 (newy>>CSF) + sprites[o->sprite].slopebox.y1);
270 if (moved_into_ceil_slope)
272 newy += (1<<CSF);
275 uint8_t moved_into_floor_slope = ReadSlopeTable((newx>>CSF) + xoff, \
276 (newy>>CSF) + sprites[o->sprite].slopebox.y2);
277 if (moved_into_floor_slope)
279 newy -= (1<<CSF);
282 // can't move if blocked by a wall. but if we've moved up or down 1px, be sure and update
283 // the blockr/l state before declaring we can't move--otherwise we can get stuck at the
284 // top of a slope with the bottom blockr/l stuck at the top px of the adjacent solid tile.
285 oldy = o->y;
286 o->y = newy;
288 if (xinertia > 0)
290 if (oldy != newy)
291 o->UpdateBlockStates(RIGHTMASK);
293 blocked_wall = o->blockr;
295 else
297 if (oldy != newy)
298 o->UpdateBlockStates(LEFTMASK);
300 blocked_wall = o->blockl;
303 if (blocked_wall)
304 { // we can't actually move...so reset Y position
305 o->y = oldy;
307 else
308 { // can move...complete the move by setting the X position too
309 o->x = newx;
312 return blocked_wall;
317 void c------------------------------() {}
320 #ifdef DEBUG_SLOPE
321 // debug crap
323 void DrawSlopeTablesOnTiles()
325 static int lastmap = -1;
327 if (game.curmap != lastmap)
329 lastmap = game.curmap;
330 for(int i=0;i<256;i++)
332 if (tileattr[i] & TA_SLOPE)
334 DrawSlopeTableOnTile((tilecode[i]&7)+1, i);
340 void DrawSlopeTableOnTile(int table, int tile)
342 SDL_Rect dstrect;
343 int x, y;
344 extern SDL_Surface *tileset;
346 for(y=0;y<TILE_H;y++)
348 for(x=0;x<TILE_W;x++)
350 dstrect.x = (tile & 15) << 5;
351 dstrect.y = (tile >> 4) << 5;
352 dstrect.w = 2;
353 dstrect.h = 2;
355 dstrect.x += x*2;
356 dstrect.y += y*2;
358 if (slopetable[table].table[x][y])
360 if (table > 4) // floor slopes
361 SDL_FillRect(tileset, &dstrect, SDL_MapRGB(tileset->format, 0, 255, 0));
362 else
363 SDL_FillRect(tileset, &dstrect, SDL_MapRGB(tileset->format, 255, 0, 0));
369 void dumpslopetable(int t)
371 int x, y;
372 char buffer[80];
374 stat("\nDumping slope table %d:", t);
375 for(y=0;y<TILE_H;y++)
377 for(x=0;x<TILE_W;x++)
379 buffer[x] = slopetable[t].table[x][y] + '0';
381 buffer[x] = 0;
382 stat("%s", buffer);
385 #endif