Refresh 11

This commit is contained in:
n64 2020-07-04 11:18:55 -04:00 committed by fgsfds
parent dd873771cf
commit 6330644371
46 changed files with 486 additions and 287 deletions

11
CHANGES
View File

@ -1,3 +1,14 @@
Refresh 11
1.) (HEAD -> master, origin/master, origin/HEAD) Make geo_process_level_of_detail endian-independent (#1049)
2.) Label oMoveFlags and slight cleanup. (#1046)
3.) Avoid UB in synthesis_resample_and_mix_reverb (#1048)
4.) Change some void * to correct type (#1047)
5.) Remove oPathedWaypointsS16 and convert all paths to Trajectory struct. (#1045)
6.) Mr Blizzard documentation, Tox Box Unks (#1042)
7.) Pipe input to textconv. (#1041)
8.) Remove erroneous long double casts from audiofile.cpp (#1039)
9.) Replace fixed dialogID in play_dialog_sound to DIALOG_COUNT (#1040)
Refresh #10.1
1.) Diff update (#1033)
2.) Fix texture dimensions for exclamation boxes (#1034)

View File

@ -766,12 +766,10 @@ endif
endif
$(BUILD_DIR)/text/%/define_courses.inc.c: text/define_courses.inc.c text/%/courses.h
$(CPP) $(VERSION_CFLAGS) $< -o $@ -I text/$*/
$(TEXTCONV) charmap.txt $@ $@
$(CPP) $(VERSION_CFLAGS) $< -o - -I text/$*/ | $(TEXTCONV) charmap.txt - $@
$(BUILD_DIR)/text/%/define_text.inc.c: text/define_text.inc.c text/%/courses.h text/%/dialogs.h
$(CPP) $(VERSION_CFLAGS) $< -o $@ -I text/$*/
$(TEXTCONV) charmap.txt $@ $@
$(CPP) $(VERSION_CFLAGS) $< -o - -I text/$*/ | $(TEXTCONV) charmap.txt - $@
RSP_DIRS := $(BUILD_DIR)/rsp
ALL_DIRS := $(BUILD_DIR) $(addprefix $(BUILD_DIR)/,$(SRC_DIRS) $(ASM_DIRS) $(GODDARD_SRC_DIRS) $(ULTRA_SRC_DIRS) $(ULTRA_ASM_DIRS) $(ULTRA_BIN_DIRS) $(BIN_DIRS) $(TEXTURE_DIRS) $(TEXT_DIRS) $(SOUND_SAMPLE_DIRS) $(addprefix levels/,$(LEVEL_DIRS)) include) $(MIO0_DIR) $(addprefix $(MIO0_DIR)/,$(VERSION)) $(SOUND_BIN_DIR) $(SOUND_BIN_DIR)/sequences/$(VERSION) $(RSP_DIRS)

View File

@ -80,30 +80,22 @@
#define OBJ_MOVE_UNDERWATER_OFF_GROUND (1 << 5) // 0x0020
#define OBJ_MOVE_UNDERWATER_ON_GROUND (1 << 6) // 0x0040
#define OBJ_MOVE_IN_AIR (1 << 7) // 0x0080
#define OBJ_MOVE_8 (1 << 8) // 0x0100
#define OBJ_MOVE_OUT_SCOPE (1 << 8) // 0x0100
#define OBJ_MOVE_HIT_WALL (1 << 9) // 0x0200
#define OBJ_MOVE_HIT_EDGE (1 << 10) // 0x0400
#define OBJ_MOVE_ABOVE_LAVA (1 << 11) // 0x0800
#define OBJ_MOVE_LEAVING_WATER (1 << 12) // 0x1000
#define OBJ_MOVE_13 (1 << 13) // 0x2000
#define OBJ_MOVE_BOUNCE (1 << 13) // 0x2000
#ifndef VERSION_JP
#define OBJ_MOVE_ABOVE_DEATH_BARRIER (1 << 14) // 0x4000
#endif
#define OBJ_MOVE_MASK_ON_GROUND (OBJ_MOVE_LANDED | OBJ_MOVE_ON_GROUND)
#define OBJ_MOVE_MASK_33 0x33
#define OBJ_MOVE_MASK_IN_WATER (\
OBJ_MOVE_ENTERED_WATER |\
OBJ_MOVE_AT_WATER_SURFACE |\
OBJ_MOVE_UNDERWATER_OFF_GROUND |\
OBJ_MOVE_UNDERWATER_ON_GROUND)
#define OBJ_MOVE_MASK_HIT_WALL_OR_IN_WATER \
(OBJ_MOVE_HIT_WALL | OBJ_MOVE_MASK_IN_WATER)
#define OBJ_MOVE_MASK_NOT_AIR (\
OBJ_MOVE_LANDED |\
OBJ_MOVE_ON_GROUND |\
OBJ_MOVE_AT_WATER_SURFACE |\
OBJ_MOVE_UNDERWATER_ON_GROUND)
/* oActiveParticleFlags */
#define ACTIVE_PARTICLE_DUST (1 << 0) // 0x00000001
@ -971,4 +963,18 @@
#define BOWSER_PUZZLE_ACT_WAIT_FOR_COMPLETE 1
#define BOWSER_PUZZLE_ACT_DONE 2
/* Mr Blizzard */
/* oAction */
#define MR_BLIZZARD_ACT_SPAWN_SNOWBALL 0
#define MR_BLIZZARD_ACT_HIDE_UNHIDE 1
#define MR_BLIZZARD_ACT_RISE_FROM_GROUND 2
#define MR_BLIZZARD_ACT_ROTATE 3
#define MR_BLIZZARD_ACT_THROW_SNOWBALL 4
#define MR_BLIZZARD_ACT_BURROW 5
#define MR_BLIZZARD_ACT_DEATH 6
#define MR_BLIZZARD_ACT_JUMP 7
/* oBehParams2ndByte */
#define MR_BLIZZARD_STYPE_NO_CAP 0
#define MR_BLIZZARD_STYPE_JUMPING 1
#endif // OBJECT_CONSTANTS_H

View File

@ -136,8 +136,6 @@
#define /*0x1C4*/ oDeathSound OBJECT_FIELD_S32(0x4F)
/* Pathed (see obj_follow_path) */
// TODO: These two 0x0FC fields need merged, one is data and one is a C struct.
#define /*0x0FC*/ oPathedWaypointsS16 OBJECT_FIELD_VPTR(0x1D)
#define /*0x0FC*/ oPathedStartWaypoint OBJECT_FIELD_WAYPOINT(0x1D)
#define /*0x100*/ oPathedPrevWaypoint OBJECT_FIELD_WAYPOINT(0x1E)
#define /*0x104*/ oPathedPrevWaypointFlags OBJECT_FIELD_S32(0x1F)
@ -966,8 +964,8 @@
#define /*0x110*/ oToadMessageState OBJECT_FIELD_S32(0x22)
/* Tox Box */
#define /*0x1AC*/ oToxBoxUnk1AC OBJECT_FIELD_VPTR(0x49)
#define /*0x1B0*/ oToxBoxUnk1B0 OBJECT_FIELD_S32(0x4A)
#define /*0x1AC*/ oToxBoxMovementPattern OBJECT_FIELD_VPTR(0x49)
#define /*0x1B0*/ oToxBoxMovementStep OBJECT_FIELD_S32(0x4A)
/* TTC Rotating Solid */
#define /*0x0F4*/ oTTCRotatingSolidNumTurns OBJECT_FIELD_S32(0x1B)

View File

@ -131,7 +131,7 @@ struct GraphNodeObject
/*0x2C*/ Vec3f scale;
/*0x38*/ struct GraphNodeObject_sub unk38;
/*0x4C*/ struct SpawnInfo *unk4C;
/*0x50*/ void *throwMatrix; // matrix ptr
/*0x50*/ Mat4 *throwMatrix; // matrix ptr
/*0x54*/ Vec3f cameraToObject;
};

View File

@ -2035,7 +2035,7 @@ void func_80320A4C(u8 bankIndex, u8 arg1) {
void play_dialog_sound(u8 dialogID) {
u8 speaker;
if (dialogID >= 170) {
if (dialogID >= DIALOG_COUNT) {
dialogID = 0;
}

View File

@ -11,8 +11,8 @@
#define DMEM_ADDR_TEMP 0x0
#define DMEM_ADDR_UNCOMPRESSED_NOTE 0x180
#define DMEM_ADDR_ADPCM_RESAMPLED 0x20
#define DMEM_ADDR_ADPCM_RESAMPLED2 0x160
#define DMEM_ADDR_RESAMPLED 0x20
#define DMEM_ADDR_RESAMPLED2 0x160
#define DMEM_ADDR_NOTE_PAN_TEMP 0x200
#define DMEM_ADDR_STEREO_STRONG_TEMP_DRY 0x200
#define DMEM_ADDR_STEREO_STRONG_TEMP_WET 0x340
@ -100,14 +100,14 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex, s32 reverbIndex)
// Touches both left and right since they are adjacent in memory
osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
for (srcPos = 0, dstPos = 0; dstPos < item->lengths[0] / 2;
for (srcPos = 0, dstPos = 0; dstPos < item->lengthA / 2;
srcPos += reverb->downsampleRate, dstPos++) {
reverb->ringBuffer.left[item->startPos + dstPos] =
item->toDownsampleLeft[srcPos];
reverb->ringBuffer.right[item->startPos + dstPos] =
item->toDownsampleRight[srcPos];
}
for (dstPos = 0; dstPos < item->lengths[1] / 2; srcPos += reverb->downsampleRate, dstPos++) {
for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += reverb->downsampleRate, dstPos++) {
reverb->ringBuffer.left[dstPos] = item->toDownsampleLeft[srcPos];
reverb->ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos];
}
@ -119,14 +119,14 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex, s32 reverbIndex)
excessiveSamples = (nSamples + reverb->nextRingBufferPos) - reverb->bufSizePerChannel;
if (excessiveSamples < 0) {
// There is space in the ring buffer before it wraps around
item->lengths[0] = nSamples * 2;
item->lengths[1] = 0;
item->lengthA = nSamples * 2;
item->lengthB = 0;
item->startPos = (s32) reverb->nextRingBufferPos;
reverb->nextRingBufferPos += nSamples;
} else {
// Ring buffer wrapped around
item->lengths[0] = (nSamples - excessiveSamples) * 2;
item->lengths[1] = excessiveSamples * 2;
item->lengthA = (nSamples - excessiveSamples) * 2;
item->lengthB = excessiveSamples * 2;
item->startPos = reverb->nextRingBufferPos;
reverb->nextRingBufferPos = excessiveSamples;
}
@ -151,14 +151,14 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) {
// Touches both left and right since they are adjacent in memory
osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
for (srcPos = 0, dstPos = 0; dstPos < item->lengths[0] / 2;
for (srcPos = 0, dstPos = 0; dstPos < item->lengthA / 2;
srcPos += gReverbDownsampleRate, dstPos++) {
gSynthesisReverb.ringBuffer.left[dstPos + item->startPos] =
item->toDownsampleLeft[srcPos];
gSynthesisReverb.ringBuffer.right[dstPos + item->startPos] =
item->toDownsampleRight[srcPos];
}
for (dstPos = 0; dstPos < item->lengths[1] / 2; srcPos += gReverbDownsampleRate, dstPos++) {
for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += gReverbDownsampleRate, dstPos++) {
gSynthesisReverb.ringBuffer.left[dstPos] = item->toDownsampleLeft[srcPos];
gSynthesisReverb.ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos];
}
@ -169,8 +169,8 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) {
numSamplesAfterDownsampling = chunkLen / gReverbDownsampleRate;
if (((numSamplesAfterDownsampling + gSynthesisReverb.nextRingBufferPos) - gSynthesisReverb.bufSizePerChannel) < 0) {
// There is space in the ring buffer before it wraps around
item->lengths[0] = numSamplesAfterDownsampling * 2;
item->lengths[1] = 0;
item->lengthA = numSamplesAfterDownsampling * 2;
item->lengthB = 0;
item->startPos = (s32) gSynthesisReverb.nextRingBufferPos;
gSynthesisReverb.nextRingBufferPos += numSamplesAfterDownsampling;
} else {
@ -178,8 +178,8 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) {
excessiveSamples =
(numSamplesAfterDownsampling + gSynthesisReverb.nextRingBufferPos) - gSynthesisReverb.bufSizePerChannel;
nSamples = numSamplesAfterDownsampling - excessiveSamples;
item->lengths[0] = nSamples * 2;
item->lengths[1] = excessiveSamples * 2;
item->lengthA = nSamples * 2;
item->lengthB = excessiveSamples * 2;
item->startPos = gSynthesisReverb.nextRingBufferPos;
gSynthesisReverb.nextRingBufferPos = excessiveSamples;
}
@ -349,33 +349,33 @@ u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
#ifdef VERSION_EU
u64 *synthesis_resample_and_mix_reverb(u64 *cmd, s32 bufLen, s16 reverbIndex, s16 updateIndex) {
struct ReverbRingBufferItem *item;
s16 temp_t9; // sp5a
s16 sp58; // sp58
s16 startPad;
s16 paddedLengthA;
item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
aClearBuffer(cmd++, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
if (gSynthesisReverbs[reverbIndex].downsampleRate == 1) {
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengths[0], reverbIndex);
if (item->lengths[1] != 0) {
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengths[0], 0, item->lengths[1], reverbIndex);
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
if (item->lengthB != 0) {
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
}
aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
aMix(cmd++, 0, 0x7fff, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH);
aMix(cmd++, 0, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH);
} else {
temp_t9 = (item->startPos % 8u) * 2;
sp58 = ALIGN(item->lengths[0] + (sp58=temp_t9), 4);
startPad = (item->startPos % 8u) * 2;
paddedLengthA = ALIGN(startPad + item->lengthA, 4);
cmd = synthesis_load_reverb_ring_buffer(cmd, 0x20, (item->startPos - temp_t9 / 2), DEFAULT_LEN_1CH, reverbIndex);
if (item->lengths[1] != 0) {
cmd = synthesis_load_reverb_ring_buffer(cmd, 0x20 + sp58, 0, DEFAULT_LEN_1CH - sp58, reverbIndex);
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, (item->startPos - startPad / 2), DEFAULT_LEN_1CH, reverbIndex);
if (item->lengthB != 0) {
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + paddedLengthA, 0, DEFAULT_LEN_1CH - paddedLengthA, reverbIndex);
}
aSetBuffer(cmd++, 0, temp_t9 + DMEM_ADDR_ADPCM_RESAMPLED, DMEM_ADDR_WET_LEFT_CH, bufLen * 2);
aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED + startPad, DMEM_ADDR_WET_LEFT_CH, bufLen * 2);
aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateLeft));
aSetBuffer(cmd++, 0, temp_t9 + DMEM_ADDR_ADPCM_RESAMPLED2, DMEM_ADDR_WET_RIGHT_CH, bufLen * 2);
aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED2 + startPad, DMEM_ADDR_WET_RIGHT_CH, bufLen * 2);
aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateRight));
aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
@ -397,10 +397,10 @@ u64 *synthesis_save_reverb_samples(u64 *cmdBuf, s16 reverbIndex, s16 updateIndex
}
if (reverb->downsampleRate == 1) {
// Put the oldest samples in the ring buffer into the wet channels
cmd = cmdBuf = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengths[0], reverbIndex);
if (item->lengths[1] != 0) {
cmd = cmdBuf = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
if (item->lengthB != 0) {
// Ring buffer wrapped
cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengths[0], 0, item->lengths[1], reverbIndex);
cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
cmdBuf = cmd;
}
} else {
@ -513,9 +513,9 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, u32 updateI
if (gReverbDownsampleRate == 1) {
// Put the oldest samples in the ring buffer into the wet channels
aSetLoadBufferPair(cmd++, 0, v1->startPos);
if (v1->lengths[1] != 0) {
if (v1->lengthB != 0) {
// Ring buffer wrapped
aSetLoadBufferPair(cmd++, v1->lengths[0], 0);
aSetLoadBufferPair(cmd++, v1->lengthA, 0);
temp = 0;
}
@ -532,9 +532,9 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, u32 updateI
// Same as above but upsample the previously downsampled samples used for reverb first
temp = 0; //! jesus christ
t4 = (v1->startPos & 7) * 2;
ra = ALIGN(v1->lengths[0] + t4, 4);
ra = ALIGN(v1->lengthA + t4, 4);
aSetLoadBufferPair(cmd++, 0, v1->startPos - t4 / 2);
if (v1->lengths[1] != 0) {
if (v1->lengthB != 0) {
// Ring buffer wrapped
aSetLoadBufferPair(cmd++, ra, 0);
//! We need an empty statement (even an empty ';') here to make the function match (because IDO).
@ -553,10 +553,10 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, u32 updateI
}
cmd = synthesis_process_notes(aiBuf, bufLen, cmd);
if (gReverbDownsampleRate == 1) {
aSetSaveBufferPair(cmd++, 0, v1->lengths[0], v1->startPos);
if (v1->lengths[1] != 0) {
aSetSaveBufferPair(cmd++, 0, v1->lengthA, v1->startPos);
if (v1->lengthB != 0) {
// Ring buffer wrapped
aSetSaveBufferPair(cmd++, v1->lengths[0], v1->lengths[1], 0);
aSetSaveBufferPair(cmd++, v1->lengthA, v1->lengthB, 0);
}
} else {
// Downsampling is done later by CPU when RSP is done, therefore we need to have double
@ -967,26 +967,26 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) {
case 2:
switch (curPart) {
case 0:
aSetBuffer(cmd++, 0, DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_ADPCM_RESAMPLED, samplesLenAdjusted + 4);
aSetBuffer(cmd++, 0, DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_RESAMPLED, samplesLenAdjusted + 4);
#ifdef VERSION_EU
aResample(cmd++, A_INIT, 0xff60, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->dummyResampleState));
#else
aResample(cmd++, A_INIT, 0xff60, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->dummyResampleState));
#endif
resampledTempLen = samplesLenAdjusted + 4;
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_ADPCM_RESAMPLED + 4;
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_RESAMPLED + 4;
#ifdef VERSION_EU
if (noteSubEu->finished != FALSE) {
#else
if (note->finished != FALSE) {
#endif
aClearBuffer(cmd++, DMEM_ADDR_ADPCM_RESAMPLED + resampledTempLen, samplesLenAdjusted + 0x10);
aClearBuffer(cmd++, DMEM_ADDR_RESAMPLED + resampledTempLen, samplesLenAdjusted + 0x10);
}
break;
case 1:
aSetBuffer(cmd++, 0, DMEM_ADDR_UNCOMPRESSED_NOTE + sp130,
DMEM_ADDR_ADPCM_RESAMPLED2,
DMEM_ADDR_RESAMPLED2,
samplesLenAdjusted + 8);
#ifdef VERSION_EU
aResample(cmd++, A_INIT, 0xff60,
@ -997,8 +997,8 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) {
VIRTUAL_TO_PHYSICAL2(
note->synthesisBuffers->dummyResampleState));
#endif
aDMEMMove(cmd++, DMEM_ADDR_ADPCM_RESAMPLED2 + 4,
DMEM_ADDR_ADPCM_RESAMPLED + resampledTempLen,
aDMEMMove(cmd++, DMEM_ADDR_RESAMPLED2 + 4,
DMEM_ADDR_RESAMPLED + resampledTempLen,
samplesLenAdjusted + 4);
break;
}

View File

@ -19,7 +19,8 @@ struct ReverbRingBufferItem
s16 *toDownsampleLeft;
s16 *toDownsampleRight; // data pointed to by left and right are adjacent in memory
s32 startPos; // start pos in ring buffer
s16 lengths[2]; // first length in ring buffer (max until end) and second length in ring buffer (from pos 0)
s16 lengthA; // first length in ring buffer (from startPos, at most until end)
s16 lengthB; // second length in ring buffer (from pos 0)
}; // size = 0x14
struct SynthesisReverb

View File

@ -117,7 +117,7 @@ struct GraphNodePerspective
*/
struct DisplayListNode
{
void *transform;
Mtx *transform;
void *displayList;
struct DisplayListNode *next;
};
@ -185,7 +185,7 @@ struct GraphNodeCamera
} config;
/*0x1C*/ Vec3f pos;
/*0x28*/ Vec3f focus;
/*0x34*/ void *matrixPtr; // pointer to look-at matrix of this camera as a Mat4
/*0x34*/ Mat4 *matrixPtr; // pointer to look-at matrix of this camera as a Mat4
/*0x38*/ s16 roll; // roll in look at matrix. Doesn't account for light direction unlike rollScreen.
/*0x3A*/ s16 rollScreen; // rolls screen while keeping the light direction consistent
};

View File

@ -19,6 +19,7 @@
#include "game_init.h"
#include "ingame_menu.h"
#include "interaction.h"
#include "level_misc_macros.h"
#include "level_table.h"
#include "level_update.h"
#include "levels/bob/header.h"
@ -173,7 +174,7 @@ Gfx *geo_move_mario_part_from_parent(s32 run, UNUSED struct GraphNode *node, Mat
if (run == TRUE) {
sp1C = (struct Object *) gCurGraphNodeObject;
if (sp1C == gMarioObject && sp1C->prevObj != NULL) {
create_transformation_from_matrices(sp20, mtx, gCurGraphNodeCamera->matrixPtr);
create_transformation_from_matrices(sp20, mtx, *gCurGraphNodeCamera->matrixPtr);
obj_update_pos_from_parent_transformation(sp20, sp1C->prevObj);
obj_set_gfx_pos_from_pos(sp1C->prevObj);
}

View File

@ -273,7 +273,7 @@ static s32 boo_update_during_death(void) {
o->oBooTargetOpacity = 0;
}
if (o->oTimer > 30 || o->oMoveFlags & 0x200) {
if (o->oTimer > 30 || o->oMoveFlags & OBJ_MOVE_HIT_WALL) {
spawn_mist_particles();
o->oBooDeathStatus = BOO_DEATH_STATUS_DEAD;

View File

@ -9,7 +9,7 @@ void bhv_bouncing_fireball_flame_loop(void) {
o->oAnimState = random_float() * 10.0f;
o->oVelY = 30.0f;
}
if (o->oMoveFlags & 1)
if (o->oMoveFlags & OBJ_MOVE_LANDED)
o->oAction++;
break;
case 1:
@ -17,7 +17,7 @@ void bhv_bouncing_fireball_flame_loop(void) {
o->oVelY = 50.0f;
o->oForwardVel = 30.0f;
}
if (o->oMoveFlags & (0x40 | 0x10 | 0x2) && o->oTimer > 100)
if (o->oMoveFlags & (OBJ_MOVE_UNDERWATER_ON_GROUND | OBJ_MOVE_AT_WATER_SURFACE | OBJ_MOVE_ON_GROUND) && o->oTimer > 100)
obj_mark_for_deletion(o);
break;
}

View File

@ -12,19 +12,32 @@ static struct ObjectHitbox sBowlingBallHitbox = {
/* hurtboxHeight: */ 0,
};
// TODO: these are likely Waypoint structs
static s16 D_803315B4[] = { 0x0000, 0xED4E, 0x0065, 0xF78A, 0x0001, 0xEC78, 0x0051, 0xF53F, 0x0002,
0xEC50, 0x0021, 0xF0FA, 0x0003, 0xEC9A, 0x0026, 0xEC9A, 0x0004, 0xF053,
0xFEFD, 0xECE3, 0x0005, 0xF5F3, 0xFC05, 0xED54, 0x0006, 0xFBE3, 0xFA89,
0xED3A, 0x0007, 0x02F8, 0xF99B, 0xED1F, 0x0008, 0x0B32, 0xF801, 0xECEA,
0x0009, 0x0D3A, 0xE66E, 0xED1F, 0xFFFF, 0x0000 };
static Trajectory sThiHugeMetalBallTraj[] = {
TRAJECTORY_POS(0, /*pos*/ -4786, 101, -2166),
TRAJECTORY_POS(1, /*pos*/ -5000, 81, -2753),
TRAJECTORY_POS(2, /*pos*/ -5040, 33, -3846),
TRAJECTORY_POS(3, /*pos*/ -4966, 38, -4966),
TRAJECTORY_POS(4, /*pos*/ -4013, -259, -4893),
TRAJECTORY_POS(5, /*pos*/ -2573, -1019, -4780),
TRAJECTORY_POS(6, /*pos*/ -1053, -1399, -4806),
TRAJECTORY_POS(7, /*pos*/ 760, -1637, -4833),
TRAJECTORY_POS(8, /*pos*/ 2866, -2047, -4886),
TRAJECTORY_POS(9, /*pos*/ 3386, -6546, -4833),
TRAJECTORY_END(),
};
// TODO: these are likely Waypoint structs
static s16 D_80331608[] = { 0x0000, 0xFA3C, 0x001D, 0xFD58, 0x0001, 0xFA2C, 0x000E, 0xFBD0,
0x0002, 0xFA24, 0x0003, 0xFACD, 0x0003, 0xFAA2, 0xFFEF, 0xFA09,
0x0004, 0xFB66, 0xFFAD, 0xFA28, 0x0005, 0xFEDC, 0xFE58, 0xFA6F,
0x0006, 0x00FA, 0xFE15, 0xFA67, 0x0007, 0x035E, 0xFD9B, 0xFA57,
0x0008, 0x0422, 0xF858, 0xFA57, 0xFFFF, 0x0000 };
static Trajectory sThiTinyMetalBallTraj[] = {
TRAJECTORY_POS(0, /*pos*/ -1476, 29, -680),
TRAJECTORY_POS(1, /*pos*/ -1492, 14, -1072),
TRAJECTORY_POS(2, /*pos*/ -1500, 3, -1331),
TRAJECTORY_POS(3, /*pos*/ -1374, -17, -1527),
TRAJECTORY_POS(4, /*pos*/ -1178, -83, -1496),
TRAJECTORY_POS(5, /*pos*/ -292, -424, -1425),
TRAJECTORY_POS(6, /*pos*/ 250, -491, -1433),
TRAJECTORY_POS(7, /*pos*/ 862, -613, -1449),
TRAJECTORY_POS(8, /*pos*/ 1058, -1960, -1449),
TRAJECTORY_END(),
};
void bhv_bowling_ball_init(void) {
o->oGravity = 5.5f;
@ -42,23 +55,23 @@ void bowling_ball_set_hitbox(void) {
void bowling_ball_set_waypoints(void) {
switch (o->oBehParams2ndByte) {
case BBALL_BP_STYPE_BOB_UPPER:
o->oPathedWaypointsS16 = segmented_to_virtual(bob_seg7_metal_ball_path0);
o->oPathedStartWaypoint = segmented_to_virtual(bob_seg7_metal_ball_path0);
break;
case BBALL_BP_STYPE_TTM:
o->oPathedWaypointsS16 = segmented_to_virtual(ttm_seg7_trajectory_070170A0);
o->oPathedStartWaypoint = segmented_to_virtual(ttm_seg7_trajectory_070170A0);
break;
case BBALL_BP_STYPE_BOB_LOWER:
o->oPathedWaypointsS16 = segmented_to_virtual(bob_seg7_metal_ball_path1);
o->oPathedStartWaypoint = segmented_to_virtual(bob_seg7_metal_ball_path1);
break;
case BBALL_BP_STYPE_THI_LARGE:
o->oPathedWaypointsS16 = D_803315B4;
o->oPathedStartWaypoint = (struct Waypoint *) sThiHugeMetalBallTraj;
break;
case BBALL_BP_STYPE_THI_SMALL:
o->oPathedWaypointsS16 = D_80331608;
o->oPathedStartWaypoint = (struct Waypoint *) sThiTinyMetalBallTraj;
break;
}
}

View File

@ -106,7 +106,7 @@ s32 bowser_spawn_shockwave(void) {
}
void bowser_bounce(s32 *a) {
if (o->oMoveFlags & 1) {
if (o->oMoveFlags & OBJ_MOVE_LANDED) {
a[0]++;
if (a[0] < 4) {
cur_obj_start_cam_event(o, CAM_EVENT_BOWSER_THROW_BOUNCE);
@ -453,7 +453,7 @@ s32 bowser_set_anim_in_air(void) {
}
s32 bowser_land(void) {
if (o->oMoveFlags & 1) {
if (o->oMoveFlags & OBJ_MOVE_LANDED) {
o->oForwardVel = 0;
o->oVelY = 0;
spawn_mist_particles_variable(0, 0, 60.0f);
@ -627,7 +627,7 @@ void bowser_act_charge_mario(void) {
cur_obj_extend_animation_if_at_end();
break;
}
if (o->oMoveFlags & 0x400)
if (o->oMoveFlags & OBJ_MOVE_HIT_EDGE)
o->oAction = 10;
}
@ -650,7 +650,7 @@ void bowser_act_thrown_dropped(void)
if (o->oSubAction == 0) {
cur_obj_init_animation_with_sound(2);
bowser_bounce(&o->oBowserUnkF8);
if (o->oMoveFlags & 2) {
if (o->oMoveFlags & OBJ_MOVE_ON_GROUND) {
o->oForwardVel = 0.0f;
o->oSubAction++;
}
@ -780,9 +780,9 @@ void bowser_fly_back_dead(void) {
void bowser_dead_bounce(void) {
o->oBowserEyesShut = 1;
bowser_bounce(&o->oBowserUnkF8);
if (o->oMoveFlags & 1)
if (o->oMoveFlags & OBJ_MOVE_LANDED)
cur_obj_play_sound_2(SOUND_OBJ_BOWSER_WALK);
if (o->oMoveFlags & 2) {
if (o->oMoveFlags & OBJ_MOVE_ON_GROUND) {
o->oForwardVel = 0.0f;
o->oSubAction++;
}
@ -962,7 +962,7 @@ s32 bowser_check_fallen_off_stage(void) // bowser off stage?
if (o->oAction != 2 && o->oAction != 19) {
if (o->oPosY < o->oHomeY - 1000.0f)
return 1;
if (o->oMoveFlags & 1) {
if (o->oMoveFlags & OBJ_MOVE_LANDED) {
if (o->oFloorType == 1)
return 1;
if (o->oFloorType == 10)
@ -1168,7 +1168,7 @@ Gfx *geo_update_body_rot_from_parent(s32 run, UNUSED struct GraphNode *node, Mat
if (run == TRUE) {
sp1C = (struct Object *) gCurGraphNodeObject;
if (sp1C->prevObj != NULL) {
create_transformation_from_matrices(sp20, mtx, gCurGraphNodeCamera->matrixPtr);
create_transformation_from_matrices(sp20, mtx, *gCurGraphNodeCamera->matrixPtr);
obj_update_pos_from_parent_transformation(sp20, sp1C->prevObj);
obj_set_gfx_pos_from_pos(sp1C->prevObj);
}
@ -1424,7 +1424,7 @@ void bhv_flame_bowser_loop(void) {
if (o->oAction == 0) {
cur_obj_become_intangible();
bowser_flame_move();
if (o->oMoveFlags & 1) {
if (o->oMoveFlags & OBJ_MOVE_LANDED) {
o->oAction++;
if (cur_obj_has_behavior(bhvFlameLargeBurningOut))
o->oFlameUnkF4 = 8.0f;
@ -1494,7 +1494,7 @@ void bhv_flame_floating_landing_loop(void) {
obj_mark_for_deletion(o);
if (o->oVelY < D_8032F748[o->oBehParams2ndByte])
o->oVelY = D_8032F748[o->oBehParams2ndByte];
if (o->oMoveFlags & 1) {
if (o->oMoveFlags & OBJ_MOVE_LANDED) {
if (o->oBehParams2ndByte == 0)
spawn_object(o, MODEL_RED_FLAME, bhvFlameLargeBurningOut);
else

View File

@ -33,7 +33,7 @@ void bubba_act_0(void) {
o->oBubbaUnkF8 = random_linear_offset(20, 30);
}
if ((o->oBubbaUnkFC = o->oMoveFlags & 0x00000200) != 0) {
if ((o->oBubbaUnkFC = o->oMoveFlags & OBJ_MOVE_HIT_WALL) != 0) {
o->oBubbaUnk1AE = cur_obj_reflect_move_angle_off_wall();
} else if (o->oTimer > 30 && o->oDistanceToMario < 2000.0f) {
o->oAction = 1;
@ -130,8 +130,8 @@ void bhv_bubba_loop(void) {
break;
}
if (o->oMoveFlags & 0x00000078) {
if (o->oMoveFlags & 0x00000008) {
if (o->oMoveFlags & OBJ_MOVE_MASK_IN_WATER) {
if (o->oMoveFlags & OBJ_MOVE_ENTERED_WATER) {
sp38 = spawn_object(o, MODEL_WATER_SPLASH, bhvWaterSplash);
if (sp38 != NULL) {
obj_scale(sp38, 3.0f);

View File

@ -45,7 +45,7 @@ void bullet_bill_act_2(void) {
cur_obj_play_sound_2(SOUND_OBJ_POUNDING_CANNON);
cur_obj_shake_screen(SHAKE_POS_SMALL);
}
if (o->oTimer > 150 || o->oMoveFlags & 0x200) {
if (o->oTimer > 150 || o->oMoveFlags & OBJ_MOVE_HIT_WALL) {
o->oAction = 3;
spawn_mist_particles();
}

View File

@ -168,7 +168,7 @@ void chuckya_act_3(void) {
}
void chuckya_act_2(void) {
if (o->oMoveFlags & (0x200 | 0x40 | 0x20 | 0x10 | 0x8 | 0x1)) {
if (o->oMoveFlags & (OBJ_MOVE_HIT_WALL | OBJ_MOVE_MASK_IN_WATER | OBJ_MOVE_LANDED)) {
obj_mark_for_deletion(o);
obj_spawn_loot_yellow_coins(o, 5, 20.0f);
spawn_mist_particles_with_sound(SOUND_OBJ_CHUCKYA_DEATH);

View File

@ -93,13 +93,13 @@ void bhv_coin_loop(void) {
obj_mark_for_deletion(o);
}
#ifndef VERSION_JP
if (o->oMoveFlags & OBJ_MOVE_13) {
if (o->oMoveFlags & OBJ_MOVE_BOUNCE) {
if (o->oCoinUnk1B0 < 5)
cur_obj_play_sound_2(0x30364081);
o->oCoinUnk1B0++;
}
#else
if (o->oMoveFlags & OBJ_MOVE_13)
if (o->oMoveFlags & OBJ_MOVE_BOUNCE)
cur_obj_play_sound_2(SOUND_GENERAL_COIN_DROP);
#endif
if (cur_obj_wait_then_blink(400, 20))
@ -214,7 +214,7 @@ void bhv_coin_formation_loop(void) {
void coin_inside_boo_act_1(void) {
cur_obj_update_floor_and_walls();
cur_obj_if_hit_wall_bounce_away();
if (o->oMoveFlags & OBJ_MOVE_13)
if (o->oMoveFlags & OBJ_MOVE_BOUNCE)
cur_obj_play_sound_2(SOUND_GENERAL_COIN_DROP);
if (o->oTimer > 90 || (o->oMoveFlags & OBJ_MOVE_LANDED)) {
obj_set_hitbox(o, &sYellowCoinHitbox);

View File

@ -41,7 +41,7 @@ void bhv_donut_platform_spawner_update(void) {
}
void bhv_donut_platform_update(void) {
if (o->oTimer != 0 && ((o->oMoveFlags & 0x00000003) || o->oDistanceToMario > 2500.0f)) {
if (o->oTimer != 0 && ((o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) || o->oDistanceToMario > 2500.0f)) {
o->parentObj->oDonutPlatformSpawnerSpawnedPlatforms =
o->parentObj->oDonutPlatformSpawnerSpawnedPlatforms
& ((1 << o->oBehParams2ndByte) ^ 0xFFFFFFFF);

View File

@ -292,7 +292,7 @@ static void eyerok_hand_act_show_eye(void) {
if (o->parentObj->oEyerokBossNumHands != 2) {
obj_face_yaw_approach(o->oMoveAngleYaw, 0x800);
if (o->oTimer > 10
&& (o->oPosZ - gMarioObject->oPosZ > 0.0f || (o->oMoveFlags & 0x00000400))) {
&& (o->oPosZ - gMarioObject->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) {
o->parentObj->oEyerokBossActiveHand = 0;
o->oForwardVel = 0.0f;
}
@ -321,7 +321,7 @@ static void eyerok_hand_act_attacked(void) {
o->collisionData = segmented_to_virtual(ssl_seg7_collision_07028274);
}
if (o->oMoveFlags & 0x00000003) {
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
o->oForwardVel = 0.0f;
}
}
@ -346,7 +346,7 @@ static void eyerok_hand_act_die(void) {
create_sound_spawner(SOUND_OBJ2_EYEROK_SOUND_LONG);
}
if (o->oMoveFlags & 0x00000003) {
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
cur_obj_play_sound_2(SOUND_OBJ_POUNDING_LOUD);
o->oForwardVel = 0.0f;
}
@ -378,7 +378,7 @@ static void eyerok_hand_act_retreat(void) {
static void eyerok_hand_act_target_mario(void) {
if (eyerok_check_mario_relative_z(400) != 0 || o->oPosZ - gMarioObject->oPosZ > 0.0f
|| o->oPosZ - o->parentObj->oPosZ > 1700.0f || absf(o->oPosX - o->parentObj->oPosX) > 900.0f
|| (o->oMoveFlags & 0x00000200)) {
|| (o->oMoveFlags & OBJ_MOVE_HIT_WALL)) {
o->oForwardVel = 0.0f;
if (approach_f32_ptr(&o->oPosY, o->oHomeY + 300.0f, 20.0f)) {
o->oAction = EYEROK_HAND_ACT_SMASH;
@ -394,7 +394,7 @@ static void eyerok_hand_act_smash(void) {
s16 sp1E;
if (o->oTimer > 20) {
if (o->oMoveFlags & 0x00000003) {
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
if (o->oGravity < -4.0f) {
eyerok_hand_pound_ground();
o->oGravity = -4.0f;
@ -418,7 +418,7 @@ static void eyerok_hand_act_smash(void) {
}
static void eyerok_hand_act_fist_push(void) {
if (o->oTimer > 5 && (o->oPosZ - gMarioObject->oPosZ > 0.0f || (o->oMoveFlags & 0x00000400))) {
if (o->oTimer > 5 && (o->oPosZ - gMarioObject->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) {
o->oAction = EYEROK_HAND_ACT_FIST_SWEEP;
o->oForwardVel = 0.0f;
@ -433,7 +433,7 @@ static void eyerok_hand_act_fist_push(void) {
}
static void eyerok_hand_act_fist_sweep(void) {
if (o->oPosZ - o->parentObj->oPosZ < 1000.0f || (o->oMoveFlags & 0x400)) {
if (o->oPosZ - o->parentObj->oPosZ < 1000.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE)) {
o->oAction = EYEROK_HAND_ACT_RETREAT;
o->oForwardVel = 0.0f;
} else {
@ -470,7 +470,7 @@ static void eyerok_hand_act_double_pound(void) {
o->oAction = EYEROK_HAND_ACT_RETREAT;
o->parentObj->oEyerokBossUnk1AC = o->oBehParams2ndByte;
} else if (o->parentObj->oEyerokBossActiveHand == o->oBehParams2ndByte) {
if (o->oMoveFlags & 0x00000003) {
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
if (o->oGravity < -15.0f) {
o->parentObj->oEyerokBossActiveHand = 0;
eyerok_hand_pound_ground();

View File

@ -1,7 +1,7 @@
static void fire_spitter_act_idle(void) {
approach_f32_ptr(&o->header.gfx.scale[0], 0.2f, 0.002f);
if (o->oTimer > 150 && o->oDistanceToMario < 800.0f && !(o->oMoveFlags & 0x00000078)) {
if (o->oTimer > 150 && o->oDistanceToMario < 800.0f && !(o->oMoveFlags & OBJ_MOVE_MASK_IN_WATER)) {
o->oAction = FIRE_SPITTER_ACT_SPIT_FIRE;
o->oFireSpitterScaleVel = 0.05f;
}

View File

@ -34,7 +34,7 @@ void bhv_small_piranha_flame_loop(void) {
obj_check_attacks(&sPiranhaPlantFireHitbox, o->oAction);
o->oSmallPiranhaFlameUnk104 += o->oSmallPiranhaFlameUnkF4;
if (o->oSmallPiranhaFlameUnk104 > 1500.0f || (o->oMoveFlags & 0x00000278)) {
if (o->oSmallPiranhaFlameUnk104 > 1500.0f || (o->oMoveFlags & (OBJ_MOVE_HIT_WALL | OBJ_MOVE_MASK_IN_WATER))) {
obj_die_if_health_non_positive();
}
}

View File

@ -118,7 +118,7 @@ void bhv_flying_bookend_loop(void) {
}
obj_check_attacks(&sFlyingBookendHitbox, -1);
if (o->oAction == -1 || (o->oMoveFlags & 0x00000203)) {
if (o->oAction == -1 || (o->oMoveFlags & (OBJ_MOVE_MASK_ON_GROUND | OBJ_MOVE_HIT_WALL))) {
o->oNumLootCoins = 0;
obj_die_if_health_non_positive();
}

View File

@ -118,7 +118,7 @@ void haunted_chair_act_1(void) {
}
o->oFaceAngleYaw += 0x2710;
}
} else if (o->oMoveFlags & 0x00000203) {
} else if (o->oMoveFlags & (OBJ_MOVE_MASK_ON_GROUND | OBJ_MOVE_HIT_WALL)) {
obj_die_if_health_non_positive();
}
}

View File

@ -93,13 +93,13 @@ void heave_ho_move(void) {
cur_obj_update_floor_and_walls();
cur_obj_call_action_function(sHeaveHoActions);
cur_obj_move_standard(-78);
if (o->oMoveFlags & (0x40 | 0x20 | 0x10 | 0x8))
if (o->oMoveFlags & OBJ_MOVE_MASK_IN_WATER)
o->oGraphYOffset = -15.0f;
else
o->oGraphYOffset = 0.0f;
if (o->oForwardVel > 3.0f)
cur_obj_play_sound_1(SOUND_AIR_HEAVEHO_MOVE);
if (o->oAction != 0 && o->oMoveFlags & (0x40 | 0x20 | 0x10 | 0x8))
if (o->oAction != 0 && o->oMoveFlags & OBJ_MOVE_MASK_IN_WATER)
o->oAction = 0;
if (o->oInteractStatus & INT_STATUS_GRABBED_MARIO) {
o->oInteractStatus = 0;

View File

@ -4,7 +4,7 @@ void bhv_horizontal_grindel_init(void) {
}
void bhv_horizontal_grindel_update(void) {
if (o->oMoveFlags & 0x00000003) {
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
if (!o->oHorizontalGrindelOnGround) {
cur_obj_play_sound_2(SOUND_OBJ_THWOMP);
o->oHorizontalGrindelOnGround = TRUE;

View File

@ -20,14 +20,14 @@ void jumping_box_act_0(void) {
o->oVelY = random_float() * 5.0f + 15.0f;
o->oSubAction++;
}
} else if (o->oMoveFlags & 2) {
} else if (o->oMoveFlags & OBJ_MOVE_ON_GROUND) {
o->oSubAction = 0;
o->oJumpingBoxUnkF8 = random_float() * 60.0f + 30.0f;
}
}
void jumping_box_act_1(void) {
if (o->oMoveFlags & (0x200 | 0x40 | 0x20 | 0x10 | 0x8 | 0x1)) {
if (o->oMoveFlags & (OBJ_MOVE_HIT_WALL | OBJ_MOVE_MASK_IN_WATER | OBJ_MOVE_LANDED)) {
obj_mark_for_deletion(o);
spawn_mist_particles();
}

View File

@ -8,7 +8,7 @@ Gfx *geo_update_held_mario_pos(s32 run, UNUSED struct GraphNode *node, Mat4 mtx)
if (run == TRUE) {
sp1C = (struct Object *) gCurGraphNodeObject;
if (sp1C->prevObj != NULL) {
create_transformation_from_matrices(sp20, mtx, gCurGraphNodeCamera->matrixPtr);
create_transformation_from_matrices(sp20, mtx, *gCurGraphNodeCamera->matrixPtr);
obj_update_pos_from_parent_transformation(sp20, sp1C->prevObj);
obj_set_gfx_pos_from_pos(sp1C->prevObj);
}
@ -194,7 +194,7 @@ void king_bobomb_act_8(void) {
void king_bobomb_act_4(void) { // bobomb been thrown
if (o->oPosY - o->oHomeY > -100.0f) { // not thrown off hill
if (o->oMoveFlags & 1) {
if (o->oMoveFlags & OBJ_MOVE_LANDED) {
o->oHealth--;
o->oForwardVel = 0;
o->oVelY = 0;
@ -206,11 +206,11 @@ void king_bobomb_act_4(void) { // bobomb been thrown
}
} else {
if (o->oSubAction == 0) {
if (o->oMoveFlags & 2) {
if (o->oMoveFlags & OBJ_MOVE_ON_GROUND) {
o->oForwardVel = 0;
o->oVelY = 0;
o->oSubAction++;
} else if (o->oMoveFlags & 1)
} else if (o->oMoveFlags & OBJ_MOVE_LANDED)
cur_obj_play_sound_2(SOUND_OBJ_KING_BOBOMB);
} else {
if (cur_obj_init_animation_and_check_if_near_end(10))

View File

@ -6,6 +6,8 @@ void bhv_volcano_flames_loop(void) {
o->oPosX += o->oVelX;
o->oPosZ += o->oVelZ;
cur_obj_move_y(-4.0f, -0.7f, 2.0f);
if (o->oMoveFlags & 0x33)
if (o->oMoveFlags & (OBJ_MOVE_MASK_ON_GROUND | OBJ_MOVE_AT_WATER_SURFACE
| OBJ_MOVE_UNDERWATER_OFF_GROUND))
obj_mark_for_deletion(o);
}

View File

@ -1,10 +1,16 @@
// manta_ray.c.inc
// TODO: these are likely Waypoint structs
static s16 D_803316A8[] = { 0x0000, 0xEE6C, 0xFA9C, 0xFFD8, 0x0001, 0xEFE8, 0xF740, 0x02E4, 0x0002,
0xF330, 0xF3F8, 0x0410, 0x0003, 0xF740, 0xF308, 0x02D0, 0x0004, 0xF8D0,
0xF3BC, 0xFEE8, 0x0005, 0xF6F0, 0xF650, 0xFBB4, 0x0006, 0xF36C, 0xF9C0,
0xFAB0, 0x0007, 0xEFAC, 0xFC04, 0xFBF0, 0xFFFF, 0x0000 };
static Trajectory sMantaRayTraj[] = {
TRAJECTORY_POS(0, /*pos*/ -4500, -1380, -40),
TRAJECTORY_POS(1, /*pos*/ -4120, -2240, 740),
TRAJECTORY_POS(2, /*pos*/ -3280, -3080, 1040),
TRAJECTORY_POS(3, /*pos*/ -2240, -3320, 720),
TRAJECTORY_POS(4, /*pos*/ -1840, -3140, -280),
TRAJECTORY_POS(5, /*pos*/ -2320, -2480, -1100),
TRAJECTORY_POS(6, /*pos*/ -3220, -1600, -1360),
TRAJECTORY_POS(7, /*pos*/ -4180, -1020, -1040),
TRAJECTORY_END(),
};
static struct ObjectHitbox sMantaRayHitbox = {
/* interactType: */ INTERACT_DAMAGE,
@ -31,7 +37,7 @@ void manta_ray_move(void) {
s32 sp18;
sp1E = o->header.gfx.unk38.animFrame;
gCurrentObject->oPathedWaypointsS16 = &D_803316A8;
gCurrentObject->oPathedStartWaypoint = (struct Waypoint *) sMantaRayTraj;
sp18 = cur_obj_follow_path(sp18);
o->oMantaUnkF8 = o->oPathedTargetYaw;
o->oMantaUnkF4 = o->oPathedTargetPitch;

View File

@ -1,3 +1,4 @@
// Mr. Blizzard hitbox
struct ObjectHitbox sMrBlizzardHitbox = {
/* interactType: */ INTERACT_MR_BLIZZARD,
/* downOffset: */ 24,
@ -10,7 +11,9 @@ struct ObjectHitbox sMrBlizzardHitbox = {
/* hurtboxHeight: */ 170,
};
void mr_blizzard_spawn_white_particles(s8 count, s8 offsetY, s8 forwardVelBase, s8 velYBase, s8 sizeBase) {
// Mr. Blizzard particle spawner.
void mr_blizzard_spawn_white_particles(s8 count, s8 offsetY, s8 forwardVelBase, s8 velYBase,
s8 sizeBase) {
static struct SpawnParticlesInfo D_80331A00 = {
/* behParam: */ 0,
/* count: */ 6,
@ -34,42 +37,66 @@ void mr_blizzard_spawn_white_particles(s8 count, s8 offsetY, s8 forwardVelBase,
cur_obj_spawn_particles(&D_80331A00);
}
/**
* Mr. Blizzard initialization function.
*/
void bhv_mr_blizzard_init(void) {
if (o->oBehParams2ndByte == 1) {
o->oAction = 7;
if (o->oBehParams2ndByte == MR_BLIZZARD_STYPE_JUMPING) {
// Jumping Mr. Blizzard.
o->oAction = MR_BLIZZARD_ACT_JUMP;
o->oMrBlizzardGraphYOffset = 24.0f;
o->oMrBlizzardTargetMoveYaw = o->oMoveAngleYaw;
} else {
if (o->oBehParams2ndByte != 0) {
if (o->oBehParams2ndByte != MR_BLIZZARD_STYPE_NO_CAP) {
// Cap wearing Mr. Blizzard from SL.
if (save_file_get_flags() & SAVE_FLAG_CAP_ON_MR_BLIZZARD) {
o->oAnimState = 1;
}
}
// Mr. Blizzard starts under the floor holding nothing.
o->oMrBlizzardGraphYOffset = -200.0f;
o->oMrBlizzardHeldObj = NULL;
}
}
static void mr_blizzard_act_0(void) {
/**
* Handler for spawning Mr. Blizzard's snowball.
*/
static void mr_blizzard_act_spawn_snowball(void) {
// If Mr. Blizzard is not holding a snowball, and the animation reaches 5 frames
// spawn the Mr. Blizzard snowball.
if (o->oMrBlizzardHeldObj == NULL && cur_obj_init_anim_check_frame(0, 5)) {
o->oMrBlizzardHeldObj = spawn_object_relative(0, -70, (s32)(o->oMrBlizzardGraphYOffset + 153.0f), 0, o,
MODEL_WHITE_PARTICLE, bhvMrBlizzardSnowball);
o->oMrBlizzardHeldObj =
spawn_object_relative(0, -70, (s32)(o->oMrBlizzardGraphYOffset + 153.0f), 0, o,
MODEL_WHITE_PARTICLE, bhvMrBlizzardSnowball);
} else if (cur_obj_check_anim_frame(10)) {
o->prevObj = o->oMrBlizzardHeldObj;
} else if (cur_obj_check_if_near_animation_end()) {
// If Mr. Blizzard's graphical position is below the ground, move to hide and unhide action.
// Otherwise, move to rotate action.
if (o->oMrBlizzardGraphYOffset < 0.0f) {
o->oAction = 1;
o->oAction = MR_BLIZZARD_ACT_HIDE_UNHIDE;
} else {
o->oAction = 3;
o->oAction = MR_BLIZZARD_ACT_ROTATE;
}
}
}
static void mr_blizzard_act_1(void) {
/**
* Handler for Mario entering or exiting Mr. Blizzard's range.
*/
static void mr_blizzard_act_hide_unhide(void) {
if (o->oDistanceToMario < 1000.0f) {
// If Mario is in range, move to rising action, make Mr. Blizzard visible,
// make Mr. Blizzard tangible, and initialize GraphYVel.
cur_obj_play_sound_2(SOUND_OBJ_SNOW_SAND2);
o->oAction = 2;
o->oAction = MR_BLIZZARD_ACT_RISE_FROM_GROUND;
o->oMoveAngleYaw = o->oAngleToMario;
o->oMrBlizzardGraphYVel = 42.0f;
@ -77,45 +104,69 @@ static void mr_blizzard_act_1(void) {
cur_obj_unhide();
cur_obj_become_tangible();
} else {
// If Mario is not in range, make Mr. Blizzard invisible.
cur_obj_hide();
}
}
static void mr_blizzard_act_2(void) {
/**
* Handler for Mr. Blizzard popping up out of the ground.
*/
static void mr_blizzard_act_rise_from_ground(void) {
// If the timer is not 0, decrement by 1 until it reaches 0.
if (o->oMrBlizzardTimer != 0) {
o->oMrBlizzardTimer -= 1;
} else if ((o->oMrBlizzardGraphYOffset += o->oMrBlizzardGraphYVel) > 24.0f) {
// Increments GraphYOffset by GraphYVel until it is greater than 24,
// moving Mr. Blizzard's graphical position upward each frame.
// Then, Mr. Blizzard's Y-position is increased by the value of
// GraphYOffset minus 24, GraphYOffset is
// set to 24, VelY is set to GraphYVel and action is moved to rotate.
o->oPosY += o->oMrBlizzardGraphYOffset - 24.0f;
o->oMrBlizzardGraphYOffset = 24.0f;
mr_blizzard_spawn_white_particles(8, -20, 20, 15, 10);
o->oAction = 3;
o->oAction = MR_BLIZZARD_ACT_ROTATE;
o->oVelY = o->oMrBlizzardGraphYVel;
} else if ((o->oMrBlizzardGraphYVel -= 10.0f) < 0.0f) {
// Decrement GraphYOffset until it is less than 0.
// When it is less than 0, set it to 47 and set timer to 5.
o->oMrBlizzardGraphYVel = 47.0f;
o->oMrBlizzardTimer = 5;
}
}
static void mr_blizzard_act_3(void) {
s16 val06;
f32 val00;
/**
* Handler for Mr. Blizzard's rotation.
*/
if (o->oMoveFlags & 0x00000003) {
static void mr_blizzard_act_rotate(void) {
s16 angleDiff;
f32 prevDizziness;
// While Mr. Blizzard is on the ground, rotate toward Mario at
// 8.4375 degrees/frame.
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x600);
val06 = o->oAngleToMario - o->oMoveAngleYaw;
if (val06 != 0) {
if (val06 < 0) {
// Modify the ChangeInDizziness based on Mario's angle to Mr. Blizzard.
angleDiff = o->oAngleToMario - o->oMoveAngleYaw;
if (angleDiff != 0) {
if (angleDiff < 0) {
o->oMrBlizzardChangeInDizziness -= 8.0f;
} else {
o->oMrBlizzardChangeInDizziness += 8.0f;
}
// Incremement Dizziness by value of ChangeInDizziness
o->oMrBlizzardDizziness += o->oMrBlizzardChangeInDizziness;
} else if (o->oMrBlizzardDizziness != 0.0f) {
val00 = o->oMrBlizzardDizziness;
prevDizziness = o->oMrBlizzardDizziness;
// Slowly move Dizziness back to 0 by making ChangeInDizziness positive if Dizziness
// is negative, and making ChangeInDizziness negative if Dizziness is positive.
if (o->oMrBlizzardDizziness < 0.0f) {
approach_f32_ptr(&o->oMrBlizzardChangeInDizziness, 1000.0f, 80.0f);
} else {
@ -123,43 +174,55 @@ static void mr_blizzard_act_3(void) {
}
o->oMrBlizzardDizziness += o->oMrBlizzardChangeInDizziness;
if (val00 * o->oMrBlizzardDizziness < 0.0f) {
// If prevDizziness has a different sign than Dizziness,
// set Dizziness and ChangeInDizziness to 0.
if (prevDizziness * o->oMrBlizzardDizziness < 0.0f) {
o->oMrBlizzardDizziness = o->oMrBlizzardChangeInDizziness = 0.0f;
}
}
// If Dizziness is not 0 and Mr. Blizzard's FaceRollAngle has a magnitude greater than
// 67.5 degrees move to death action, delete the snowball, and make Mr. Blizzard intangible.
if (o->oMrBlizzardDizziness != 0.0f) {
if (absi(o->oFaceAngleRoll) > 0x3000) {
o->oAction = 6;
o->oAction = MR_BLIZZARD_ACT_DEATH;
o->prevObj = o->oMrBlizzardHeldObj = NULL;
cur_obj_become_intangible();
}
// If Mario gets too far away, move to burrow action and delete the snowball.
} else if (o->oDistanceToMario > 1500.0f) {
o->oAction = 5;
o->oAction = MR_BLIZZARD_ACT_BURROW;
o->oMrBlizzardChangeInDizziness = 300.0f;
o->prevObj = o->oMrBlizzardHeldObj = NULL;
// After 60 frames, if Mario is within 11.25 degrees of Mr. Blizzard, throw snowball action.
} else if (o->oTimer > 60 && abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw) < 0x800) {
o->oAction = 4;
o->oAction = MR_BLIZZARD_ACT_THROW_SNOWBALL;
}
}
}
static void mr_blizzard_act_6(void) {
struct Object *val04;
/**
* Handler for Mr. Blizzard's death.
*/
static void mr_blizzard_act_death(void) {
struct Object *cap;
if (clamp_f32(&o->oMrBlizzardDizziness, -0x4000, 0x4000)) {
if (o->oMrBlizzardChangeInDizziness != 0.0f) {
cur_obj_play_sound_2(SOUND_OBJ_SNOW_SAND1);
// If Mr. Blizzard is wearing Mario's cap, clear
// the save flag and spawn Mario's cap.
if (o->oAnimState) {
save_file_clear_flags(SAVE_FLAG_CAP_ON_MR_BLIZZARD);
val04 = spawn_object_relative(0, 5, 105, 0, o, MODEL_MARIOS_CAP, bhvNormalCap);
if (val04 != NULL) {
val04->oMoveAngleYaw =
o->oFaceAngleYaw + (o->oFaceAngleRoll < 0 ? 0x4000 : -0x4000);
val04->oForwardVel = 10.0f;
cap = spawn_object_relative(0, 5, 105, 0, o, MODEL_MARIOS_CAP, bhvNormalCap);
if (cap != NULL) {
cap->oMoveAngleYaw = o->oFaceAngleYaw + (o->oFaceAngleRoll < 0 ? 0x4000 : -0x4000);
cap->oForwardVel = 10.0f;
}
// Mr. Blizzard no longer spawns with Mario's cap on.
o->oAnimState = 0;
}
@ -175,6 +238,8 @@ static void mr_blizzard_act_6(void) {
o->oMrBlizzardDizziness += o->oMrBlizzardChangeInDizziness;
}
// After 30 frames, play the defeat sound once and scale Mr. Blizzard down to 0
// at .03 units per frame. Spawn coins and set the coins to not respawn.
if (o->oTimer >= 30) {
if (o->oTimer == 30) {
cur_obj_play_sound_2(SOUND_OBJ_ENEMY_DEFEAT_SHRINK);
@ -188,10 +253,11 @@ static void mr_blizzard_act_6(void) {
set_object_respawn_info_bits(o, 1);
}
}
// Reset Mr. Blizzard if Mario leaves its radius.
} else if (o->oDistanceToMario > 1000.0f) {
cur_obj_init_animation_with_sound(1);
o->oAction = 0;
o->oAction = MR_BLIZZARD_ACT_SPAWN_SNOWBALL;
o->oMrBlizzardScale = 1.0f;
o->oMrBlizzardGraphYOffset = -200.0f;
o->oFaceAngleRoll = 0;
@ -200,16 +266,29 @@ static void mr_blizzard_act_6(void) {
}
}
static void mr_blizzard_act_4(void) {
/**
* Handler for snowball throw.
*/
static void mr_blizzard_act_throw_snowball(void) {
// Play a sound and set HeldObj to NULL. Then set action to 0.
if (cur_obj_init_anim_check_frame(1, 7)) {
cur_obj_play_sound_2(SOUND_OBJ2_SCUTTLEBUG_ALERT);
o->prevObj = o->oMrBlizzardHeldObj = NULL;
} else if (cur_obj_check_if_near_animation_end()) {
o->oAction = 0;
o->oAction = MR_BLIZZARD_ACT_SPAWN_SNOWBALL;
}
}
static void mr_blizzard_act_5(void) {
/**
* Mr. Blizzard's going back into the ground function.
*/
static void mr_blizzard_act_burrow(void) {
// Reset Dizziness by increasing ChangeInDizziness if
// dizziness is negative and decreasing it if Dizziness
o->oMrBlizzardDizziness += o->oMrBlizzardChangeInDizziness;
if (o->oMrBlizzardDizziness < 0.0f) {
@ -217,32 +296,45 @@ static void mr_blizzard_act_5(void) {
} else {
o->oMrBlizzardChangeInDizziness -= 150.0f;
}
// Put Mr. Blizzard's graphical position back below ground
// then move to action 0.
if (approach_f32_ptr(&o->oMrBlizzardGraphYOffset, -200.0f, 4.0f)) {
o->oAction = 0;
o->oAction = MR_BLIZZARD_ACT_SPAWN_SNOWBALL;
cur_obj_init_animation_with_sound(1);
}
}
static void mr_blizzard_act_7(void) {
/**
* Jumping Mr. Blizzard handler function.
*/
static void mr_blizzard_act_jump(void) {
if (o->oMrBlizzardTimer != 0) {
cur_obj_rotate_yaw_toward(o->oMrBlizzardTargetMoveYaw, 3400);
if (--o->oMrBlizzardTimer == 0) {
cur_obj_play_sound_2(SOUND_OBJ_MR_BLIZZARD_ALERT);
// If Mr. Blizzard is more than 700 units from its home, change its target yaw
// by 180 degrees, jump in the air, set distance from home to 0.
if (o->oMrBlizzardDistFromHome > 700) {
o->oMrBlizzardTargetMoveYaw += 0x8000;
o->oVelY = 25.0f;
o->oMrBlizzardTimer = 30;
o->oMrBlizzardDistFromHome = 0;
// Jump forward.
} else {
o->oForwardVel = 10.0f;
o->oVelY = 50.0f;
o->oMoveFlags = 0;
}
}
} else if (o->oMoveFlags & 0x00000003) {
} else if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
// When Mr. Blizzard lands, play the landing sound, stop Mr. Blizzard, and
// set its timer to 15. If Mr. Blizzard's DistFromHome is not 0,
// set DistFromHome to its current distance from its home.
// Otherwise, set DistFromHome to 700.
cur_obj_play_sound_2(SOUND_OBJ_SNOW_SAND1);
if (o->oMrBlizzardDistFromHome != 0) {
o->oMrBlizzardDistFromHome = (s32) cur_obj_lateral_dist_to_home();
@ -255,37 +347,45 @@ static void mr_blizzard_act_7(void) {
}
}
/**
* Mr. Blizzard update function.
*/
void bhv_mr_blizzard_update(void) {
cur_obj_update_floor_and_walls();
// Behavior loop
switch (o->oAction) {
case 0:
mr_blizzard_act_0();
case MR_BLIZZARD_ACT_SPAWN_SNOWBALL:
mr_blizzard_act_spawn_snowball();
break;
case 1:
mr_blizzard_act_1();
case MR_BLIZZARD_ACT_HIDE_UNHIDE:
mr_blizzard_act_hide_unhide();
break;
case 2:
mr_blizzard_act_2();
case MR_BLIZZARD_ACT_RISE_FROM_GROUND:
mr_blizzard_act_rise_from_ground();
break;
case 3:
mr_blizzard_act_3();
case MR_BLIZZARD_ACT_ROTATE:
mr_blizzard_act_rotate();
break;
case 4:
mr_blizzard_act_4();
case MR_BLIZZARD_ACT_THROW_SNOWBALL:
mr_blizzard_act_throw_snowball();
break;
case 5:
mr_blizzard_act_5();
case MR_BLIZZARD_ACT_BURROW:
mr_blizzard_act_burrow();
break;
case 6:
mr_blizzard_act_6();
case MR_BLIZZARD_ACT_DEATH:
mr_blizzard_act_death();
break;
case 7:
mr_blizzard_act_7();
case MR_BLIZZARD_ACT_JUMP:
mr_blizzard_act_jump();
break;
}
// Set roll angle equal to dizziness, making Mr. Blizzard
// slowly fall over.
o->oFaceAngleRoll = o->oMrBlizzardDizziness;
// Mr. Blizzard's graphical position changes by changing the Y offset.
o->oGraphYOffset = o->oMrBlizzardGraphYOffset + absf(20.0f * sins(o->oFaceAngleRoll))
- 40.0f * (1.0f - o->oMrBlizzardScale);
@ -294,6 +394,10 @@ void bhv_mr_blizzard_update(void) {
obj_check_attacks(&sMrBlizzardHitbox, o->oAction);
}
/**
* Snowball initial takeoff position handler.
*/
static void mr_blizzard_snowball_act_0(void) {
cur_obj_move_using_fvel_and_gravity();
if (o->parentObj->prevObj == o) {
@ -303,26 +407,31 @@ static void mr_blizzard_snowball_act_0(void) {
}
}
/**
* Snowball launching action.
*/
static void mr_blizzard_snowball_act_1(void) {
f32 val04;
f32 marioDist;
if (o->parentObj->prevObj == NULL) {
if (o->parentObj->oAction == 4) {
val04 = o->oDistanceToMario;
if (val04 > 800.0f) {
val04 = 800.0f;
if (o->parentObj->oAction == MR_BLIZZARD_ACT_THROW_SNOWBALL) {
marioDist = o->oDistanceToMario;
if (marioDist > 800.0f) {
marioDist = 800.0f;
}
o->oMoveAngleYaw = (s32)(o->parentObj->oMoveAngleYaw + 4000 - val04 * 4.0f);
// Launch the snowball relative to Mario's distance from the snowball.
o->oMoveAngleYaw = (s32)(o->parentObj->oMoveAngleYaw + 4000 - marioDist * 4.0f);
o->oForwardVel = 40.0f;
o->oVelY = -20.0f + val04 * 0.075f;
o->oVelY = -20.0f + marioDist * 0.075f;
}
o->oAction = 2;
o->oMoveFlags = 0;
}
}
// Snowball hitbox.
struct ObjectHitbox sMrBlizzardSnowballHitbox = {
/* interactType: */ INTERACT_MR_BLIZZARD,
/* downOffset: */ 12,
@ -335,11 +444,17 @@ struct ObjectHitbox sMrBlizzardSnowballHitbox = {
/* hurtboxHeight: */ 25,
};
/**
* Snowball collision function.
*/
static void mr_blizzard_snowball_act_2(void) {
// Set snowball to interact with walls, floors, and Mario.
cur_obj_update_floor_and_walls();
obj_check_attacks(&sMrBlizzardSnowballHitbox, -1);
if (o->oAction == -1 || o->oMoveFlags & 0x0000000B) {
// If snowball collides with the ground, delete snowball.
if (o->oAction == -1 || o->oMoveFlags & (OBJ_MOVE_MASK_ON_GROUND | OBJ_MOVE_ENTERED_WATER)) {
mr_blizzard_spawn_white_particles(6, 0, 5, 10, 3);
create_sound_spawner(SOUND_GENERAL_MOVING_IN_SAND);
obj_mark_for_deletion(o);
@ -348,6 +463,10 @@ static void mr_blizzard_snowball_act_2(void) {
cur_obj_move_standard(78);
}
/**
* Snowball behavior loop.
*/
void bhv_mr_blizzard_snowball(void) {
switch (o->oAction) {
case 0:

View File

@ -17,7 +17,7 @@ void mr_i_piranha_particle_act_0(void) {
cur_obj_update_floor_and_walls();
if (0x8000 & o->oInteractStatus)
o->oAction = 1;
else if ((o->oTimer >= 101) || (0x200 & o->oMoveFlags) || o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM) {
else if ((o->oTimer >= 101) || (o->oMoveFlags & OBJ_MOVE_HIT_WALL) || o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM) {
obj_mark_for_deletion(o);
spawn_mist_particles();
}

View File

@ -88,7 +88,7 @@ static void racing_penguin_act_race(void) {
cur_obj_init_animation_with_sound(1);
cur_obj_rotate_yaw_toward(o->oPathedTargetYaw, (s32)(15.0f * o->oForwardVel));
if (cur_obj_check_if_at_animation_end() && (o->oMoveFlags & 0x00000003)) {
if (cur_obj_check_if_at_animation_end() && (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND)) {
spawn_object_relative_with_scale(0, 0, -100, 0, 4.0f, o, MODEL_SMOKE, bhvWhitePuffSmoke2);
}
}
@ -104,7 +104,7 @@ static void racing_penguin_act_race(void) {
static void racing_penguin_act_finish_race(void) {
if (o->oForwardVel != 0.0f) {
if (o->oTimer > 5 && (o->oMoveFlags & 0x00000200)) {
if (o->oTimer > 5 && (o->oMoveFlags & OBJ_MOVE_HIT_WALL)) {
cur_obj_play_sound_2(SOUND_OBJ_POUNDING_LOUD);
set_camera_shake_from_point(SHAKE_POS_SMALL, o->oPosX, o->oPosY, o->oPosZ);
o->oForwardVel = 0.0f;

View File

@ -35,9 +35,9 @@ void bhv_scuttlebug_loop(void) {
o->oScuttlebugUnkF8 = 0;
switch (o->oSubAction) {
case 0:
if (o->oMoveFlags & 1)
if (o->oMoveFlags & OBJ_MOVE_LANDED)
cur_obj_play_sound_2(SOUND_OBJ_GOOMBA_ALERT);
if (o->oMoveFlags & 3) {
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
o->oHomeX = o->oPosX;
o->oHomeY = o->oPosY;
o->oHomeZ = o->oPosZ;
@ -85,7 +85,7 @@ void bhv_scuttlebug_loop(void) {
break;
case 4:
o->oForwardVel = -10.0f;
if (o->oMoveFlags & 1) {
if (o->oMoveFlags & OBJ_MOVE_LANDED) {
o->oSubAction++;
o->oVelY = 0.0f;
o->oScuttlebugUnkFC = 0;
@ -105,7 +105,7 @@ void bhv_scuttlebug_loop(void) {
else
sp18 = 3.0f;
cur_obj_init_animation_with_accel_and_sound(0, sp18);
if (o->oMoveFlags & 3)
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND)
set_obj_anim_with_accel_and_sound(1, 23, SOUND_OBJ2_SCUTTLEBUG_WALK);
if (o->parentObj != o) {
if (obj_is_hidden(o))

View File

@ -32,7 +32,7 @@ static void skeeter_spawn_waves(void) {
}
static void skeeter_act_idle(void) {
if (o->oMoveFlags & 0x00000003) {
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
cur_obj_init_animation_with_sound(3);
o->oForwardVel = 0.0f;
@ -42,7 +42,7 @@ static void skeeter_act_idle(void) {
} else {
cur_obj_init_animation_with_sound(1);
if (o->oMoveFlags & 0x00000010) {
if (o->oMoveFlags & OBJ_MOVE_AT_WATER_SURFACE) {
skeeter_spawn_waves();
if (o->oTimer > 60
&& obj_smooth_turn(&o->oSkeeterUnk1AC, &o->oMoveAngleYaw, o->oSkeeterTargetAngle, 0.02f,
@ -61,13 +61,13 @@ static void skeeter_act_idle(void) {
}
static void skeeter_act_lunge(void) {
if (!(o->oMoveFlags & 0x00000010)) {
if (!(o->oMoveFlags & OBJ_MOVE_AT_WATER_SURFACE)) {
o->oAction = SKEETER_ACT_IDLE;
} else {
skeeter_spawn_waves();
cur_obj_init_animation_with_sound(0);
if (o->oMoveFlags & 0x00000200) {
if (o->oMoveFlags & OBJ_MOVE_HIT_WALL) {
o->oMoveAngleYaw = cur_obj_reflect_move_angle_off_wall();
o->oForwardVel *= 0.3f;
o->oFlags &= ~0x00000008;
@ -92,7 +92,7 @@ static void skeeter_act_lunge(void) {
static void skeeter_act_walk(void) {
f32 sp24;
if (!(o->oMoveFlags & 0x00000003)) {
if (!(o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND)) {
o->oAction = SKEETER_ACT_IDLE;
} else {
obj_forward_vel_approach(o->oSkeeterUnkFC, 0.4f);

View File

@ -124,7 +124,7 @@ static void triplet_butterfly_act_explode(void) {
obj_check_attacks(&sTripletButterflyExplodeHitbox, -1);
if (o->oAction == -1 || (o->oMoveFlags & 0x00000200) || o->oTimer >= 158) {
if (o->oAction == -1 || (o->oMoveFlags & OBJ_MOVE_HIT_WALL) || o->oTimer >= 158) {
o->oPosY += o->oGraphYOffset;
spawn_object(o, MODEL_EXPLOSION, bhvExplosion);
obj_mark_for_deletion(o);

View File

@ -48,7 +48,7 @@ Gfx *geo_update_projectile_pos_from_parent_copy(s32 run,UNUSED struct GraphNode
obj = (struct Object*)gCurGraphNodeObject;
if (obj->prevObj != NULL) {
create_transformation_from_matrices(mtx2, mtx, gCurGraphNodeCamera->matrixPtr);
create_transformation_from_matrices(mtx2, mtx, *gCurGraphNodeCamera->matrixPtr);
obj_update_pos_from_parent_transformation(mtx2, obj->prevObj);
obj_set_gfx_pos_from_pos(obj->prevObj);
}
@ -299,7 +299,8 @@ void ukiki_act_jump(void) {
if (o->oSubAction == 0) {
if (o->oTimer == 0) {
cur_obj_set_y_vel_and_animation(random_float() * 10.0f + 45.0f, UKIKI_ANIM_JUMP);
} else if (o->oMoveFlags & OBJ_MOVE_MASK_NOT_AIR) {
} else if (o->oMoveFlags & (OBJ_MOVE_MASK_ON_GROUND | OBJ_MOVE_AT_WATER_SURFACE
| OBJ_MOVE_UNDERWATER_ON_GROUND)) {
o->oSubAction++;
o->oVelY = 0.0f;
}
@ -316,22 +317,20 @@ void ukiki_act_jump(void) {
/**
* Waypoints that lead from the top of the mountain to the cage.
*
* TODO: Convert to an array of waypoints, perhaps? -1 is tricky.
*/
s16 sCageUkikiPath[] = {
0, 1011, 2306, -285,
0, 1151, 2304, -510,
0, 1723, 1861, -964,
0, 2082, 1775, -1128,
0, 2489, 1717, -1141,
0, 2662, 1694, -1140,
0, 2902, 1536, -947,
0, 2946, 1536, -467,
0, 2924, 1536, 72,
0, 2908, 1536, 536,
0, 2886, 1536, 783,
-1,
static Trajectory sCageUkikiPath[] = {
TRAJECTORY_POS(0, /*pos*/ 1011, 2306, -285),
TRAJECTORY_POS(0, /*pos*/ 1151, 2304, -510),
TRAJECTORY_POS(0, /*pos*/ 1723, 1861, -964),
TRAJECTORY_POS(0, /*pos*/ 2082, 1775, -1128),
TRAJECTORY_POS(0, /*pos*/ 2489, 1717, -1141),
TRAJECTORY_POS(0, /*pos*/ 2662, 1694, -1140),
TRAJECTORY_POS(0, /*pos*/ 2902, 1536, -947),
TRAJECTORY_POS(0, /*pos*/ 2946, 1536, -467),
TRAJECTORY_POS(0, /*pos*/ 2924, 1536, 72),
TRAJECTORY_POS(0, /*pos*/ 2908, 1536, 536),
TRAJECTORY_POS(0, /*pos*/ 2886, 1536, 783),
TRAJECTORY_END(),
};
/**
@ -358,8 +357,8 @@ void ukiki_act_go_to_cage(void) {
switch(o->oSubAction) {
case UKIKI_SUB_ACT_CAGE_RUN_TO_CAGE:
cur_obj_init_animation_with_sound(UKIKI_ANIM_RUN);
o->oPathedWaypointsS16 = sCageUkikiPath;
o->oPathedStartWaypoint = (struct Waypoint *) sCageUkikiPath;
if (cur_obj_follow_path(0) != PATH_REACHED_END) {
o->oForwardVel = 10.0f;
@ -470,7 +469,7 @@ void (*sUkikiActions[])(void) = {
ukiki_act_wait_to_respawn,
ukiki_act_unused_turn,
ukiki_act_return_home,
};
};
/**
* Called via the main behavior function when Ukiki is either nothing

View File

@ -122,13 +122,13 @@ void whomp_act_4(void) {
}
void whomp_act_5(void) {
if (o->oSubAction == 0 && o->oMoveFlags & 1) {
if (o->oSubAction == 0 && o->oMoveFlags & OBJ_MOVE_LANDED) {
cur_obj_play_sound_2(SOUND_OBJ_WHOMP_LOWPRIO);
cur_obj_shake_screen(SHAKE_POS_SMALL);
o->oVelY = 0.0f;
o->oSubAction++;
}
if (o->oMoveFlags & 2)
if (o->oMoveFlags & OBJ_MOVE_ON_GROUND)
o->oAction = 6;
}

View File

@ -554,7 +554,7 @@ void debug_print_obj_move_flags(void) {
if (gCurrentObject->oMoveFlags & OBJ_MOVE_IN_AIR) {
print_debug_top_down_objectinfo("SKY %x", gCurrentObject->oMoveFlags);
}
if (gCurrentObject->oMoveFlags & OBJ_MOVE_8) {
if (gCurrentObject->oMoveFlags & OBJ_MOVE_OUT_SCOPE) {
print_debug_top_down_objectinfo("OUT SCOPE %x", gCurrentObject->oMoveFlags);
}
#endif

View File

@ -1582,8 +1582,7 @@ void sink_mario_in_quicksand(struct MarioState *m) {
struct Object *o = m->marioObj;
if (o->header.gfx.throwMatrix) {
// TODO: throwMatrix should probably be an actual matrix pointer
*(f32 *) ((u8 *) o->header.gfx.throwMatrix + 0x34) -= m->quicksandDepth;
(*o->header.gfx.throwMatrix)[3][1] -= m->quicksandDepth;
}
o->header.gfx.pos[1] -= m->quicksandDepth;

View File

@ -61,7 +61,7 @@ struct LandingAction sBackflipLandAction = {
4, 0, ACT_FREEFALL, ACT_BACKFLIP_LAND_STOP, ACT_BACKFLIP, ACT_FREEFALL, ACT_BEGIN_SLIDING,
};
Mat4 D_80339F50[2];
Mat4 sFloorAlignMatrix[2];
s16 tilt_body_running(struct MarioState *m) {
s16 pitch = find_floor_slope(m, 0);
@ -89,8 +89,8 @@ void play_step_sound(struct MarioState *m, s16 frame1, s16 frame2) {
void align_with_floor(struct MarioState *m) {
m->pos[1] = m->floorHeight;
mtxf_align_terrain_triangle(D_80339F50[m->unk00], m->pos, m->faceAngle[1], 40.0f);
m->marioObj->header.gfx.throwMatrix = &D_80339F50[m->unk00];
mtxf_align_terrain_triangle(sFloorAlignMatrix[m->unk00], m->pos, m->faceAngle[1], 40.0f);
m->marioObj->header.gfx.throwMatrix = &sFloorAlignMatrix[m->unk00];
}
s32 begin_walking_action(struct MarioState *m, f32 forwardVel, u32 action, u32 actionArg) {

View File

@ -574,7 +574,7 @@ Gfx *geo_switch_mario_hand_grab_pos(s32 callContext, struct GraphNode *b, Mat4 *
// This is why it won't update during a pause buffered hitstun or when the camera is very far
// away.
get_pos_from_transform_mtx(marioState->marioBodyState->heldObjLastPosition, *curTransform,
gCurGraphNodeCamera->matrixPtr);
*gCurGraphNodeCamera->matrixPtr);
}
return NULL;
}

View File

@ -15,6 +15,7 @@
#include "game_init.h"
#include "ingame_menu.h"
#include "interaction.h"
#include "level_misc_macros.h"
#include "level_table.h"
#include "level_update.h"
#include "levels/bob/header.h"
@ -235,7 +236,7 @@ void obj_orient_graph(struct Object *obj, f32 normalX, f32 normalY, f32 normalZ)
surfaceNormals[2] = normalZ;
mtxf_align_terrain_normal(*throwMatrix, surfaceNormals, objVisualPosition, obj->oFaceAngleYaw);
obj->header.gfx.throwMatrix = (void *) throwMatrix;
obj->header.gfx.throwMatrix = throwMatrix;
}
/**

View File

@ -42,7 +42,7 @@ Gfx *geo_update_projectile_pos_from_parent(s32 callContext, UNUSED struct GraphN
if (callContext == GEO_CONTEXT_RENDER) {
sp1C = (struct Object *) gCurGraphNodeObject; // TODO: change global type to Object pointer
if (sp1C->prevObj) {
create_transformation_from_matrices(sp20, mtx, gCurGraphNodeCamera->matrixPtr);
create_transformation_from_matrices(sp20, mtx, *gCurGraphNodeCamera->matrixPtr);
obj_update_pos_from_parent_transformation(sp20, sp1C->prevObj);
obj_set_gfx_pos_from_pos(sp1C->prevObj);
}
@ -1285,7 +1285,7 @@ static void cur_obj_move_update_underwater_flags(void) {
}
static void cur_obj_move_update_ground_air_flags(UNUSED f32 gravity, f32 bounciness) {
o->oMoveFlags &= ~OBJ_MOVE_13;
o->oMoveFlags &= ~OBJ_MOVE_BOUNCE;
if (o->oPosY < o->oFloorHeight) {
// On the first frame that we touch the ground, set OBJ_MOVE_LANDED.
@ -1305,9 +1305,9 @@ static void cur_obj_move_update_ground_air_flags(UNUSED f32 gravity, f32 bouncin
}
if (o->oVelY > 5.0f) {
//! If OBJ_MOVE_13 tracks bouncing, it overestimates, since velY
// could be > 5 here without bounce (e.g. jump into misa)
o->oMoveFlags |= OBJ_MOVE_13;
//! This overestimates since velY could be > 5 here
//! without bounce (e.g. jump into misa).
o->oMoveFlags |= OBJ_MOVE_BOUNCE;
}
} else {
o->oMoveFlags &= ~OBJ_MOVE_LANDED;
@ -1379,7 +1379,8 @@ void cur_obj_move_y(f32 gravity, f32 bounciness, f32 buoyancy) {
}
}
if (o->oMoveFlags & OBJ_MOVE_MASK_33) {
if (o->oMoveFlags & (OBJ_MOVE_MASK_ON_GROUND | OBJ_MOVE_AT_WATER_SURFACE
| OBJ_MOVE_UNDERWATER_OFF_GROUND)) {
o->oMoveFlags &= ~OBJ_MOVE_IN_AIR;
} else {
o->oMoveFlags |= OBJ_MOVE_IN_AIR;
@ -1770,7 +1771,7 @@ static void cur_obj_update_floor_and_resolve_wall_collisions(s16 steepSlopeDegre
if (o->activeFlags & (ACTIVE_FLAG_FAR_AWAY | ACTIVE_FLAG_IN_DIFFERENT_ROOM)) {
cur_obj_update_floor();
o->oMoveFlags &= ~OBJ_MOVE_MASK_HIT_WALL_OR_IN_WATER;
o->oMoveFlags &= ~(OBJ_MOVE_HIT_WALL | OBJ_MOVE_MASK_IN_WATER);
if (o->oPosY > o->oFloorHeight) {
o->oMoveFlags |= OBJ_MOVE_IN_AIR;
@ -1939,7 +1940,7 @@ void obj_set_throw_matrix_from_transform(struct Object *obj) {
obj_apply_scale_to_transform(obj);
}
obj->header.gfx.throwMatrix = obj->transform;
obj->header.gfx.throwMatrix = &obj->transform;
//! Sets scale of gCurrentObject instead of obj. Not exploitable since this
// function is only called with obj = gCurrentObject
@ -1957,7 +1958,7 @@ void obj_build_transform_relative_to_parent(struct Object *obj) {
obj->oPosY = obj->transform[3][1];
obj->oPosZ = obj->transform[3][2];
obj->header.gfx.throwMatrix = obj->transform;
obj->header.gfx.throwMatrix = &obj->transform;
//! Sets scale of gCurrentObject instead of obj. Not exploitable since this
// function is only called with obj = gCurrentObject
@ -2250,23 +2251,23 @@ static void stub_obj_helpers_2(void) {
}
s32 cur_obj_set_direction_table(s8 *a0) {
o->oToxBoxUnk1AC = a0;
o->oToxBoxUnk1B0 = 0;
o->oToxBoxMovementPattern = a0;
o->oToxBoxMovementStep = 0;
return *(s8 *) o->oToxBoxUnk1AC;
return *(s8 *) o->oToxBoxMovementPattern;
}
s32 cur_obj_progress_direction_table(void) {
s8 spF;
s8 *sp8 = o->oToxBoxUnk1AC;
s32 sp4 = o->oToxBoxUnk1B0 + 1;
s8 *sp8 = o->oToxBoxMovementPattern;
s32 sp4 = o->oToxBoxMovementStep + 1;
if (sp8[sp4] != -1) {
spF = sp8[sp4];
o->oToxBoxUnk1B0++;
o->oToxBoxMovementStep++;
} else {
spF = sp8[0];
o->oToxBoxUnk1B0 = 0;
o->oToxBoxMovementStep = 0;
}
return spF;
@ -2763,7 +2764,7 @@ void cur_obj_align_gfx_with_floor(void) {
floorNormal[2] = floor->normal.z;
mtxf_align_terrain_normal(o->transform, floorNormal, position, o->oFaceAngleYaw);
o->header.gfx.throwMatrix = o->transform;
o->header.gfx.throwMatrix = &o->transform;
}
}

View File

@ -267,10 +267,15 @@ static void geo_process_perspective(struct GraphNodePerspective *node) {
* range of this node.
*/
static void geo_process_level_of_detail(struct GraphNodeLevelOfDetail *node) {
#ifdef GBI_FLOATS
Mtx *mtx = gMatStackFixed[gMatStackIndex];
s16 distanceFromCam = (s32) -mtx->m[3][2]; // z-component of the translation column
#else
// The fixed point Mtx type is defined as 16 longs, but it's actually 16
// shorts for the integer parts followed by 16 shorts for the fraction parts
s16 *mtx = (s16 *) gMatStackFixed[gMatStackIndex];
s16 distanceFromCam = -mtx[14]; // z-component of the translation column
Mtx *mtx = gMatStackFixed[gMatStackIndex];
s16 distanceFromCam = -GET_HIGH_S16_OF_32(mtx->m[1][3]); // z-component of the translation column
#endif
if (node->minDistance <= distanceFromCam && distanceFromCam < node->maxDistance) {
if (node->node.children != 0) {
@ -321,7 +326,7 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
gMatStackFixed[gMatStackIndex] = mtx;
if (node->fnNode.node.children != 0) {
gCurGraphNodeCamera = node;
node->matrixPtr = gMatStack[gMatStackIndex];
node->matrixPtr = &gMatStack[gMatStackIndex];
geo_process_node_and_siblings(node->fnNode.node.children);
gCurGraphNodeCamera = NULL;
}
@ -646,7 +651,7 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
if (gCurGraphNodeCamera != NULL && gCurGraphNodeObject != NULL) {
if (gCurGraphNodeHeldObject != NULL) {
get_pos_from_transform_mtx(shadowPos, gMatStack[gMatStackIndex],
gCurGraphNodeCamera->matrixPtr);
*gCurGraphNodeCamera->matrixPtr);
shadowScale = node->shadowScale;
} else {
vec3f_copy(shadowPos, gCurGraphNodeObject->pos);
@ -686,7 +691,7 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
mtx = alloc_display_list(sizeof(*mtx));
gMatStackIndex++;
mtxf_translate(mtxf, shadowPos);
mtxf_mul(gMatStack[gMatStackIndex], mtxf, gCurGraphNodeCamera->matrixPtr);
mtxf_mul(gMatStack[gMatStackIndex], mtxf, *gCurGraphNodeCamera->matrixPtr);
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
if (gShadowAboveWaterOrLava == 1) {
@ -800,7 +805,7 @@ static void geo_process_object(struct Object *node) {
if (node->header.gfx.unk18 == gCurGraphNodeRoot->areaIndex) {
if (node->header.gfx.throwMatrix != NULL) {
mtxf_mul(gMatStack[gMatStackIndex + 1], (void *) node->header.gfx.throwMatrix,
mtxf_mul(gMatStack[gMatStackIndex + 1], *node->header.gfx.throwMatrix,
gMatStack[gMatStackIndex]);
} else if (node->header.gfx.node.flags & GRAPH_RENDER_CYLBOARD) {
mtxf_cylboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex],
@ -815,7 +820,7 @@ static void geo_process_object(struct Object *node) {
mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1],
node->header.gfx.scale);
node->header.gfx.throwMatrix = gMatStack[++gMatStackIndex];
node->header.gfx.throwMatrix = &gMatStack[++gMatStackIndex];
node->header.gfx.cameraToObject[0] = gMatStack[gMatStackIndex][3][0];
node->header.gfx.cameraToObject[1] = gMatStack[gMatStackIndex][3][1];
node->header.gfx.cameraToObject[2] = gMatStack[gMatStackIndex][3][2];
@ -886,7 +891,7 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
translation[2] = node->translation[2] / 4.0f;
mtxf_translate(mat, translation);
mtxf_copy(gMatStack[gMatStackIndex + 1], (void *) gCurGraphNodeObject->throwMatrix);
mtxf_copy(gMatStack[gMatStackIndex + 1], *gCurGraphNodeObject->throwMatrix);
gMatStack[gMatStackIndex + 1][3][0] = gMatStack[gMatStackIndex][3][0];
gMatStack[gMatStackIndex + 1][3][1] = gMatStack[gMatStackIndex][3][1];
gMatStack[gMatStackIndex + 1][3][2] = gMatStack[gMatStackIndex][3][2];

View File

@ -54,31 +54,69 @@ static void parse_error(const char *filename, int lineNum, const char *msgfmt, .
// Reads the whole file and returns a null-terminated buffer with its contents
void *read_text_file(const char *filename)
{
FILE *file = fopen(filename, "rb");
uint8_t *buffer;
size_t size;
if (strcmp(filename, "-") != 0)
{
FILE *file = fopen(filename, "rb");
uint8_t *buffer;
size_t size;
if (file == NULL)
fatal_error("failed to open file '%s' for reading: %s", filename, strerror(errno));
if (file == NULL)
fatal_error("failed to open file '%s' for reading: %s", filename, strerror(errno));
// get size
fseek(file, 0, SEEK_END);
size = ftell(file);
// get size
fseek(file, 0, SEEK_END);
size = ftell(file);
// allocate buffer
buffer = malloc(size + 1);
// allocate buffer
buffer = malloc(size + 1);
if (buffer == NULL)
fatal_error("could not allocate buffer of size %u", (uint32_t)(size + 1));
// read file
fseek(file, 0, SEEK_SET);
if (fread(buffer, size, 1, file) != 1)
fatal_error("error reading from file '%s': %s", filename, strerror(errno));
// read file
fseek(file, 0, SEEK_SET);
if (fread(buffer, size, 1, file) != 1)
fatal_error("error reading from file '%s': %s", filename, strerror(errno));
// null-terminate the buffer
buffer[size] = 0;
// null-terminate the buffer
buffer[size] = 0;
fclose(file);
fclose(file);
return buffer;
return buffer;
}
else
{
size_t size = 0;
size_t capacity = 1024;
uint8_t *buffer = malloc(capacity + 1);
if (buffer == NULL)
fatal_error("could not allocate buffer of size %u", (uint32_t)(capacity + 1));
for (;;)
{
size += fread(buffer + size, 1, capacity - size, stdin);
if (size == capacity)
{
capacity *= 2;
buffer = realloc(buffer, capacity + 1);
if (buffer == NULL)
fatal_error("could not allocate buffer of size %u", (uint32_t)(capacity + 1));
}
else if (feof(stdin))
{
break;
}
else
{
fatal_error("error reading from stdin: %s", strerror(errno));
}
}
// null-terminate the buffer
buffer[size] = 0;
return buffer;
}
}
static char *skip_whitespace(char *str)
@ -351,7 +389,7 @@ static char *convert_string(char *pos, FILE *fout, const char *inputFileName, ch
static void convert_file(const char *infilename, const char *outfilename)
{
char *in = read_text_file(infilename);
FILE *fout = fopen(outfilename, "wb");
FILE *fout = strcmp(outfilename, "-") != 0 ? fopen(outfilename, "wb") : stdout;
if (fout == NULL)
fatal_error("failed to open file '%s' for writing: %s", strerror(errno));
@ -436,7 +474,8 @@ static void convert_file(const char *infilename, const char *outfilename)
eof:
fwrite(start, pos - start, 1, fout);
fclose(fout);
if (strcmp(outfilename, "-") != 0)
fclose(fout);
free(in);
}