2019-08-25 04:46:40 +00:00
|
|
|
#include <ultra64.h>
|
|
|
|
|
|
|
|
#include "sm64.h"
|
|
|
|
#include "game.h"
|
|
|
|
#include "mario.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "save_file.h"
|
|
|
|
#include "engine/surface_collision.h"
|
|
|
|
#include "engine/graph_node.h"
|
|
|
|
#include "geo_misc.h"
|
|
|
|
#include "area.h"
|
|
|
|
#include "prevent_bss_reordering.h"
|
|
|
|
#include "paintings.h"
|
|
|
|
|
|
|
|
s16 gPaintingMarioFloorType;
|
|
|
|
float gPaintingMarioXPos, gPaintingMarioYPos, gPaintingMarioZPos;
|
|
|
|
struct Thing *D_8035FFA0;
|
|
|
|
float (*D_8035FFA4)[3]; // TODO: Use struct
|
|
|
|
struct PaintingData *ripplingPainting;
|
|
|
|
s8 dddStatus;
|
|
|
|
|
|
|
|
struct PaintingData *hmcPaintings[] = {
|
|
|
|
cotmc_painting,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PaintingData *insideCastlePaintings[] = {
|
|
|
|
bob_painting, ccm_painting, wf_painting, jrb_painting, lll_painting,
|
|
|
|
ssl_painting, hmc_painting, ddd_painting, wdw_painting, thi_tiny_painting,
|
|
|
|
ttm_painting, ttc_painting, sl_painting, thi_huge_painting, NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PaintingData *ttmPaintings[] = {
|
|
|
|
ttm_slide_painting,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PaintingData **paintingGroups[] = {
|
|
|
|
hmcPaintings,
|
|
|
|
insideCastlePaintings,
|
|
|
|
ttmPaintings,
|
|
|
|
};
|
|
|
|
|
|
|
|
s16 gPaintingUpdateCounter = 1;
|
|
|
|
s16 gLastPaintingUpdateCounter = 0;
|
|
|
|
|
|
|
|
void stopAllRippleExcept(s16 *idptr, struct PaintingData *paintingGroup[]) {
|
|
|
|
s16 index;
|
|
|
|
s16 id = *idptr;
|
|
|
|
|
|
|
|
index = 0;
|
|
|
|
while (paintingGroup[index] != NULL) // for each painting
|
|
|
|
{
|
|
|
|
struct PaintingData *painting = segmented_to_virtual(paintingGroup[index]);
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->id != id) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting->rippleStatus = 0; // stop all rippling except for the selected painting
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float find_mario_y_position_on_painting(struct PaintingData *painting) {
|
|
|
|
//! unnecessary use of double constants
|
|
|
|
float marioYOffsetFromPainting = gPaintingMarioYPos - painting->vYPos + 50.0;
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (marioYOffsetFromPainting < 0.0) {
|
2019-08-25 04:46:40 +00:00
|
|
|
marioYOffsetFromPainting = 0.0; // If Mario is below the bottom, return the bottom
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (marioYOffsetFromPainting
|
|
|
|
> painting->vSize) { // If Mario is above the top, return the top
|
2019-08-25 04:46:40 +00:00
|
|
|
marioYOffsetFromPainting = painting->vSize;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
return marioYOffsetFromPainting;
|
|
|
|
}
|
|
|
|
|
|
|
|
float find_mario_z_position_on_painting(struct PaintingData *painting) {
|
|
|
|
float marioZOffsetFromPainting = painting->vZPos - gPaintingMarioZPos;
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (marioZOffsetFromPainting < 0.0) {
|
2019-08-25 04:46:40 +00:00
|
|
|
marioZOffsetFromPainting = 0.0; // If Mario is past the left side, return the left side
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (marioZOffsetFromPainting > painting->vSize) {
|
2019-08-25 04:46:40 +00:00
|
|
|
marioZOffsetFromPainting =
|
|
|
|
painting->vSize; // If Mario is past the right side, return the right side
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
return marioZOffsetFromPainting;
|
|
|
|
}
|
|
|
|
|
|
|
|
float painting_find_vertical_ripple_location(struct PaintingData *painting, s8 rippleSpot) {
|
|
|
|
switch (rippleSpot) {
|
|
|
|
case MARIO_Y:
|
|
|
|
return find_mario_y_position_on_painting(painting); // normal vertical paintings
|
|
|
|
break;
|
|
|
|
case MARIO_Z:
|
|
|
|
return find_mario_z_position_on_painting(painting); // horizontal paintings use X and Z
|
|
|
|
break;
|
|
|
|
case MIDDLE_Y:
|
|
|
|
return painting->vSize / 2.0; // some concentric ripples don't care about Mario
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float find_part_of_painting_near_mario(struct PaintingData *painting) {
|
|
|
|
float firstQuarter = painting->vSize / 4.0; // 1/4 of the way across the painting
|
|
|
|
float secondQuarter = painting->vSize / 2.0; // 1/2 of the way across the painting
|
|
|
|
float thirdQuarter = painting->vSize * 3.0 / 4.0; // 3/4 of the way across the painting
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->floorEntered & STAND_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return firstQuarter;
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return secondQuarter;
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return thirdQuarter;
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return firstQuarter;
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return secondQuarter;
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return thirdQuarter;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float find_mario_x_position_on_painting(struct PaintingData *painting) {
|
|
|
|
float mario_x_offset_from_painting = gPaintingMarioXPos - painting->vXPos;
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (mario_x_offset_from_painting < 0.0) {
|
2019-08-25 04:46:40 +00:00
|
|
|
mario_x_offset_from_painting = 0.0; // If Mario is past the left side, return the left side
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (mario_x_offset_from_painting > painting->vSize) {
|
2019-08-25 04:46:40 +00:00
|
|
|
mario_x_offset_from_painting =
|
|
|
|
painting->vSize; // If Mario is past the right side, return the right side
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
return mario_x_offset_from_painting;
|
|
|
|
}
|
|
|
|
|
|
|
|
float painting_find_horizontal_ripple_location(struct PaintingData *painting, s8 rippleSpot) {
|
|
|
|
switch (rippleSpot) {
|
|
|
|
case NEAR_MARIO_LATERALLY: // normal vertical paintings
|
|
|
|
return find_part_of_painting_near_mario(painting);
|
|
|
|
break;
|
|
|
|
case MARIO_X: // horizontally placed paintings use X and Z
|
|
|
|
return find_mario_x_position_on_painting(painting);
|
|
|
|
break;
|
|
|
|
case MIDDLE_X: // concentric rippling may not care about Mario
|
|
|
|
return painting->vSize / 2.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void painting_set_ripple_type(s8 intendedStatus, struct PaintingData *painting,
|
|
|
|
struct PaintingData *paintingGroup[], s8 hRippleSpot, s8 vRippleSpot,
|
|
|
|
s8 resetTimer) {
|
|
|
|
stopAllRippleExcept(&painting->id, paintingGroup); // make sure no other paintings are rippling
|
|
|
|
switch (intendedStatus) // set the variables necessary for the given ripple status
|
|
|
|
{
|
|
|
|
case RIPPLE_STATE_IDLE:
|
|
|
|
painting->currRippleMag = painting->passiveRippleMag;
|
|
|
|
painting->rippleMagMultiplier = painting->passiveRippleMagMultiplier;
|
|
|
|
painting->currRippleRate = painting->passiveRippleRate;
|
|
|
|
painting->dispersionFactor = painting->passiveDispersionFactor;
|
|
|
|
break;
|
|
|
|
case RIPPLE_STATE_ENTRY:
|
|
|
|
painting->currRippleMag = painting->entryRippleMag;
|
|
|
|
painting->rippleMagMultiplier = painting->entryRippleMagMultiplier;
|
|
|
|
painting->currRippleRate = painting->entryRippleRate;
|
|
|
|
painting->dispersionFactor = painting->entryDispersionFactor;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
painting->rippleStatus = intendedStatus;
|
|
|
|
painting->horizontalRippleSpot =
|
|
|
|
painting_find_horizontal_ripple_location(painting, hRippleSpot); // find the ripple location
|
|
|
|
painting->verticalRippleSpot = painting_find_vertical_ripple_location(painting, vRippleSpot);
|
|
|
|
gPaintingMarioYEntry = gPaintingMarioYPos;
|
2019-09-01 19:50:50 +00:00
|
|
|
if (resetTimer == RESET_TIMER) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting->rippleTimer = 0.0f;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
ripplingPainting = painting;
|
|
|
|
}
|
|
|
|
|
|
|
|
void vertical_proximity_ripple_painting_ripple(
|
|
|
|
struct PaintingData *painting,
|
|
|
|
struct PaintingData
|
|
|
|
*paintingGroup[]) // For paintings aligned vertically that follow RIPPLE_TRIGGER_PROXIMITY, set
|
|
|
|
// some flags depending on where Mario is
|
|
|
|
{
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->floorEntered & STAND_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void vertical_proximity_ripple_painting_ripple_if_mario_enters(
|
|
|
|
struct PaintingData *painting,
|
|
|
|
struct PaintingData *paintingGroup[]) // For paintings aligned vertically that follow
|
|
|
|
// RIPPLE_TRIGGER_PROXIMITY, set some flags if Mario enters
|
|
|
|
{
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->floorEntered & ENTER_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void vertical_continuous_ripple_painting_ripple(
|
|
|
|
struct PaintingData *painting,
|
|
|
|
struct PaintingData
|
|
|
|
*paintingGroup[]) // For paintings aligned vertically that follow RIPPLE_TRIGGER_CONTINUOUS (DDD
|
|
|
|
// only), set some flags depending on where Mario is
|
|
|
|
{
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->floorEntered & STAND_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, MIDDLE_X, MIDDLE_Y,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, MIDDLE_X, MIDDLE_Y,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, MIDDLE_X, MIDDLE_Y,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void vertical_continuous_ripple_painting_ripple_if_mario_enters(
|
|
|
|
struct PaintingData *painting,
|
|
|
|
struct PaintingData
|
|
|
|
*paintingGroup[]) // For paintings aligned vertically that follow RIPPLE_TRIGGER_CONTINUOUS (DDD
|
|
|
|
// only), set some flags if Mario enters
|
|
|
|
{
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->floorEntered & ENTER_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, DONT_RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, DONT_RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & ENTER_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, NEAR_MARIO_LATERALLY,
|
|
|
|
MARIO_Y, DONT_RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void horizontal_proximity_ripple_painting_ripple(
|
|
|
|
struct PaintingData *painting,
|
|
|
|
struct PaintingData
|
|
|
|
*paintingGroup[]) // For paintings aligned horizontally that follow RIPPLE_TRIGGER_PROXIMITY
|
|
|
|
// (these are not found in-game), set some flags depending on where Mario is
|
|
|
|
{
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->floorEntered & STAND_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->marioNewlyUnderPainting) {
|
|
|
|
if (painting->currFloor & ENTER_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->currFloor & ENTER_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->currFloor & ENTER_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void horizontal_proximity_ripple_painting_ripple_if_mario_enters(
|
|
|
|
struct PaintingData *painting,
|
|
|
|
struct PaintingData
|
|
|
|
*paintingGroup[]) // For paintings aligned horizontally that follow RIPPLE_TRIGGER_PROXIMITY
|
|
|
|
// (these are not found in-game), set some flags if Mario enters
|
|
|
|
{
|
|
|
|
if (painting->marioNewlyUnderPainting) {
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->currFloor & ENTER_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->currFloor & ENTER_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->currFloor & ENTER_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void horizontal_continuous_ripple_painting_ripple(
|
|
|
|
struct PaintingData *painting,
|
|
|
|
struct PaintingData
|
|
|
|
*paintingGroup[]) // For paintings aligned horizontally that follow RIPPLE_TRIGGER_CONTINUOUS
|
|
|
|
// (HMC and CotMC), set some flags depending on where Mario is
|
|
|
|
{
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->floorEntered & STAND_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, MIDDLE_X, MIDDLE_Y,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, MIDDLE_X, MIDDLE_Y,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->floorEntered & STAND_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_IDLE, painting, paintingGroup, MIDDLE_X, MIDDLE_Y,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->currFloor & ENTER_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->currFloor & ENTER_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->currFloor & ENTER_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void horizontal_continuous_ripple_painting_ripple_if_mario_enters(
|
|
|
|
struct PaintingData *painting,
|
|
|
|
struct PaintingData
|
|
|
|
*paintingGroup[]) // For paintings aligned horizontally that follow RIPPLE_TRIGGER_CONTINUOUS
|
|
|
|
// (HMC and CotMC), set some flags if Mario enters
|
|
|
|
{
|
|
|
|
if (painting->marioNewlyUnderPainting) {
|
2019-09-01 19:50:50 +00:00
|
|
|
if (painting->currFloor & ENTER_LEFT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
DONT_RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->currFloor & ENTER_MIDDLE) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
DONT_RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (painting->currFloor & ENTER_RIGHT) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting_set_ripple_type(RIPPLE_STATE_ENTRY, painting, paintingGroup, MARIO_X, MARIO_Z,
|
|
|
|
DONT_RESET_TIMER);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void painting_update_floors(struct PaintingData *painting) {
|
|
|
|
s16 paintingId = painting->id;
|
|
|
|
s8 leftSideStand = 0;
|
|
|
|
s8 middleStand = 0;
|
|
|
|
s8 rightSideStand = 0;
|
|
|
|
s8 leftSideEnter = 0;
|
|
|
|
s8 middleEnter = 0;
|
|
|
|
s8 rightSideEnter = 0;
|
|
|
|
|
|
|
|
/* The area in front of every painting in the game (except HMC and CotMC, which *\
|
|
|
|
|* act a little differently) is made up of 3 special floor triangles with special *|
|
|
|
|
|* (unique) surface types. This code checks which surface Mario is currently on *|
|
|
|
|
\* and sets a bitfield accordingly. */
|
|
|
|
|
|
|
|
if (gPaintingMarioFloorType
|
2019-09-01 19:50:50 +00:00
|
|
|
== paintingId * 3
|
|
|
|
+ SURFACE_PAINTING_WOBBLE_A6) { // check if Mario's current floor is one of the
|
|
|
|
// special floors
|
2019-08-25 04:46:40 +00:00
|
|
|
leftSideStand = STAND_LEFT;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
|
|
|
if (gPaintingMarioFloorType == paintingId * 3 + SURFACE_PAINTING_WOBBLE_A7) {
|
2019-08-25 04:46:40 +00:00
|
|
|
middleStand = STAND_MIDDLE;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
|
|
|
if (gPaintingMarioFloorType == paintingId * 3 + SURFACE_PAINTING_WOBBLE_A8) {
|
2019-08-25 04:46:40 +00:00
|
|
|
rightSideStand = STAND_RIGHT;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
|
|
|
if (gPaintingMarioFloorType == paintingId * 3 + SURFACE_PAINTING_WARP_D3) {
|
2019-08-25 04:46:40 +00:00
|
|
|
leftSideEnter = ENTER_LEFT;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
|
|
|
if (gPaintingMarioFloorType == paintingId * 3 + SURFACE_PAINTING_WARP_D4) {
|
2019-08-25 04:46:40 +00:00
|
|
|
middleEnter = ENTER_MIDDLE;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
|
|
|
if (gPaintingMarioFloorType == paintingId * 3 + SURFACE_PAINTING_WARP_D5) {
|
2019-08-25 04:46:40 +00:00
|
|
|
rightSideEnter = ENTER_RIGHT;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
|
|
|
painting->lastFloor = painting->currFloor;
|
|
|
|
painting->currFloor = leftSideStand + middleStand + rightSideStand + leftSideEnter + middleEnter
|
|
|
|
+ rightSideEnter; // at most 1 of these will be nonzero;
|
|
|
|
painting->floorEntered =
|
|
|
|
(painting->lastFloor ^ painting->currFloor)
|
|
|
|
& painting->currFloor; // floorEntered is true iff currFloor is true and lastFloor is false
|
|
|
|
// (Mario just entered the floor on this frame)
|
|
|
|
painting->lastMarioUnderPainting = painting->currMarioUnderPainting;
|
2019-09-01 19:50:50 +00:00
|
|
|
if (gPaintingMarioYPos < painting->vYPos) {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting->currMarioUnderPainting = 1; // If Mario is below the painting, set a variable
|
2019-09-01 19:50:50 +00:00
|
|
|
} else {
|
2019-08-25 04:46:40 +00:00
|
|
|
painting->currMarioUnderPainting = 0; // Otherwise, reset it
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
painting->marioNewlyUnderPainting =
|
|
|
|
(painting->lastMarioUnderPainting ^ painting->currMarioUnderPainting)
|
|
|
|
& painting->currMarioUnderPainting; // Again, marioNewlyUnderPainting is true iff he is under it
|
|
|
|
// this frame but wasn't last frame.
|
|
|
|
}
|
|
|
|
|
|
|
|
void painting_update_ripple_status(struct PaintingData *painting) {
|
|
|
|
if (gPaintingUpdateCounter != gLastPaintingUpdateCounter) {
|
|
|
|
painting->currRippleMag *= painting->rippleMagMultiplier;
|
|
|
|
painting->rippleTimer +=
|
|
|
|
1.0; //! After ~6.47 days, paintings with RIPPLE_TRIGGER_CONTINUOUS will increment this to
|
|
|
|
//! 16777216 (1 << 24), at which point it will freeze (due to floating-point
|
|
|
|
//! imprecision?) and the painting will stop rippling. This happens to HMC, DDD, and
|
|
|
|
//! CotMC. This happens on Wii VC. Untested on N64 and Wii U VC.
|
|
|
|
}
|
|
|
|
if (painting->rippleTrigger == RIPPLE_TRIGGER_PROXIMITY) {
|
|
|
|
if (painting->currRippleMag <= 1.0) // if the painting is barely rippling, make it stop rippling
|
|
|
|
{
|
|
|
|
painting->rippleStatus = RIPPLE_STATE_NONE;
|
|
|
|
ripplingPainting = NULL;
|
|
|
|
}
|
|
|
|
} else if (painting->rippleTrigger == RIPPLE_TRIGGER_CONTINUOUS) {
|
|
|
|
|
|
|
|
if (painting->rippleStatus == RIPPLE_STATE_ENTRY
|
|
|
|
&& painting->currRippleMag
|
|
|
|
<= painting->passiveRippleMag) // if the painting is doing the entry ripple but the
|
|
|
|
// ripples are as small as those from the passive
|
|
|
|
// ripple, make it do a passive ripple
|
|
|
|
{
|
|
|
|
painting->rippleStatus = RIPPLE_STATE_IDLE;
|
|
|
|
painting->currRippleMag = painting->passiveRippleMag;
|
|
|
|
painting->rippleMagMultiplier = painting->passiveRippleMagMultiplier;
|
|
|
|
painting->currRippleRate = painting->passiveRippleRate;
|
|
|
|
painting->dispersionFactor = painting->passiveDispersionFactor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s16 painting_calculate_point_ripple(struct PaintingData *painting, float xpos,
|
|
|
|
float ypos) // note that xpos and ypos correspond to a point on the
|
|
|
|
// face of the painting, not actual axes
|
|
|
|
{
|
|
|
|
float rippleMag = painting->currRippleMag;
|
|
|
|
float rippleRate = painting->currRippleRate;
|
|
|
|
float dispersionFactor = painting->dispersionFactor;
|
|
|
|
float rippleTimer = painting->rippleTimer;
|
|
|
|
float hRippleSpot = painting->horizontalRippleSpot;
|
|
|
|
float vRippleSpot = painting->verticalRippleSpot;
|
|
|
|
float distanceToRippleSpot;
|
|
|
|
float scaledDistance;
|
|
|
|
|
|
|
|
xpos *= painting->vSize / DEFAULT_HEIGHT; // scale x position of point by painting size
|
|
|
|
ypos *= painting->vSize / DEFAULT_HEIGHT; // scale y position of point by painting size
|
|
|
|
distanceToRippleSpot =
|
|
|
|
sqrtf((xpos - hRippleSpot) * (xpos - hRippleSpot)
|
|
|
|
+ (ypos - vRippleSpot) * (ypos - vRippleSpot)); // distance from point to ripple spot
|
|
|
|
scaledDistance =
|
|
|
|
distanceToRippleSpot / dispersionFactor; // scale distance by dispersion factor so that ripples
|
|
|
|
// farther from the ripple spot are smaller
|
|
|
|
if (rippleTimer < scaledDistance) {
|
|
|
|
return 0; // if the ripple hasn't reached the point yet, make the point magnitude 0
|
|
|
|
} else {
|
|
|
|
|
|
|
|
float rippleHeight =
|
|
|
|
rippleMag
|
|
|
|
* cosf(rippleRate * (2 * M_PI)
|
|
|
|
* (rippleTimer
|
|
|
|
- scaledDistance)); // use a cosine wave to make the ripple go up and down, and
|
|
|
|
// scale it by the painting's ripple magnitude
|
|
|
|
|
|
|
|
return round_float(rippleHeight); // round it to an int and return it
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s16 painting_conditionally_calculate_point_ripple(struct PaintingData *painting, s16 condition,
|
|
|
|
s16 xpos, s16 ypos) {
|
|
|
|
s16 rippleHeight = 0;
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (condition) {
|
2019-08-25 04:46:40 +00:00
|
|
|
rippleHeight = painting_calculate_point_ripple(painting, xpos, ypos);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
return rippleHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Print1(struct PaintingData *painting, s16 *b, s16 c) {
|
|
|
|
s16 sp1E;
|
|
|
|
|
|
|
|
D_8035FFA0 = mem_pool_alloc(D_8033A124, c * sizeof(struct Thing));
|
|
|
|
if (D_8035FFA0 == NULL) {
|
|
|
|
}
|
|
|
|
for (sp1E = 0; sp1E < c; sp1E++) {
|
|
|
|
D_8035FFA0[sp1E].unk0[0] = b[sp1E * 3 + 1];
|
|
|
|
D_8035FFA0[sp1E].unk0[1] = b[sp1E * 3 + 2];
|
|
|
|
D_8035FFA0[sp1E].unk0[2] = painting_conditionally_calculate_point_ripple(
|
|
|
|
painting, b[(sp1E + 1) * 3], D_8035FFA0[sp1E].unk0[0], D_8035FFA0[sp1E].unk0[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Print2(s16 *a, s16 b, s16 c) {
|
|
|
|
s16 sp46;
|
|
|
|
|
|
|
|
D_8035FFA4 = mem_pool_alloc(D_8033A124, c * 12U); // TODO: Make use sizeof(struct)
|
|
|
|
if (D_8035FFA4 == NULL) {
|
|
|
|
}
|
|
|
|
for (sp46 = 0; sp46 < c; sp46++) {
|
|
|
|
s16 sp44 = b * 3 + sp46 * 3 + 2;
|
|
|
|
s16 sp42 = a[sp44];
|
|
|
|
s16 sp40 = a[sp44 + 1];
|
|
|
|
s16 sp3E = a[sp44 + 2];
|
|
|
|
f32 sp38 = D_8035FFA0[sp42].unk0[0];
|
|
|
|
f32 sp34 = D_8035FFA0[sp42].unk0[1];
|
|
|
|
f32 sp30 = D_8035FFA0[sp42].unk0[2];
|
|
|
|
f32 sp2C = D_8035FFA0[sp40].unk0[0];
|
|
|
|
f32 sp28 = D_8035FFA0[sp40].unk0[1];
|
|
|
|
f32 sp24 = D_8035FFA0[sp40].unk0[2];
|
|
|
|
f32 sp20 = D_8035FFA0[sp3E].unk0[0];
|
|
|
|
f32 sp1C = D_8035FFA0[sp3E].unk0[1];
|
|
|
|
f32 sp18 = D_8035FFA0[sp3E].unk0[2];
|
|
|
|
|
|
|
|
D_8035FFA4[sp46][0] = (sp28 - sp34) * (sp18 - sp24) - (sp24 - sp30) * (sp1C - sp28);
|
|
|
|
D_8035FFA4[sp46][1] = (sp24 - sp30) * (sp20 - sp2C) - (sp2C - sp38) * (sp18 - sp24);
|
|
|
|
D_8035FFA4[sp46][2] = (sp2C - sp38) * (sp1C - sp28) - (sp28 - sp34) * (sp20 - sp2C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s8 small_float_to_byte(float decimal) // This function converts a decimal to a signed byte by
|
|
|
|
// multiplying it by 127 or 128 and rounding away from 0.
|
|
|
|
{
|
|
|
|
s8 convertedFloat;
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (decimal > 0.0) {
|
2019-08-25 04:46:40 +00:00
|
|
|
convertedFloat = decimal * 127.0 + 0.5; // round up
|
2019-09-01 19:50:50 +00:00
|
|
|
} else if (decimal < 0.0) {
|
2019-08-25 04:46:40 +00:00
|
|
|
convertedFloat = decimal * 128.0 - 0.5; // round down
|
2019-09-01 19:50:50 +00:00
|
|
|
} else {
|
2019-08-25 04:46:40 +00:00
|
|
|
convertedFloat = 0; // don't round 0
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
return convertedFloat;
|
|
|
|
}
|
|
|
|
|
|
|
|
void func_802D39DC(s16 *a, s16 b) {
|
|
|
|
UNUSED s16 unused;
|
|
|
|
s16 sp34;
|
|
|
|
s16 index;
|
|
|
|
s16 index2;
|
|
|
|
s16 sp2E;
|
|
|
|
s16 sp2C = 0;
|
|
|
|
|
|
|
|
for (index = 0; index < b; index++) {
|
|
|
|
f32 sp28 = 0.0f;
|
|
|
|
f32 sp24 = 0.0f;
|
|
|
|
f32 sp20 = 0.0f;
|
|
|
|
f32 sp1C;
|
|
|
|
|
|
|
|
sp2E = a[sp2C];
|
|
|
|
for (index2 = 0; index2 < sp2E; index2++) {
|
|
|
|
sp34 = a[sp2C + index2 + 1];
|
|
|
|
sp28 += D_8035FFA4[sp34][0];
|
|
|
|
sp24 += D_8035FFA4[sp34][1];
|
|
|
|
sp20 += D_8035FFA4[sp34][2];
|
|
|
|
}
|
|
|
|
sp2C += sp2E + 1;
|
|
|
|
sp28 /= sp2E;
|
|
|
|
sp24 /= sp2E;
|
|
|
|
sp20 /= sp2E;
|
|
|
|
sp1C = sqrtf(sp28 * sp28 + sp24 * sp24 + sp20 * sp20);
|
|
|
|
if (sp1C == 0.0) {
|
|
|
|
D_8035FFA0[index].unk6[0] = 0;
|
|
|
|
D_8035FFA0[index].unk6[1] = 0;
|
|
|
|
D_8035FFA0[index].unk6[2] = 0;
|
|
|
|
} else {
|
|
|
|
D_8035FFA0[index].unk6[0] = small_float_to_byte(sp28 / sp1C);
|
|
|
|
D_8035FFA0[index].unk6[1] = small_float_to_byte(sp24 / sp1C);
|
|
|
|
D_8035FFA0[index].unk6[2] = small_float_to_byte(sp20 / sp1C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void *func_802D3CF0(u8 *img, s16 b, s16 c, s16 *d, s16 e, s16 f, u8 g) {
|
|
|
|
s16 sp9E;
|
|
|
|
s16 sp9C;
|
|
|
|
s16 sp9A;
|
|
|
|
s16 sp98;
|
|
|
|
s16 sp96;
|
|
|
|
s16 tx;
|
|
|
|
s16 ty;
|
|
|
|
s16 sp90 = f / 5;
|
|
|
|
s16 sp8E = f % 5;
|
|
|
|
s16 sp8C = f * 3;
|
|
|
|
s16 sp8A = sp90 * 2 + sp8E + 7;
|
|
|
|
Vtx *verts = alloc_display_list(sp8C * sizeof(*verts));
|
|
|
|
Gfx *sp80 = alloc_display_list(sp8A * sizeof(*sp80));
|
|
|
|
Gfx *sp7C = sp80;
|
|
|
|
|
|
|
|
if (verts == NULL || sp80 == NULL) {
|
|
|
|
}
|
|
|
|
|
|
|
|
gDPSetTextureImage(sp7C++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, img);
|
|
|
|
gDPTileSync(sp7C++);
|
|
|
|
gDPSetTile(sp7C++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, 7, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK,
|
|
|
|
G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD);
|
|
|
|
gDPLoadSync(sp7C++);
|
|
|
|
gDPLoadBlock(sp7C++, 7, 0, 0, b * c - 1, (MAX(1, b * 2 / 8) + 2047) / MAX(1, b * 2 / 8));
|
|
|
|
|
|
|
|
for (sp9E = 0; sp9E < sp90; sp9E++) {
|
|
|
|
sp9A = e * 3 + sp9E * 15 + 2;
|
|
|
|
for (sp9C = 0; sp9C < 15; sp9C++) {
|
|
|
|
sp98 = d[sp9A + sp9C];
|
|
|
|
sp96 = d[sp98 * 3 + 1];
|
|
|
|
tx = d[sp98 * 3 + 2];
|
|
|
|
ty = d[sp98 * 3 + 3];
|
|
|
|
make_vertex(verts, sp9E * 15 + sp9C, D_8035FFA0[sp96].unk0[0], D_8035FFA0[sp96].unk0[1],
|
|
|
|
D_8035FFA0[sp96].unk0[2], tx, ty, D_8035FFA0[sp96].unk6[0],
|
|
|
|
D_8035FFA0[sp96].unk6[1], D_8035FFA0[sp96].unk6[2], g);
|
|
|
|
}
|
|
|
|
gSPVertex(sp7C++, VIRTUAL_TO_PHYSICAL(verts + sp9E * 15), 15, 0);
|
|
|
|
gSPDisplayList(sp7C++, dl_paintings_draw_ripples);
|
|
|
|
}
|
|
|
|
|
|
|
|
sp9A = e * 3 + sp90 * 15 + 2;
|
|
|
|
for (sp9C = 0; sp9C < sp8E * 3; sp9C++) {
|
|
|
|
sp98 = d[sp9A + sp9C];
|
|
|
|
sp96 = d[sp98 * 3 + 1];
|
|
|
|
tx = d[sp98 * 3 + 2];
|
|
|
|
ty = d[sp98 * 3 + 3];
|
|
|
|
make_vertex(verts, sp90 * 15 + sp9C, D_8035FFA0[sp96].unk0[0], D_8035FFA0[sp96].unk0[1],
|
|
|
|
D_8035FFA0[sp96].unk0[2], tx, ty, D_8035FFA0[sp96].unk6[0],
|
|
|
|
D_8035FFA0[sp96].unk6[1], D_8035FFA0[sp96].unk6[2], g);
|
|
|
|
}
|
|
|
|
gSPVertex(sp7C++, VIRTUAL_TO_PHYSICAL(verts + sp90 * 15), sp8E * 3, 0);
|
|
|
|
for (sp9E = 0; sp9E < sp8E; sp9E++)
|
|
|
|
gSP1Triangle(sp7C++, sp9E * 3, sp9E * 3 + 1, sp9E * 3 + 2, 0);
|
|
|
|
gSPEndDisplayList(sp7C);
|
|
|
|
return sp80;
|
|
|
|
}
|
|
|
|
|
|
|
|
Gfx *func_802D43FC(struct PaintingData *painting) {
|
|
|
|
float sp4C = painting->vSize / DEFAULT_HEIGHT;
|
|
|
|
void *sp48 = alloc_display_list(64);
|
|
|
|
void *sp44 = alloc_display_list(64);
|
|
|
|
void *sp40 = alloc_display_list(64);
|
|
|
|
void *sp3C = alloc_display_list(64);
|
|
|
|
void *sp38 = alloc_display_list(40);
|
|
|
|
Gfx *sp34 = sp38;
|
|
|
|
|
|
|
|
if (sp48 == NULL || sp44 == NULL || sp40 == NULL || sp38 == NULL) {
|
|
|
|
}
|
|
|
|
|
|
|
|
guTranslate(sp40, painting->vXPos, painting->vYPos, painting->vZPos);
|
|
|
|
guRotate(sp48, painting->vXRotation, 1.0f, 0.0f, 0.0f);
|
|
|
|
guRotate(sp44, painting->vYRotation, 0.0f, 1.0f, 0.0f);
|
|
|
|
guScale(sp3C, sp4C, sp4C, sp4C);
|
|
|
|
|
|
|
|
gSPMatrix(sp34++, sp40, G_MTX_MODELVIEW | G_MTX_PUSH);
|
|
|
|
gSPMatrix(sp34++, sp48, G_MTX_MODELVIEW | G_MTX_MUL);
|
|
|
|
gSPMatrix(sp34++, sp44, G_MTX_MODELVIEW | G_MTX_MUL);
|
|
|
|
gSPMatrix(sp34++, sp3C, G_MTX_MODELVIEW | G_MTX_MUL);
|
|
|
|
gSPEndDisplayList(sp34);
|
|
|
|
|
|
|
|
return sp38;
|
|
|
|
}
|
|
|
|
|
|
|
|
Gfx *func_802D45FC(struct PaintingData *painting) {
|
|
|
|
s16 sp66;
|
|
|
|
s16 sp64;
|
|
|
|
s16 sp62;
|
|
|
|
s16 *sp5C;
|
|
|
|
s16 faceCount = painting->faceCount;
|
|
|
|
s16 tWidth = painting->textureWidth;
|
|
|
|
s16 tHeight = painting->textureHeight;
|
|
|
|
s16 **meshArray = segmented_to_virtual(painting->meshData);
|
|
|
|
u8 **tArray = segmented_to_virtual(painting->textureArray);
|
|
|
|
Gfx *sp48 = alloc_display_list(faceCount * 8 + 48);
|
|
|
|
Gfx *sp44 = sp48;
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (sp48 == NULL) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return sp48;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
|
|
|
gSPDisplayList(sp44++, func_802D43FC(painting));
|
|
|
|
gSPDisplayList(sp44++, dl_paintings_rippling_begin);
|
|
|
|
gSPDisplayList(sp44++, painting->displayList68);
|
|
|
|
|
|
|
|
for (sp62 = 0; sp62 < faceCount; sp62++) {
|
|
|
|
sp5C = segmented_to_virtual(meshArray[sp62]);
|
|
|
|
sp66 = sp5C[0];
|
|
|
|
sp64 = sp5C[sp66 * 3 + 1];
|
|
|
|
gSPDisplayList(sp44++, func_802D3CF0(tArray[sp62], tWidth, tHeight, sp5C, sp66, sp64,
|
|
|
|
painting->brightness));
|
|
|
|
}
|
|
|
|
painting_update_ripple_status(painting);
|
|
|
|
gSPPopMatrix(sp44++, G_MTX_MODELVIEW);
|
|
|
|
gSPDisplayList(sp44++, dl_paintings_rippling_end);
|
|
|
|
gSPEndDisplayList(sp44);
|
|
|
|
return sp48;
|
|
|
|
}
|
|
|
|
|
|
|
|
Gfx *func_802D4874(struct PaintingData *painting) {
|
|
|
|
s16 sp5E;
|
|
|
|
s16 sp5C;
|
|
|
|
s16 *sp58;
|
|
|
|
s16 tWidth = painting->textureWidth;
|
|
|
|
s16 tHeight = painting->textureHeight;
|
|
|
|
s16 **meshArray = segmented_to_virtual(painting->meshData);
|
|
|
|
u8 **tArray = segmented_to_virtual(painting->textureArray);
|
|
|
|
Gfx *sp48 = alloc_display_list(56);
|
|
|
|
Gfx *sp44 = sp48;
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (sp48 == NULL) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return sp48;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
|
|
|
|
gSPDisplayList(sp44++, func_802D43FC(painting));
|
|
|
|
gSPDisplayList(sp44++, dl_paintings_env_mapped_begin);
|
|
|
|
gSPDisplayList(sp44++, painting->displayList68);
|
|
|
|
sp58 = segmented_to_virtual(meshArray[0]);
|
|
|
|
sp5E = sp58[0];
|
|
|
|
sp5C = sp58[sp5E * 3 + 1];
|
|
|
|
gSPDisplayList(sp44++,
|
|
|
|
func_802D3CF0(tArray[0], tWidth, tHeight, sp58, sp5E, sp5C, painting->brightness));
|
|
|
|
painting_update_ripple_status(painting);
|
|
|
|
gSPPopMatrix(sp44++, G_MTX_MODELVIEW);
|
|
|
|
gSPDisplayList(sp44++, dl_paintings_env_mapped_end);
|
|
|
|
gSPEndDisplayList(sp44);
|
|
|
|
return sp48;
|
|
|
|
}
|
|
|
|
|
|
|
|
Gfx *display_painting_rippling(struct PaintingData *painting) {
|
|
|
|
s16 *sp34 = segmented_to_virtual(seg2_triangle_mesh);
|
|
|
|
s16 *sp30 = segmented_to_virtual(seg2_mesh_order);
|
|
|
|
s16 sp2E = sp34[0];
|
|
|
|
s16 sp2C = sp34[sp2E * 3 + 1];
|
|
|
|
Gfx *sp28;
|
|
|
|
|
|
|
|
Print1(painting, sp34, sp2E);
|
|
|
|
Print2(sp34, sp2E, sp2C);
|
|
|
|
func_802D39DC(sp30, sp2E);
|
|
|
|
switch (painting->rippleShape) {
|
|
|
|
case RIPPLE_SHAPE_WAVE:
|
|
|
|
sp28 = func_802D45FC(painting);
|
|
|
|
break;
|
|
|
|
case RIPPLE_SHAPE_CONCENTRIC:
|
|
|
|
sp28 = func_802D4874(painting);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mem_pool_free(D_8033A124, D_8035FFA0);
|
|
|
|
mem_pool_free(D_8033A124, D_8035FFA4);
|
|
|
|
return sp28;
|
|
|
|
}
|
|
|
|
|
|
|
|
Gfx *display_painting_not_rippling(struct PaintingData *painting) {
|
|
|
|
Gfx *sp2C = alloc_display_list(32);
|
|
|
|
Gfx *sp28 = sp2C;
|
|
|
|
|
2019-09-01 19:50:50 +00:00
|
|
|
if (sp2C == NULL) {
|
2019-08-25 04:46:40 +00:00
|
|
|
return sp2C;
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
gSPDisplayList(sp28++, func_802D43FC(painting));
|
|
|
|
gSPDisplayList(sp28++, painting->displayList58);
|
|
|
|
gSPPopMatrix(sp28++, G_MTX_MODELVIEW);
|
|
|
|
gSPEndDisplayList(sp28);
|
|
|
|
return sp2C;
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset_painting(struct PaintingData *painting) {
|
|
|
|
painting->lastFloor = 0;
|
|
|
|
painting->currFloor = 0;
|
|
|
|
painting->floorEntered = 0;
|
|
|
|
painting->lastMarioUnderPainting = 0;
|
|
|
|
painting->currMarioUnderPainting = 0;
|
|
|
|
painting->marioNewlyUnderPainting = 0;
|
|
|
|
ripplingPainting = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void update_ddd_painting(struct PaintingData *painting, float frontPos, float backPos,
|
|
|
|
float speed) // Tells the DDD painting whether to move back
|
|
|
|
{
|
|
|
|
u32 dddFlags = save_file_get_star_flags(gCurrSaveFileNum - 1,
|
|
|
|
DIRE_DIRE_DOCKS - 1); // Obtain the DDD star flags
|
|
|
|
u32 saveFileFlags = save_file_get_flags(); // Get the other save file flags
|
|
|
|
u32 bowsersSubBeaten =
|
|
|
|
dddFlags & BOARD_BOWSERS_SUB; // Find out whether Board Bowser's Sub was collected
|
|
|
|
u32 dddBack = saveFileFlags & SAVE_FLAG_DDD_MOVED_BACK; // Check whether DDD has already moved back
|
|
|
|
|
|
|
|
if (!bowsersSubBeaten && !dddBack) {
|
|
|
|
painting->vXPos = frontPos; // If we haven't collected the star or moved the painting, put the
|
|
|
|
// painting at the front
|
|
|
|
dddStatus = 0;
|
|
|
|
} else if (bowsersSubBeaten
|
|
|
|
&& !dddBack) // If we've collected the star but not moved the painting back,
|
|
|
|
{
|
|
|
|
painting->vXPos +=
|
|
|
|
speed; // Each frame, move the painting by a certain speed towards the back area.
|
|
|
|
dddStatus = BOWSERS_SUB_BEATEN;
|
|
|
|
if (painting->vXPos >= backPos) {
|
|
|
|
painting->vXPos = backPos;
|
|
|
|
save_file_set_flags(
|
|
|
|
SAVE_FLAG_DDD_MOVED_BACK); // Tell the save file that we've moved DDD back.
|
|
|
|
}
|
|
|
|
} else if (bowsersSubBeaten && dddBack) {
|
|
|
|
painting->vXPos =
|
|
|
|
backPos; // If the painting has already moved back, place it in the back position.
|
|
|
|
dddStatus = BOWSERS_SUB_BEATEN | DDD_BACK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Struct802D4E04 {
|
|
|
|
u8 filler0[2];
|
|
|
|
s16 unk2;
|
|
|
|
u8 filler4[20];
|
|
|
|
u32 unk18; // the upper half is the painting's id
|
|
|
|
};
|
|
|
|
|
|
|
|
void func_802D4E04(struct GraphNodeGenerated *a, struct PaintingData *b) {
|
|
|
|
switch (b->brightness) {
|
|
|
|
case 0xFF: // brightest
|
|
|
|
a->fnNode.node.flags = (a->fnNode.node.flags & 0xFF) | 0x100;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
a->fnNode.node.flags = (a->fnNode.node.flags & 0xFF) | 0x500;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Gfx *display_painting(struct PaintingData *painting) {
|
|
|
|
switch (painting->rippleStatus) {
|
|
|
|
case RIPPLE_STATE_NONE:
|
|
|
|
return display_painting_not_rippling(painting);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return display_painting_rippling(painting);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void vertical_painting_ripple(struct PaintingData *painting, struct PaintingData *paintingGroup[]) {
|
|
|
|
if (painting->rippleTrigger
|
|
|
|
== RIPPLE_TRIGGER_PROXIMITY) // make the painting ripple using a different function based on its
|
|
|
|
// ripple trigger and status
|
|
|
|
{
|
|
|
|
switch (painting->rippleStatus) {
|
|
|
|
case RIPPLE_STATE_NONE:
|
|
|
|
vertical_proximity_ripple_painting_ripple(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
case RIPPLE_STATE_IDLE:
|
|
|
|
vertical_proximity_ripple_painting_ripple_if_mario_enters(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (painting->rippleTrigger == RIPPLE_TRIGGER_CONTINUOUS) {
|
|
|
|
switch (painting->rippleStatus) {
|
|
|
|
case RIPPLE_STATE_NONE:
|
|
|
|
vertical_continuous_ripple_painting_ripple(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
case RIPPLE_STATE_IDLE:
|
|
|
|
vertical_continuous_ripple_painting_ripple_if_mario_enters(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void horizontal_painting_ripple(struct PaintingData *painting, struct PaintingData *paintingGroup[]) {
|
|
|
|
if (painting->rippleTrigger
|
|
|
|
== RIPPLE_TRIGGER_PROXIMITY) // make the painting ripple using a different function based on its
|
|
|
|
// ripple trigger and status
|
|
|
|
{
|
|
|
|
switch (painting->rippleStatus) // No horizontal proximity ripple paintings exist in-game.
|
|
|
|
{
|
|
|
|
case RIPPLE_STATE_NONE:
|
|
|
|
horizontal_proximity_ripple_painting_ripple(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
case RIPPLE_STATE_IDLE:
|
|
|
|
horizontal_proximity_ripple_painting_ripple_if_mario_enters(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (painting->rippleTrigger == RIPPLE_TRIGGER_CONTINUOUS) {
|
|
|
|
switch (painting->rippleStatus) {
|
|
|
|
case RIPPLE_STATE_NONE:
|
|
|
|
horizontal_continuous_ripple_painting_ripple(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
case RIPPLE_STATE_IDLE:
|
|
|
|
horizontal_continuous_ripple_painting_ripple_if_mario_enters(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Gfx *Geo18_802D5B98(s32 run, struct GraphNode *node, UNUSED s32 c) {
|
|
|
|
struct GraphNodeGenerated *sp2C = (struct GraphNodeGenerated *) node;
|
|
|
|
s32 sp28 = (sp2C->parameter >> 8) & 0xFF;
|
|
|
|
s32 id = sp2C->parameter & 0xFF;
|
|
|
|
Gfx *sp20 = NULL;
|
|
|
|
struct PaintingData **paintingGroup = paintingGroups[sp28];
|
|
|
|
struct PaintingData *painting = segmented_to_virtual(paintingGroup[id]);
|
|
|
|
|
|
|
|
if (run != TRUE) {
|
|
|
|
reset_painting(painting);
|
|
|
|
} else if (run == TRUE) // because the extra comparison was really necessary...
|
|
|
|
{
|
2019-09-01 19:50:50 +00:00
|
|
|
if (sp28 == 1 && id == PAINTING_ID_DDD) { // painting is DDD painting
|
2019-08-25 04:46:40 +00:00
|
|
|
update_ddd_painting(painting, 3456.0f, 5529.6f, 20.0f);
|
2019-09-01 19:50:50 +00:00
|
|
|
}
|
2019-08-25 04:46:40 +00:00
|
|
|
func_802D4E04(sp2C, painting);
|
|
|
|
sp20 = display_painting(painting);
|
|
|
|
painting_update_floors(painting);
|
|
|
|
switch ((s16) painting->vXRotation) {
|
|
|
|
case ROTATION_VERTICAL:
|
|
|
|
vertical_painting_ripple(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
horizontal_painting_ripple(painting, paintingGroup);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sp20;
|
|
|
|
}
|
|
|
|
|
|
|
|
Gfx *Geo18_802D5D0C(s32 run, UNUSED struct GraphNode *node, UNUSED f32 c[4][4]) {
|
|
|
|
struct Surface *surface;
|
|
|
|
|
|
|
|
if (run != TRUE) {
|
|
|
|
gLastPaintingUpdateCounter = gAreaUpdateCounter - 1;
|
|
|
|
gPaintingUpdateCounter = gAreaUpdateCounter;
|
|
|
|
} else {
|
|
|
|
gLastPaintingUpdateCounter = gPaintingUpdateCounter;
|
|
|
|
gPaintingUpdateCounter = gAreaUpdateCounter;
|
|
|
|
find_floor(gMarioObject->oPosX, gMarioObject->oPosY, gMarioObject->oPosZ, &surface);
|
|
|
|
gPaintingMarioFloorType = surface->type;
|
|
|
|
gPaintingMarioXPos = gMarioObject->oPosX;
|
|
|
|
gPaintingMarioYPos = gMarioObject->oPosY;
|
|
|
|
gPaintingMarioZPos = gMarioObject->oPosZ;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|