Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
foliage.c
Go to the documentation of this file.
1#include "foliage.h"
2#include "npc.h"
3#include "model.h"
4#include "effects.h"
5
6// how many times to shake LEFT-RIGHT before stopping
7#define SHAKE_CYCLES 5
8
9// ShakeTree and SearchBush can be invoked from battle
10API_CALLABLE(GetActorPos);
11
12static void foliage_setup_shear_mtx(Matrix4f mtx, f32 scale, f32 xAmount, f32 zAmount) {
13 guMtxIdentF(mtx);
14 mtx[1][0] = scale * xAmount;
15 mtx[1][1] = 1.0f;
16 mtx[1][2] = scale * zAmount;
17}
18
19static void foliage_apply_model_shear(s32 modelID, f32 scale, f32 dx, f32 pivotY, f32 dz) {
22 Matrix4f mtx;
23
24 if (!model) {
25 return;
26 }
27
28 if (!(model->flags & MODEL_FLAG_HAS_TRANSFORM)) {
29 guTranslateF(model->userTransformMtx, 0.0f, pivotY, 0.0f);
30 foliage_setup_shear_mtx(mtx, scale, dx, dz);
31 guMtxCatF(mtx, model->userTransformMtx, model->userTransformMtx);
32 guTranslateF(mtx, 0.0f, -pivotY, 0.0f);
33 guMtxCatF(mtx, model->userTransformMtx, model->userTransformMtx);
35 } else {
36 guTranslateF(mtx, 0.0f, pivotY, 0.0f);
37 guMtxCatF(mtx, model->userTransformMtx, model->userTransformMtx);
38 foliage_setup_shear_mtx(mtx, scale, dx, dz);
39 guMtxCatF(mtx, model->userTransformMtx, model->userTransformMtx);
40 guTranslateF(mtx, 0.0f, -pivotY, 0.0f);
41 guMtxCatF(mtx, model->userTransformMtx, model->userTransformMtx);
42 }
43}
44
45static void foliage_clear_model_shear(s32 modelID) {
48
49 if (!model) {
50 return;
51 }
52
53 guMtxIdentF(model->userTransformMtx);
54
55 if (!(model->flags & MODEL_FLAG_HAS_TRANSFORM)) {
57 }
58}
59
60API_CALLABLE(ShakeFoliageModels) {
61 Bytecode* args = script->ptrReadPos;
62
64 s32 soundID = evt_get_variable(script, *args++);
65 f32 scale = evt_get_float_variable(script, *args++);
68
69 enum {
70 SHAKE_LEFT = 0,
71 SHAKE_RIGHT = 1,
72 SHAKE_DONE = 2,
73 };
74
75 if (isInitialCall) {
76 script->functionTemp[0] = SHAKE_LEFT;
77 script->functionTemp[1] = 0; // cyclesDone
78 }
79
80 // do nothing for empty or missing model list
81 if (list == NULL || list->count <= 0) {
82 return ApiStatus_DONE2;
83 }
84
85 switch (script->functionTemp[0]) {
86 case SHAKE_LEFT: {
87 for (s32 i = 0; i < list->count; i++) {
88 s32 modelID = list->models[i];
89 foliage_apply_model_shear(modelID, scale, dx, pivotY, 0.0f);
90
91 // only play sound ONCE, for the first model on the first iteration
92 if (script->functionTemp[1] == 0 && i == 0) {
93 f32 x, y, z;
94 f32 sx, sy, sz;
95
97 get_model_center_and_size(modelID, &x, &y, &z, &sx, &sy, &sz);
99 }
100 }
101 script->functionTemp[0] = SHAKE_RIGHT;
102 return ApiStatus_BLOCK;
103 }
104
105 case SHAKE_RIGHT: {
106 for (s32 i = 0; i < list->count; i++) {
107 s32 modelID = list->models[i];
108 foliage_apply_model_shear(modelID, scale, -dx, pivotY, 0.0f);
109 }
110
111 script->functionTemp[1]++; // cyclesDone++
112
113 if (script->functionTemp[1] < SHAKE_CYCLES) {
114 script->functionTemp[0] = SHAKE_LEFT;
115 } else {
116 script->functionTemp[0] = SHAKE_DONE;
117 }
118 return ApiStatus_BLOCK;
119 }
120
121 case SHAKE_DONE: {
122 for (s32 i = 0; i < list->count; i++) {
123 s32 modelID = list->models[i];
124 foliage_clear_model_shear(modelID);
125 }
126 // all done
127 return ApiStatus_DONE2;
128 }
129
130 default:
131 return ApiStatus_DONE2;
132 }
133}
134
135API_CALLABLE(SpawnFoliageDrops) {
136 Bytecode* args = script->ptrReadPos;
138
139 if (!list) {
140 return ApiStatus_DONE2;
141 }
142
143 for (s32 i = 0; i < list->count; i++) {
144 FoliageDrop* drop = &list->drops[i];
145
146 if (drop->spawnFlag == 0) {
148 drop->pos.x, drop->pos.y, drop->pos.z,
149 drop->spawnMode, drop->pickupFlag);
150 } else {
152 if (!alreadySpawned) {
153 evt_set_variable(script, drop->spawnFlag, true);
155 drop->pos.x, drop->pos.y, drop->pos.z,
156 drop->spawnMode, drop->pickupFlag);
157 }
158 }
159 }
160
161 return ApiStatus_DONE2;
162}
163
164API_CALLABLE(SpawnShakeTreeFX) {
165 Bytecode* args = script->ptrReadPos;
168
169 if (!list) {
170 return ApiStatus_DONE2;
171 }
172
173 for (s32 i = 0; i < list->count; i++) {
174 Vec3i* pos = &list->vectors[i];
175
176 switch(treeType) {
178 fx_drop_leaves(0, pos->x, pos->y, pos->z, 100);
179 break;
181 fx_sparkles(2, pos->x, pos->y, pos->z, 50);
182 fx_sparkles(2, pos->x, pos->y, pos->z, 50);
183 break;
184 }
185 }
186
187 return ApiStatus_DONE2;
188}
189
191 // get player Y to find bottom of bush
195 Else
197 EndIf
198 // read SearchBushConfig
200 BufRead4(LVar1, LVar2, LVar3, LVar4) // bush models, drops, vectors, callback
201 BufRead1(LVar5) // bush type
202 Thread
205 Thread
208 Wait(15)
209 IfNe(LVar4, 0) // has callback?
211 EndIf
212 Return
213 End
214};
215
217 SetTimescale(Float(2.0))
218 // get player Y to find bottom of tree
222 Else
223 Call(GetPlayerPos, LVar1, LVarF, LVar2) // get player Y (ignore X and Z)
224 EndIf
225 // read ShakeTreeConfig
227 BufRead4(LVar1, LVar2, LVar3, LVar4) // leaf models, trunk models, drops, vectors
228 BufRead2(LVar5, LVar6) // callback, tree type
229 Thread
232 Thread
235 Thread
238 Thread
241 IfNe(LVar5, 0) // has callback?
243 EndIf
244 Wait(15)
245 Return
246 End
247};
BSS s32 PopupMenu_SelectedIndex
s32 b32
f32 Matrix4f[4][4]
Bytecode EvtScript[]
Vec3s pos
Definition demo_api.c:17
#define sfx_play_sound_at_position
#define guTranslateF
#define guMtxCatF
@ MODEL_FLAG_HAS_TRANSFORM
Definition enums.h:3952
@ MODEL_FLAG_MATRIX_DIRTY
Definition enums.h:3954
@ CONTEXT_BATTLE
Definition enums.h:3563
@ SOUND_SMACK_TREE
Definition enums.h:790
@ SOUND_SEARCH_BUSH
Definition enums.h:776
@ SOUND_SHAKE_TREE_LEAVES
Definition enums.h:791
@ ACTOR_PLAYER
Definition enums.h:2118
@ SOUND_SPACE_DEFAULT
Definition enums.h:1740
#define ApiStatus_DONE2
Definition evt.h:119
s32 Bytecode
Definition evt.h:7
#define ApiStatus_BLOCK
Definition evt.h:117
EvtScript EVS_SearchBush
Execute this script to animate a shaking bush and potentially spawn an item from it.
Definition foliage.c:190
#define SHAKE_CYCLES
Definition foliage.c:7
EvtScript EVS_ShakeTree
Execute this script to animate a shaking tree and potentially spawn items from it.
Definition foliage.c:216
Vec3i vectors[VLA]
Definition foliage.h:44
FoliageDrop drops[VLA]
Definition foliage.h:39
s32 models[VLA]
Definition foliage.h:26
@ TREE_TYPE_SPARKLY
Definition foliage.h:21
@ TREE_TYPE_STANDARD
Definition foliage.h:20
s32 evt_get_variable(Evt *script, Bytecode var)
Definition evt.c:1725
s32 get_model_list_index_from_tree_index(s32 treeIndex)
Definition model.c:3396
s32 evt_set_variable(Evt *script, Bytecode var, s32 value)
Definition evt.c:1882
s32 make_item_entity_nodelay(s32 itemID, f32 x, f32 y, f32 z, s32 itemSpawnMode, s32 pickupVar)
struct Model * get_model_from_list_index(s32 listIndex)
Definition model.c:3314
f32 evt_get_float_variable(Evt *script, Bytecode var)
Definition evt.c:1965
void get_model_center_and_size(u16 modelID, f32 *centerX, f32 *centerY, f32 *centerZ, f32 *sizeX, f32 *sizeY, f32 *sizeZ)
Definition model.c:3432
Definition model.h:59
ApiStatus GetPlayerPos(Evt *script, b32 isInitialCall)
ApiStatus GetGameContext(Evt *script, b32 isInitialCall)
Get current GameContext from GameStatus Use this to tell whether the script is executing in world or ...
#define Else
Marks the end of an if statement and the start of the else block.
Definition macros.h:296
#define LVar6
Definition macros.h:155
#define LVarF
Definition macros.h:164
#define IfNe(LVAR, RVAR)
Marks the beginning of an if statement that only executes if LVAR != RVAR.
Definition macros.h:273
#define End
Signals the end of EVT script data. A script missing this will likely crash on load.
Definition macros.h:214
#define UseBuf(INT_PTR)
Loads a s32 pointer for use with subsequent EVT_BUF_READ commands.
Definition macros.h:390
#define BufRead4(VAR1, VAR2, VAR3, VAR4)
Consumes the next four s32s from the buffer and stores them in the given variables.
Definition macros.h:402
#define BufRead1(VAR)
Consumes the next s32 from the buffer and stores it in the given variable.
Definition macros.h:393
#define Float(DOUBLE)
Definition macros.h:52
#define EndIf
Marks the end of an if statement or an else block.
Definition macros.h:299
#define LVar5
Definition macros.h:154
#define SetTimescale(TIMESCALE)
Sets the current thread's timescale. This is a multiplier applied to Wait and Wait_SECONDS.
Definition macros.h:517
#define ExecWait(EVT_SOURCE)
Launches a new child thread.
Definition macros.h:476
#define Thread
Marks the start of a thread block.
Definition macros.h:545
#define EndThread
Marks the end of a thread block.
Definition macros.h:548
#define LVar2
Definition macros.h:151
#define LVar1
Definition macros.h:150
#define Wait(NUM_FRAMES)
Blocks for the given number of frames.
Definition macros.h:255
#define BufRead2(VAR1, VAR2)
Consumes the next two s32s from the buffer and stores them in the given variables.
Definition macros.h:396
#define IfEq(LVAR, RVAR)
Marks the beginning of an if statement that only executes if LVAR == RVAR.
Definition macros.h:270
#define Call(FUNC, ARGS...)
Calls a given C EVT API function with any number of arguments.
Definition macros.h:577
#define LVar4
Definition macros.h:153
#define LVar3
Definition macros.h:152
#define LVar0
Definition macros.h:149
#define Return
Kills the current EVT thread.
Definition macros.h:218