Alchemy
Loading...
Searching...
No Matches

terrain.c

Go to the documentation of this file.
1/// @file
2/// Terrain: ground heights and the collision of cells and the world map.
3/// Part of field.c, the field object, compiled only through it.
4
5#include "../field_internal.h"
6
7// A sample is in eight-pixel units. UB: signed samples may be negative, so
8// their left shift is undefined. Multiplication fits s32 for both s8 and u8.
9#ifdef UBFIX
10#define CURVE_HEIGHT_FIXED(sample) ((sample) * (1 << CURVE_VALUE_SHIFT))
11#else
12#define CURVE_HEIGHT_FIXED(sample) ((sample) << CURVE_VALUE_SHIFT)
13#endif
14
15/// The terrain height functions (gMap_TerrainHeightFunctions): each takes a
16/// cell's height samples after its kind byte and a pixel (x, y) within the
17/// 16x16 cell, and returns the ground height there in 16.16 pixels. This one
18/// is flat: the first sample everywhere.
19/// Each is reached only through that table, by the low four bits of the
20/// cell's kind byte: this one is kind 0, and the rest follow in order.
21s32 Curve_GetFirstSampleA(const u8 *heightBytes, s32 pixelX, s32 pixelY) {
22 const s8 *samples = (const s8 *)heightBytes;
23 return CURVE_HEIGHT_FIXED(samples[0]);
24}
25
26/// A slope along x: from sample 0 at x = 0 towards sample 1 at x = 16.
27/// Kind 1.
28s32 Curve_LerpTwoSamples(const u8 *heightBytes, s32 pixelX, s32 pixelY) {
29 const s8 *samples = (const s8 *)heightBytes;
30 s32 startHeight;
31 s32 heightDelta;
32
33 startHeight = CURVE_HEIGHT_FIXED(samples[0]);
34 heightDelta = (CURVE_HEIGHT_FIXED(samples[1]) - startHeight) * pixelX;
35 // Round towards zero, as dividing by 16 would.
36 if (heightDelta < 0) {
37 heightDelta += CURVE_FULL_STEPS - 1;
38 }
39 return startHeight + (heightDelta >> 4);
40}
41
42/// A slope along y: from sample 0 at y = 0 towards sample 1 at y = 16.
43/// Kind 2.
44s32 Curve_LerpTwoSamplesB(const u8 *heightBytes, s32 pixelX, s32 pixelY) {
45 const s8 *samples = (const s8 *)heightBytes;
46 s32 startHeight;
47 s32 heightDelta;
48
49 startHeight = CURVE_HEIGHT_FIXED(samples[0]);
50 heightDelta = (CURVE_HEIGHT_FIXED(samples[1]) - startHeight) * pixelY;
51 // Round towards zero, as dividing by 16 would.
52 if (heightDelta < 0) {
53 heightDelta += CURVE_FULL_STEPS - 1;
54 }
55 return startHeight + (heightDelta >> 4);
56}
57
58/// A step across the diagonal x + y = 15: sample 0 before it, sample 1 after
59/// it and the higher of the two on it.
60/// Kind 3.
61s32 Curve_StepAtSummedPosition(const u8 *heightBytes, s32 x, s32 y) {
62 const s8 *samples = (const s8 *)heightBytes;
63 s32 firstHeight;
64 s32 secondHeight;
65 s32 higherHeight;
66 u32 summedPixel;
67
68 firstHeight = CURVE_HEIGHT_FIXED(samples[0]);
69 secondHeight = CURVE_HEIGHT_FIXED(samples[1]);
70 higherHeight = firstHeight;
71 if (secondHeight > firstHeight) {
72 higherHeight = secondHeight;
73 }
74 // x + y runs from 0 to 30; 15 is the diagonal.
75 summedPixel = x + y;
76 if (summedPixel == CURVE_FULL_STEPS - 1) {
77 return higherHeight;
78 }
79 if (summedPixel < CURVE_FULL_STEPS - 1) {
80 secondHeight = firstHeight;
81 }
82 return secondHeight;
83}
84
85/// A step across the diagonal x = y: sample 0 where y < x, sample 1 where
86/// y > x and the higher of the two on it.
87/// Kind 4.
88s32 Curve_StepAtDifferencePosition(const u8 *heightBytes, s32 x, s32 y) {
89 const s8 *samples = (const s8 *)heightBytes;
90 s32 firstHeight;
91 s32 secondHeight;
92 s32 higherHeight;
93 s32 pixelDifference;
94 u32 biasedDifference = x;
95
96 firstHeight = CURVE_HEIGHT_FIXED(samples[0]);
97 secondHeight = CURVE_HEIGHT_FIXED(samples[1]);
98 higherHeight = firstHeight;
99 if (secondHeight > firstHeight) {
100 higherHeight = secondHeight;
101 }
102 // y - x biased by 15 runs from 0 to 30, so the diagonal is 15 and one
103 // unsigned compare tells the sides apart, as in kind 3.
104 pixelDifference = y - biasedDifference;
105 biasedDifference = pixelDifference + CURVE_FULL_STEPS - 1;
106 if (biasedDifference == CURVE_FULL_STEPS - 1) {
107 return higherHeight;
108 }
109 if (biasedDifference < CURVE_FULL_STEPS - 1) {
110 secondHeight = firstHeight;
111 }
112 return secondHeight;
113}
114
115/// A slope that bends on the diagonal x + y = 15: from sample 0 at the top
116/// left corner to sample 1 on the diagonal to sample 2 at the bottom right.
117/// Kind 5.
118s32 Curve_LerpThreeSamplesByRatio(const u8 *heightBytes, s32 x, s32 y) {
119 const s8 *samples = (const s8 *)heightBytes;
120 s32 firstHeight;
121 s32 middleHeight;
122 s32 lastHeight;
123 s32 height;
124
125 firstHeight = CURVE_HEIGHT_FIXED(*samples++);
126 middleHeight = CURVE_HEIGHT_FIXED(*samples);
127 lastHeight = CURVE_HEIGHT_FIXED(samples[1]);
128 // x + y from 0 to 30: 15 is the diagonal, below it the first half and
129 // above it the second. Each half divides by 15, so it reaches its end
130 // sample.
131 x += y;
132 if (x == CURVE_FULL_STEPS - 1) {
133 height = middleHeight;
134 } else if ((u32)x < CURVE_FULL_STEPS - 1) {
135 height =
136 firstHeight + (middleHeight - firstHeight) * x / (CURVE_FULL_STEPS - 1);
137 } else {
138 x -= (CURVE_FULL_STEPS - 1);
139 height =
140 middleHeight + (lastHeight - middleHeight) * x / (CURVE_FULL_STEPS - 1);
141 }
142 return height;
143}
144
145/// A slope that bends on the diagonal x = y: from sample 0 at the top right
146/// corner to sample 1 on the diagonal to sample 2 at the bottom left.
147/// Kind 6. It divides by 16 with a shift where kind 5 divides by 15, so its
148/// slopes are 15/16 as steep and it never reaches sample 2 exactly.
150 const s8 *samples = (const s8 *)heightBytes;
151 s32 firstHeight;
152 s32 middleHeight;
153 s32 lastHeight;
154 s32 pixelDifference;
155 s32 heightDelta;
156
157 firstHeight = CURVE_HEIGHT_FIXED(*samples++);
158 middleHeight = CURVE_HEIGHT_FIXED(samples[0]);
159 lastHeight = samples[1];
160 // As kind 5, on y - x biased by 15.
161 pixelDifference = y - x;
162 x = pixelDifference + CURVE_FULL_STEPS - 1;
163 lastHeight = CURVE_HEIGHT_FIXED(lastHeight);
164
165 if (x == CURVE_FULL_STEPS - 1)
166 return middleHeight;
167
168 if ((u32)x < CURVE_FULL_STEPS - 1) {
169 heightDelta = middleHeight - firstHeight;
170 pixelDifference = heightDelta * x;
171 if (pixelDifference < 0)
172 // Round towards zero, as dividing by 16 would.
173 pixelDifference += CURVE_FULL_STEPS - 1;
174 pixelDifference >>= 4;
175 return firstHeight + pixelDifference;
176 }
177 // The second half measures from the diagonal by y - x itself, 1 to 15.
178 pixelDifference *= lastHeight - middleHeight;
179 if (pixelDifference < 0)
180 pixelDifference += CURVE_FULL_STEPS - 1;
181 pixelDifference >>= 4;
182 return middleHeight + pixelDifference;
183}
184
185/// A raised or sunken rounded square: sample 1 where gCurve_LerpWeightTable is
186/// 1, sample 0 in the corners.
187/// Kind 7.
188s32 Curve_LerpTwoSamplesByTable(const u8 *heightBytes, s32 x, s32 y) {
189 const s8 *samples = (const s8 *)heightBytes;
190 s32 startHeight;
191
192 startHeight = CURVE_HEIGHT_FIXED(samples[0]);
193 // The weight is 0 or 1, so the result is one sample or the other, never
194 // between.
195 return startHeight + ((CURVE_HEIGHT_FIXED(samples[1]) - startHeight) *
197}
198
199/// A step along x: sample 0 for x < 8, sample 1 from x = 8.
200/// Kind 8.
201s32 Curve_StepAtHalf(const u8 *heightBytes, s32 pixelX, s32 pixelY) {
202 const s8 *samples = (const s8 *)heightBytes;
203 u32 cellX = pixelX;
204 s32 heightSample;
205 if (cellX < CURVE_HALF_STEPS)
206 heightSample = samples[0];
207 else
208 heightSample = samples[1];
209 return CURVE_HEIGHT_FIXED(heightSample);
210}
211
212/// A step along y: sample 0 for y < 8, sample 1 from y = 8.
213/// Kind 9.
214s32 Curve_StepAtHalfB(const u8 *heightBytes, s32 pixelX, s32 pixelY) {
215 const s8 *samples = (const s8 *)heightBytes;
216 u32 cellY = pixelY;
217 s32 heightSample;
218 if (cellY < CURVE_HALF_STEPS)
219 heightSample = samples[0];
220 else
221 heightSample = samples[1];
222 return CURVE_HEIGHT_FIXED(heightSample);
223}
224
225/// A slope along x that bends at the middle: sample 0 at x = 0, sample 1 at
226/// x = 8, towards sample 2 at x = 16.
227/// Kind 10.
228s32 Curve_LerpThreeSamplesAtHalf(const u8 *heightBytes, s32 pixelX,
229 s32 pixelY) {
230 const s8 *samples = (const s8 *)heightBytes;
231 u32 cellX = pixelX;
232 s32 endpointHeight;
233 s32 middleHeight;
234 s32 heightDelta;
235
236 endpointHeight = CURVE_HEIGHT_FIXED(*samples++);
237 middleHeight = CURVE_HEIGHT_FIXED(*samples++);
238 // Each half is 8 pixels: the shift by 3 divides by 8, and the bias of 7
239 // rounds towards zero.
240 if (cellX < CURVE_HALF_STEPS) {
241 heightDelta = (middleHeight - endpointHeight) * cellX;
242 if (heightDelta < 0) {
243 heightDelta += CURVE_HALF_STEPS - 1;
244 }
245 return endpointHeight + (heightDelta >> 3);
246 }
247
248 {
249 s32 offsetPastMiddle;
250
251 endpointHeight = CURVE_HEIGHT_FIXED(*samples);
252 offsetPastMiddle = cellX;
253 endpointHeight -= middleHeight;
254 offsetPastMiddle -= CURVE_HALF_STEPS;
255 heightDelta = endpointHeight * offsetPastMiddle;
256 if (heightDelta < 0) {
257 heightDelta += CURVE_HALF_STEPS - 1;
258 }
259 return middleHeight + (heightDelta >> 3);
260 }
261}
262
263/// A slope along y that bends at the middle, as kind 10 does along x.
264/// Kind 11. Its samples are read unsigned: 128 to 255 are heights, where the
265/// other kinds read them as -128 to -1.
266s32 Curve_LerpThreeSamplesAtHalfB(const u8 *heightBytes, s32 pixelX,
267 s32 pixelY) {
268 const u8 *samples = heightBytes;
269 u32 cellY = pixelY;
270 s32 endpointHeight;
271 s32 middleHeight;
272 s32 offsetPastMiddle;
273 s32 heightDelta;
274 s32 tailDelta;
275
276 endpointHeight = CURVE_HEIGHT_FIXED(*samples++);
277 middleHeight = CURVE_HEIGHT_FIXED(*samples++);
278 // As kind 10: halves of 8 pixels, rounded towards zero.
279 if (cellY < CURVE_HALF_STEPS) {
280 heightDelta = (middleHeight - endpointHeight) * cellY;
281 if (heightDelta < 0) {
282 heightDelta += CURVE_HALF_STEPS - 1;
283 }
284 return endpointHeight + (heightDelta >> 3);
285 }
286
287 endpointHeight = CURVE_HEIGHT_FIXED(*samples);
288 offsetPastMiddle = cellY;
289 endpointHeight -= middleHeight;
290 offsetPastMiddle -= CURVE_HALF_STEPS;
291 tailDelta = endpointHeight * offsetPastMiddle;
292 if (tailDelta < 0) {
293 tailDelta += CURVE_HALF_STEPS - 1;
294 }
295 return middleHeight + (tailDelta >> 3);
296}
297
298/// The sample gCurve_SampleIndexTable picks for (x, y).
299/// Kind 12.
300s32 Curve_LookupSampleByTable(const u8 *heightBytes, s32 pixelX, s32 pixelY) {
301 const s8 *samples = (const s8 *)heightBytes;
302 u32 cellX = pixelX;
303 u32 cellY = pixelY;
304 // The table holds a byte per pixel of the cell, row by row.
305 return CURVE_HEIGHT_FIXED(
306 samples[gCurve_SampleIndexTable[cellX + (cellY << 4)]]);
307}
308
309/// The same, with the table mirrored left to right.
310/// Kind 13.
311s32 Curve_LookupSampleByTableReversed(const u8 *heightBytes, s32 pixelX,
312 s32 pixelY) {
313 const s8 *samples = (const s8 *)heightBytes;
314 u32 cellX = pixelX;
315 u32 cellY = pixelY;
316 // Row y read from its right end: (y << 4) + 15 - x.
317 return CURVE_HEIGHT_FIXED(
318 samples[gCurve_SampleIndexTable[((cellY << 4) - cellX) +
319 CURVE_FULL_STEPS - 1]]);
320}
321
322/// Flat, as Curve_GetFirstSampleA. Kind 14.
323s32 Curve_GetFirstSampleB(const u8 *heightBytes, s32 pixelX, s32 pixelY) {
324 const s8 *samples = (const s8 *)heightBytes;
325 return CURVE_HEIGHT_FIXED(samples[0]);
326}
327
328/// Flat, as Curve_GetFirstSampleA. Kind 15.
329s32 Curve_GetFirstSampleC(const u8 *heightBytes, s32 pixelX, s32 pixelY) {
330 const s8 *samples = (const s8 *)heightBytes;
331 return CURVE_HEIGHT_FIXED(samples[0]);
332}
333
334#undef CURVE_HEIGHT_FIXED
335
336/// Returns the ground height of a layer at (x, y) in 16.16 pixels: the
337/// height function of the cell's terrain kind applied to its samples.
338/// y is the map's down axis, an object's z.
339///
340/// Called each frame by Object_UpdateAllThumb for objects that follow the
341/// terrain, by the player control, and as Map_GetTerrainHeightFar by the
342/// field scene's objects, the Psynergy effects and about ten scene overlays.
344 struct MapState *work = gMapWork[0];
345 struct MapCell *cell;
346 u8 *heightBytes;
347
348 x >>= 16;
349 y >>= 16;
350 // Before the map work exists, the grid is read from its start.
351 cell = (struct MapCell *)Ram_MapCellBuffer;
352 if (work != NULL) {
353 cell = work->layers[layer & 3].cells;
354 }
355 // Cells are 16 pixels, 128 to a row. A cell's collision record is four
356 // bytes: the kind, then up to three height samples.
357 cell += x / 16 + (y / 16 << 7);
358 heightBytes = Ram_MapCollision + cell->attributeB * 4;
359 // UB: sequence the kind-byte read before passing the remaining samples.
360#ifdef UBFIX
361 {
362 u32 kind = *heightBytes++ & 15;
363
364 return gMap_TerrainHeightFunctions[kind](heightBytes, x & 15, y & 15);
365 }
366#else
367 return gMap_TerrainHeightFunctions[*heightBytes++ & 15](heightBytes, x & 15,
368 y & 15);
369#endif
370}
371
372/// Returns the terrain kind (the low four bits of the first collision byte)
373/// of a layer's cell at (x, y) in 16.16 pixels.
374/// Called through Map_GetCellAttributeLowNibbleFar by the Psynergy Move
375/// effect.
377 struct MapState *state = gMapWork[0];
378 struct MapCell *cells;
379 s32 cellX;
380 s32 cellY;
381 u32 heightAttributeIndex;
382
383 x >>= 16;
384 y >>= 16;
385 cells = (struct MapCell *)gMapCellBuffer;
386 if (state != 0) {
387 cells = state->layers[layer & 3].cells;
388 }
389 cellX = x / 16;
390 cellY = y / 16;
391 cells += cellX + (cellY << 7);
392 // The kind byte of the cell's four-byte collision record.
393 heightAttributeIndex = cells->attributeB;
394 return *(Ram_MapCollision + heightAttributeIndex * 4) & 15;
395}
396
397/// Returns the collision code of a layer's cell at (x, y) in 16.16 pixels.
398/// The shift by 20 takes 16.16 pixels straight to 16-pixel cells. Called
399/// through GetMapCellCollisionFar by the Psynergy climbing and by scenes
400/// (Altin Peak, Colosso, Imil, Crossbone Isle).
402 struct MapState *state;
403 struct MapCell *cell;
404
405 state = gMapWork[0];
406 x >>= 20;
407 y >>= 20;
408 // Before the map work exists, the grid is read from its start.
409 cell = (struct MapCell *)gMapCellBuffer;
410 if (state != NULL) {
411 cell = state->layers[layer & 3].cells;
412 }
413 cell += x + (y << 7);
414 return cell->collisionCode;
415}
416
417/// Sets the collision code of a layer's cell at (x, y) in 16.16 pixels.
418/// Writes the cell in the map's grid; does nothing before the map is set up.
419/// Called through SetMapCellCollisionFar by scenes
420/// (Colosso, Altin Peak, Crossbone Isle, Venus Lighthouse, Tolbi, Sol
421/// Sanctum).
423 struct MapState *state = gMapWork[0];
424
425 x >>= 20;
426 y >>= 20;
427 // Without the map work there is no layer to write to.
428 if (state != NULL) {
429 struct MapCell *cell = state->layers[layer & 3].cells;
430
431 cell += x + (y << 7);
433 }
434}
435
436/// Returns the top two bits of the block word of the cell at pixel (x, y).
438 s32 cellX = x / 16;
439 s32 cellY = y / 16;
440 struct MapCell *mapCell =
441 (struct MapCell *)gMapCellBuffer + (cellX + cellY * 128);
442
443 // The high byte of the block word; its top two bits are flags.
444 return ((u8 *)&mapCell->metatileAndFlags)[1] >> 6;
445}
446
447/// Returns whether an object can step to position: 2 when the cell there is
448/// a wall (collision code 0xff), 1 when the ground is more than 8 pixels
449/// higher than the object's, -1 when it is more than 12 pixels lower, else 0.
450///
451/// Called by the player control and the script commands that pick a free
452/// step, and as Map_CheckObjectStepFar by the Psynergy effects (Move, Carry,
453/// Force, climbing). A terrainId above 2 reads the grid from its start.
455 struct FieldPosition *position) {
456 struct MapState *mapState;
457 s32 pixelX;
458 s32 pixelZ;
459 struct MapCell *cell;
460 u8 *heightBytes;
461 s32 targetGround;
462 s32 stepHeight;
463
464 pixelX = ((union FieldCoordinate *)&position->x)->part.pixel;
465 pixelZ = ((union FieldCoordinate *)&position->z)->part.pixel;
466 mapState = gMapWork[0];
467 if (mapState == NULL)
468 return 0;
469 // Layers 0 to 2 have their windows into the grid; any other terrainId
470 // reads the grid from its start.
471 if (object->terrainId <= 2)
472 cell = mapState->layers[object->terrainId].cells;
473 else
474 cell = (struct MapCell *)Ram_MapCellBuffer;
475 cell += pixelX / 16 + (pixelZ / 16 << 7);
476 // A wall blocks whatever the heights.
477 if (cell->collisionCode == 0xff)
478 return 2;
479 heightBytes = Ram_MapCollision + cell->attributeB * 4;
480 // UB: sequence the kind-byte read before passing the remaining samples.
481#ifdef UBFIX
482 {
483 u32 kind = *heightBytes++ & 15;
484
485 targetGround = gMap_TerrainHeightFunctions[kind](heightBytes, pixelX & 15,
486 pixelZ & 15);
487 }
488#else
489 targetGround = gMap_TerrainHeightFunctions[*heightBytes++ & 15](
490 heightBytes, pixelX & 15, pixelZ & 15);
491#endif
492 // Up to 8 pixels up or 12 down is a step the object can take.
493 stepHeight = targetGround - object->terrainHeight;
494 if (stepHeight > 0x80000)
495 return 1;
496 if (stepHeight < -0xc0000)
497 return -1;
498 return 0;
499}
500
501/// Returns 0 when the cell under position (its x, and y less its height) in
502/// layer 2 is a wall (collision code 0xff), else -1.
503/// The name says the opposite of what it returns: 0 is the blocked answer.
504/// Called by the player control and, as CheckMapPositionCellOccupiedFar, by
505/// the Psynergy climbing.
507 s32 pixelX;
508 s32 pixelY;
509 s32 cellX;
510 s32 cellY;
511 struct MapState *mapState;
512 struct MapCell *cell;
513
514 pixelX = position->x / 65536;
515 // The point on the ground below the position.
516 pixelY = (position->y - position->height) / 65536;
517 mapState = gMapWork[0];
518 if (mapState == NULL)
519 return 0;
520 // Always layer 2, the one on BG1.
521 cell = mapState->layers[2].cells;
522 cellX = pixelX / 16;
523 cellY = pixelY / 16;
524 cell += cellX + cellY * 128;
525 // 1 - 1 for open ground, 0 - 1 for a wall: 0 means walled.
526 return (cell->collisionCode != 0xff) - 1;
527}
528
529/// Returns the world map's collision value (1-15) at position: from the upper
530/// collision layer where it has one, else the lower, else 7. Each layer is a
531/// tile map of 4-bit collision pixels.
532///
533/// Called by the player control, CheckWorldMapWalkable and
534/// GetWorldMapTerrainBehavior.
536 s32 halfPixelX = position->x >> 17;
537 s32 y = position->y;
538 s32 halfPixelY = y >> 17;
539 u32 collisionCell;
540 u32 pixelOffset;
541 u8 collisionTile;
542 u8 packedCollisions;
543 u32 result;
544
545 // Coordinates in 2-pixel units. A collision tile covers 16x16 pixels as
546 // 4x4 values of 4 bits, two to a byte, 8 bytes a tile; the maps of tile
547 // numbers are 64 tiles square and wrap.
548 collisionCell = (((halfPixelY / 8) & 63) << 6) + ((halfPixelX / 8) & 63);
549 pixelOffset = (((halfPixelY / 2) & 3) << 1) + ((halfPixelX / 4) & 1);
550
551 // The upper layer: its tile map in screen block 10, its tiles 0x800 bytes
552 // into the collision buffer.
553 collisionTile = BG_SCREEN_BLOCK(10)[collisionCell];
554 packedCollisions =
555 *(Ram_MapCollision + 0x800 + (collisionTile << 3) + pixelOffset);
556 if (packedCollisions != 0) {
557 if (halfPixelX & 2)
558 result = packedCollisions >> 4;
559 else
560 result = packedCollisions & 15;
561 if (result != 0)
562 return result;
563 }
564
565 // The lower layer: its tile map in screen block 8, its tiles at the start.
566 collisionTile = BG_SCREEN_BLOCK(8)[collisionCell];
567 packedCollisions = *(Ram_MapCollision + (collisionTile << 3) + pixelOffset);
568 if (packedCollisions != 0) {
569 if (halfPixelX & 2)
570 result = packedCollisions >> 4;
571 else
572 result = packedCollisions & 15;
573 if (result != 0)
574 return result;
575 }
576
577 // Neither layer has a value: the default, 7, inside the walkable range.
578 return 7;
579}
580
581/// Returns 0 when the world map at position can be walked on (collision 5 to
582/// 12), else -1.
583/// The first argument is not read; the player control passes its object.
584/// Called by the player control as it probes the steps around the object it
585/// moves.
586s32 CheckWorldMapWalkable(s32 unused, struct WorldPosition *position) {
587 // One unsigned compare tests 5 to 12.
588 if ((GetWorldMapCollision(position) - 5) <= 7U) {
589 return 0;
590 }
591 return -1;
592}
593
594/// Returns the world map's terrain behaviour at position from
595/// gWorldMap_TerrainBehaviorTable, and stores the block's terrain kind in
596/// terrainKind.
597/// Called through GetWorldMapTerrainBehaviorFar by the world map's
598/// encounters (Encounter_ResolveWorldMapZoneAndBackdrop).
600 s32 *terrainKind) {
601 s32 collisionKind = GetWorldMapCollision(position);
602 s32 x = position->x;
603 s32 y;
604 s32 behaviorBank = 0;
605 u32 blockX;
606 u32 index;
607 u32 *blockWord;
608
609 // Blocks are 32 pixels, 32 to a row; the bias rounds a negative coordinate
610 // towards zero, as division would.
611 if (x < 0)
612 x += 0x1fffff;
613 blockX = (x >> 21) & 31;
614 y = position->y;
615 if (y < 0)
616 y += 0x1fffff;
617
618 index = blockX + (((y >> 21) & 31) << 5);
619 blockWord = gMapBlocks + index;
620 // Bit 31 of the block word selects the second bank of 16; terrain kind
621 // 21 the third, whatever bit 31 says.
622 if (((u8 *)blockWord)[3] & 0x80)
623 behaviorBank = 0x10;
624
625 // The terrain kind is bits 24 to 30 of the block word.
626 *terrainKind = (*blockWord << 1) >> 25;
627 if (*terrainKind == 21)
628 behaviorBank = 0x20;
629
630 return gWorldMap_TerrainBehaviorTable[behaviorBank + collisionKind];
631}
@ CURVE_FULL_STEPS
pixels across a cell
Definition curve.h:13
@ CURVE_HALF_STEPS
pixels to the middle of a 16-pixel cell
Definition curve.h:12
const u8 gCurve_LerpWeightTable[256]
Height-curve tables, indexed by (row << 4) + column within a 16x16 cell.
Definition curve_data.c:8
const u8 gCurve_SampleIndexTable[256]
The sample Curve_LookupSampleByTable reads at each position: 0, 1 or 2, split along two diagonals.
Definition curve_data.c:29
What every part of the field object shares: its includes and the few names more than one part uses.
struct EffectStep gMapCellBuffer[]
Map cells; battle effects reuse this as a particle array.
void * gMapWork[]
#define BG_SCREEN_BLOCK(n)
Definition io_reg.h:167
u32 gMapBlocks[]
const TerrainHeightFn gMap_TerrainHeightFunctions[16]
Terrain height functions, chosen by the low four bits of a cell's first collision byte and called wit...
Definition mapdata.c:14
const u8 gWorldMap_TerrainBehaviorTable[48]
World map terrain behaviour, indexed by the collision value plus 0x10 when the block word's top bit i...
Definition mapdata.c:37
#define Ram_MapCollision
Definition ram_buffer.h:13
#define Ram_MapCellBuffer
Definition ram_buffer.h:10
#define NULL
Definition bilibin.h:6
A position on the field.
s32 z
16.16 fixed-point pixels
One cell of a map layer: its metatile and flags, its collision code and an attribute indexing the col...
Definition map.h:13
u8 attributeB
Indexes the 4-byte collision entries (gMapCollision): terrain kind in the first byte's low four bits,...
Definition map.h:21
u16 metatileAndFlags
bits: 15..12 flags (15..14 read by Map_GetCellHighFlags) | 11..0 metatile
Definition map.h:15
u8 collisionCode
The step code: 1 to 239 scene events, 240 and 241 encounter ground, 250 hazard, 252 to 254 for Field_...
Definition map.h:18
struct MapCell * cells
the layer's first cell (MapLayerScroll's cells)
Definition map.h:26
The map work in heap slot 8 (struct MapScrollWork), seen as its tile animation channels,...
Definition map.h:49
struct MapLayer layers[4]
Each layer's cells, at MapScrollWork's layers[i].cells; readers mask the layer with 3,...
Definition map.h:63
One of the 64 field objects in the object pool (heap slot 5): its script, position,...
u8 terrainId
the map layer its ground height is read from
A position on the world map, as its walkability check reads it.
Definition map.h:74
s32 x
16.16 fixed-point pixels
Definition map.h:75
s32 y
16.16 fixed-point pixels
Definition map.h:77
s32 height
16.16 fixed-point pixels
Definition map.h:76
s32 Curve_LerpTwoSamplesByTable(const u8 *heightBytes, s32 x, s32 y)
A raised or sunken rounded square: sample 1 where gCurve_LerpWeightTable is 1, sample 0 in the corner...
Definition terrain.c:188
s32 Curve_LerpTwoSamplesB(const u8 *heightBytes, s32 pixelX, s32 pixelY)
A slope along y: from sample 0 at y = 0 towards sample 1 at y = 16.
Definition terrain.c:44
s32 Curve_GetFirstSampleB(const u8 *heightBytes, s32 pixelX, s32 pixelY)
Flat, as Curve_GetFirstSampleA. Kind 14.
Definition terrain.c:323
s32 Map_CheckObjectStep(struct ObjectRuntime *object, struct FieldPosition *position)
Returns whether an object can step to position: 2 when the cell there is a wall (collision code 0xff)...
Definition terrain.c:454
s32 Curve_LookupSampleByTableReversed(const u8 *heightBytes, s32 pixelX, s32 pixelY)
The same, with the table mirrored left to right.
Definition terrain.c:311
s32 Map_GetCellAttributeLowNibble(s32 layer, s32 x, s32 y)
Returns the terrain kind (the low four bits of the first collision byte) of a layer's cell at (x,...
Definition terrain.c:376
s32 Curve_StepAtSummedPosition(const u8 *heightBytes, s32 x, s32 y)
A step across the diagonal x + y = 15: sample 0 before it, sample 1 after it and the higher of the tw...
Definition terrain.c:61
s32 CheckWorldMapWalkable(s32 unused, struct WorldPosition *position)
Returns 0 when the world map at position can be walked on (collision 5 to 12), else -1.
Definition terrain.c:586
s32 Curve_GetFirstSampleC(const u8 *heightBytes, s32 pixelX, s32 pixelY)
Flat, as Curve_GetFirstSampleA. Kind 15.
Definition terrain.c:329
s32 Curve_LerpTwoSamples(const u8 *heightBytes, s32 pixelX, s32 pixelY)
A slope along x: from sample 0 at x = 0 towards sample 1 at x = 16.
Definition terrain.c:28
UNUSED s32 Map_GetCellHighFlags(s32 x, s32 y)
Returns the top two bits of the block word of the cell at pixel (x, y).
Definition terrain.c:437
s32 GetWorldMapCollision(struct WorldPosition *position)
Returns the world map's collision value (1-15) at position: from the upper collision layer where it h...
Definition terrain.c:535
s32 Curve_StepAtHalfB(const u8 *heightBytes, s32 pixelX, s32 pixelY)
A step along y: sample 0 for y < 8, sample 1 from y = 8.
Definition terrain.c:214
s32 Curve_LookupSampleByTable(const u8 *heightBytes, s32 pixelX, s32 pixelY)
The sample gCurve_SampleIndexTable picks for (x, y).
Definition terrain.c:300
s32 Curve_GetFirstSampleA(const u8 *heightBytes, s32 pixelX, s32 pixelY)
The terrain height functions (gMap_TerrainHeightFunctions): each takes a cell's height samples after ...
Definition terrain.c:21
s32 GetWorldMapTerrainBehavior(struct WorldPosition *position, s32 *terrainKind)
Returns the world map's terrain behaviour at position from gWorldMap_TerrainBehaviorTable,...
Definition terrain.c:599
s32 Curve_LerpThreeSamplesAtHalf(const u8 *heightBytes, s32 pixelX, s32 pixelY)
A slope along x that bends at the middle: sample 0 at x = 0, sample 1 at x = 8, towards sample 2 at x...
Definition terrain.c:228
s32 Curve_StepAtHalf(const u8 *heightBytes, s32 pixelX, s32 pixelY)
A step along x: sample 0 for x < 8, sample 1 from x = 8.
Definition terrain.c:201
s32 CheckMapPositionCellOccupied(struct WorldPosition *position)
Returns 0 when the cell under position (its x, and y less its height) in layer 2 is a wall (collision...
Definition terrain.c:506
s32 Curve_StepAtDifferencePosition(const u8 *heightBytes, s32 x, s32 y)
A step across the diagonal x = y: sample 0 where y < x, sample 1 where y > x and the higher of the tw...
Definition terrain.c:88
s32 GetMapCellCollision(s32 layer, s32 x, s32 y)
Returns the collision code of a layer's cell at (x, y) in 16.16 pixels.
Definition terrain.c:401
#define CURVE_HEIGHT_FIXED(sample)
Definition terrain.c:12
s32 Curve_LerpThreeSamplesAtDifference(const u8 *heightBytes, s32 x, s32 y)
A slope that bends on the diagonal x = y: from sample 0 at the top right corner to sample 1 on the di...
Definition terrain.c:149
s32 Curve_LerpThreeSamplesByRatio(const u8 *heightBytes, s32 x, s32 y)
A slope that bends on the diagonal x + y = 15: from sample 0 at the top left corner to sample 1 on th...
Definition terrain.c:118
void SetMapCellCollision(u32 layer, s32 x, s32 y, u32 collisionCode)
Sets the collision code of a layer's cell at (x, y) in 16.16 pixels.
Definition terrain.c:422
s32 Curve_LerpThreeSamplesAtHalfB(const u8 *heightBytes, s32 pixelX, s32 pixelY)
A slope along y that bends at the middle, as kind 10 does along x.
Definition terrain.c:266
s32 Map_GetTerrainHeight(s32 layer, s32 x, s32 y)
Returns the ground height of a layer at (x, y) in 16.16 pixels: the height function of the cell's ter...
Definition terrain.c:343
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed char s8
Definition types.h:10
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
A field coordinate, read whole or as its fraction and its whole pixels.
struct FieldCoordinate::@024321007066302143002254325121164243234242211074 part