Files
perfect_dark/src/game/sparks.c
T
2023-08-05 01:57:26 +02:00

526 lines
19 KiB
C

#include <ultra64.h>
#include "constants.h"
#include "game/dlights.h"
#include "game/camera.h"
#include "game/chr.h"
#include "game/gfxmemory.h"
#include "game/tex.h"
#include "game/sparks.h"
#include "game/file.h"
#include "bss.h"
#include "lib/vi.h"
#include "lib/rng.h"
#include "lib/mtx.h"
#include "data.h"
#include "types.h"
struct spark g_Sparks[100];
s32 g_NextSparkIndex;
u32 var800a3fc4;
struct sparkgroup g_SparkGroups[10];
s32 g_NextSparkGroupIndex;
u32 var800a4134;
u32 var800a4138;
u32 var800a413c;
u32 var800a4140;
u32 var800a4144;
u32 var800a4148;
u32 var800a414c;
struct sparktype g_SparkTypes[] = {
// weight
// | max age
// | | decel
// | | |
#if PAL
/*0x00*/ { 100, 28, 100, 1, 0, 0, 2.4, 50, 50, 15, 1, 0xffff80ff, 0xffffffff, 0.024 },
/*0x00*/ { 100, 28, 100, 1, 0, 0, 2.4, 50, 50, 15, 1, 0x80ffffff, 0xffffffff, 0.024 },
/*0x00*/ { 40, -1, 30, 30, 0, 0, 2.4, 29, 29, 5, 1, 0x301010ff, 0x401010ff, 0.024 },
/*0x00*/ { 40, -1, 300, 200, 0, 0, 0.18, 5, 5, 4, 1, 0xffffff40, 0x560011a0, 0.024 },
/*0x00*/ { 10, 1, 1200, 400, 0, 0, 0.18, 5, 5, 5, 1, 0xa0a0e000, 0xffffffff, 0.024 },
/*0x00*/ { 40, 10, 10, 10, 0, 0, 3.6000001430511, 150, 75, 5, 1, 0x00ff6aff, 0xffffffff, 0.024 },
/*0x00*/ { 15, 10, 20, 20, 0, 0, 0.78000003099442, 150, 75, 5, 1, 0xa0a0e0ff, 0xffffffff, 0.024 },
/*0x00*/ { 1, 1, 120, 2, 0, 0, 0, 50, 50, 5, 1, 0xffff80ff, 0xffffffff, 0.024 },
/*0x00*/ { 1, 1, 300, 50, 0, 0, 0, 5, 5, 5, 1, 0xffff8000, 0xffffffff, 0.024 },
/*0x00*/ { 1, 1, 400, 100, 0, 0, 0, 8, 8, 5, 1, 0xffff8000, 0xffffffff, 0.024 },
/*0x00*/ { 75, 100, 100, 1, 0, 0, 2.4, 50, 50, 15, 1, 0xffff80ff, 0xffffffff, 0.024 },
/*0x00*/ { 75, 100, 20, 5, 0, 0, 1.8000000715256, 50, 50, 20, 1, 0xa0a0e0ff, 0xffffffff, 0.024 },
/*0x00*/ { 20, 10, 100, 1, 0, 0, 2.4, 50, 50, 15, 1, 0xffff80ff, 0xffffffff, 0.024 },
/*0x00*/ { 20, 10, 20, 5, 0, 0, 1.8000000715256, 50, 50, 20, 1, 0xa0a0e0ff, 0xffffffff, 0.024 },
/*0x00*/ { 1, 0, 80, 1, 36, 6, 0, 100, 75, 15, 0, 0x0808f000, 0xffffffff, 0.024 },
/*0x00*/ { 70, 0, 150, 15, 0, 0, 7.2000002861023, 33, 8, 3, 0, 0x11112880, 0xaaaaaa40, 0.024 },
/*0x00*/ { 50, 28, 100, 1, 0, 0, 1.2, 50, 25, 10, 1, 0xffff80ff, 0xffffffff, 0.024 },
/*0x00*/ { 300, 100, 100, 2, 0, 0, 0.36, 25, 1, 40, 2, 0xffff80ff, 0xffffffff, 0.119 },
/*0x00*/ { 170, 80, 60, 5, 0, 0, 0.48000001907349, 25, 5, 10, 3, 0xa0a0e0ff, 0xffffffff, 0.119 },
/*0x00*/ { 120, 40, 30, 7, 0, 0, 0.24000000953674, 50, 5, 15, 3, 0xffff80ff, 0xffffffff, 0.119 },
/*0x00*/ { 80, 10, 10, 9, 0, 0, 0.12000000476837, 25, 5, 20, 3, 0xa0a0e0ff, 0xffffffff, 0.119 },
/*0x00*/ { 100, 1, 100, 50, 0, 0, 2.4, 25, 16, 15, 1, 0xffff80ff, 0xffffffff, 0.024 },
/*0x00*/ { 100, 28, 100, 1, 0, 0, 2.4, 100, 100, 30, 1, 0xff8080ff, 0xffff80ff, 0.024 },
/*0x00*/ { 100, 28, 100, 1, 0, 0, 2.4, 50, 50, 15, 1, 0x4fff4fff, 0xffffffff, 0.024 },
/*0x00*/ { 100, 28, 100, 1, 0, 0, 2.4, 50, 50, 15, 1, 0xffff7f7f, 0xffffffff, 0.024 },
/*0x00*/ { 40, -1, 30, 10, 0, 0, 2.4, 41, 29, 10, 1, 0x301010ff, 0x401010ff, 0.024 },
/*0x00*/ { 70, 0, 150, 15, 0, 0, 7.2000002861023, 33, 8, 3, 0, 0x1111a880, 0xaaaaff40, 0.024 },
#else
/*0x00*/ { 100, 28, 100, 1, 0, 0, 2, 60, 60, 15, 1, 0xffff80ff, 0xffffffff, 0.02 },
/*0x01*/ { 100, 28, 100, 1, 0, 0, 2, 60, 60, 15, 1, 0x80ffffff, 0xffffffff, 0.02 },
/*0x02*/ { 40, -1, 30, 30, 0, 0, 2, 35, 35, 5, 1, 0x301010ff, 0x401010ff, 0.02 },
/*0x03*/ { 40, -1, 300, 200, 0, 0, 0.15, 5, 5, 4, 1, 0xffffff40, 0x560011a0, 0.02 },
/*0x04*/ { 10, 1, 1200, 400, 0, 0, 0.15, 5, 5, 5, 1, 0xa0a0e000, 0xffffffff, 0.02 },
/*0x05*/ { 40, 10, 10, 10, 0, 0, 3, 180, 90, 5, 1, 0x00ff6aff, 0xffffffff, 0.02 },
/*0x06*/ { 15, 10, 20, 20, 0, 0, 0.65, 180, 90, 5, 1, 0xa0a0e0ff, 0xffffffff, 0.02 },
/*0x07*/ { 1, 1, 120, 2, 0, 0, 0, 60, 60, 5, 1, 0xffff80ff, 0xffffffff, 0.02 },
/*0x08*/ { 1, 1, 300, 50, 0, 0, 0, 5, 5, 5, 1, 0xffff8000, 0xffffffff, 0.02 },
/*0x09*/ { 1, 1, 400, 100, 0, 0, 0, 10, 10, 5, 1, 0xffff8000, 0xffffffff, 0.02 },
/*0x0a*/ { 75, 100, 100, 1, 0, 0, 2, 60, 60, 15, 1, 0xffff80ff, 0xffffffff, 0.02 },
/*0x0b*/ { 75, 100, 20, 5, 0, 0, 1.5, 60, 60, 20, 1, 0xa0a0e0ff, 0xffffffff, 0.02 },
/*0x0c*/ { 20, 10, 100, 1, 0, 0, 2, 60, 60, 15, 1, 0xffff80ff, 0xffffffff, 0.02 },
/*0x0d*/ { 20, 10, 20, 5, 0, 0, 1.5, 60, 60, 20, 1, 0xa0a0e0ff, 0xffffffff, 0.02 },
/*0x0e*/ { 1, 0, 80, 1, 30, 5, 0, 120, 90, 15, 0, 0x0808f000, 0xffffffff, 0.02 },
/*0x0f*/ { 70, 0, 150, 15, 0, 0, 6, 40, 10, 3, 0, 0x11112880, 0xaaaaaa40, 0.02 },
/*0x10*/ { 50, 28, 100, 1, 0, 0, 1, 60, 30, 10, 1, 0xffff80ff, 0xffffffff, 0.02 },
/*0x11*/ { 300, 100, 100, 2, 0, 0, 0.3, 30, 1, 40, 2, 0xffff80ff, 0xffffffff, 0.1 },
/*0x12*/ { 170, 80, 60, 5, 0, 0, 0.4, 30, 5, 10, 3, 0xa0a0e0ff, 0xffffffff, 0.1 },
/*0x13*/ { 120, 40, 30, 7, 0, 0, 0.2, 60, 5, 15, 3, 0xffff80ff, 0xffffffff, 0.1 },
/*0x14*/ { 80, 10, 10, 9, 0, 0, 0.1, 30, 5, 20, 3, 0xa0a0e0ff, 0xffffffff, 0.1 },
/*0x15*/ { 100, 1, 100, 50, 0, 0, 2, 30, 20, 15, 1, 0xffff80ff, 0xffffffff, 0.02 },
/*0x16*/ { 100, 28, 100, 1, 0, 0, 2, 120, 120, 30, 1, 0xff8080ff, 0xffff80ff, 0.02 },
/*0x17*/ { 100, 28, 100, 1, 0, 0, 2, 60, 60, 15, 1, 0x4fff4fff, 0xffffffff, 0.02 },
/*0x18*/ { 100, 28, 100, 1, 0, 0, 2, 60, 60, 15, 1, 0xffff7f7f, 0xffffffff, 0.02 },
/*0x19*/ { 40, -1, 30, 10, 0, 0, 2, 50, 35, 10, 1, 0x301010ff, 0x401010ff, 0.02 },
/*0x1a*/ { 70, 0, 150, 15, 0, 0, 6, 40, 10, 3, 0, 0x1111a880, 0xaaaaff40, 0.02 },
#endif
};
bool g_SparksAreActive = false;
void sparkCreate(struct coord *pos, struct sparktype *type)
{
f32 tmp;
f32 maxspeed = 0.0f;
s32 i;
struct spark *spark;
spark = &g_Sparks[g_NextSparkIndex];
g_NextSparkIndex = (g_NextSparkIndex + 1) % 100;
spark->pos.x = 0.0f;
spark->pos.y = 0.0f;
spark->pos.z = 0.0f;
spark->speed.x = (s32)(random() % (type->unk00 * 2 + 1)) - type->unk00;
spark->speed.y = (s32)(random() % (type->unk00 * 2 + 1)) - type->unk00;
spark->speed.z = (s32)(random() % (type->unk00 * 2 + 1)) - type->unk00;
if (spark->speed.y == 0.0f) {
spark->speed.y = -0.0001f;
}
for (i = 0; i < 3; i++) {
if (spark->speed.f[i] > maxspeed) {
maxspeed = spark->speed.f[i];
}
if (-spark->speed.f[i] > maxspeed) {
maxspeed = -spark->speed.f[i];
}
}
tmp = sqrtf(spark->speed.f[0] * spark->speed.f[0] + spark->speed.f[1] * spark->speed.f[1] + spark->speed.f[2] * spark->speed.f[2]);
spark->speed.x *= maxspeed / tmp;
spark->speed.y *= maxspeed / tmp;
spark->speed.z *= maxspeed / tmp;
spark->speed.y += type->unk00 / 2;
spark->speed.x += pos->x;
spark->speed.y += pos->y;
spark->speed.z += pos->z;
#if PAL
spark->speed.x *= 1.2f;
spark->speed.y *= 1.2f;
spark->speed.z *= 1.2f;
#endif
if (spark->speed.y == 0.0f) {
spark->speed.y = -0.0001f;
}
if (type->unk18 % 2) {
spark->ttl = random() % type->maxage;
} else {
spark->ttl = type->maxage;
}
}
/**
* This function handles an out-of-memory situation when creating a spark, by
* shrinking whichever spark group was about to be overwritten.
*/
void sparkgroupEnsureFreeSparkSlot(struct sparkgroup *group)
{
s32 i;
for (i = 0; i < ARRAYCOUNT(g_SparkGroups); i++) {
if (&g_SparkGroups[i] != group && g_SparkGroups[i].startindex == g_NextSparkIndex) {
g_SparkGroups[i].startindex = (g_SparkGroups[i].startindex + 1) % 100;
g_SparkGroups[i].numsparks--;
if (g_SparkGroups[i].numsparks == 0) {
g_SparkGroups[i].age = 0;
}
}
}
}
void sparksCreate(s32 room, struct prop *prop, struct coord *pos, struct coord *arg3, struct coord *arg4, s32 typenum)
{
struct sparkgroup *group = &g_SparkGroups[g_NextSparkGroupIndex];
struct sparktype *type = &g_SparkTypes[typenum];
struct coord grouppos;
s32 i;
if ((typenum == SPARKTYPE_BLOOD || typenum == SPARKTYPE_FLESH) && prop && prop->type == PROPTYPE_CHR) {
struct chrdata *chr = prop->chr;
u32 colours[3];
u32 stack;
chrGetBloodColour(chr->bodynum, NULL, colours);
if (typenum == SPARKTYPE_BLOOD) {
type->unk1c = colours[0];
type->unk20 = colours[1];
} else if (typenum == SPARKTYPE_FLESH) {
type->unk20 = colours[2];
}
} else if (typenum == SPARKTYPE_PAINT) {
type->unk1c = (random() % 2 ? 0xff000000 : 0) | (random() % 2 ? 0x00ff0000 : 0) | (random() % 2 ? 0x0000ff00 : 0) | 0xff;
if (type->unk1c == 0x000000ff) {
type->unk1c |= 0x0000ff00 << ((random() % 3) * 8);
}
type->unk20 = (random() % 2 ? 0xff000000 : 0) | (random() % 2 ? 0x00ff0000 : 0) | (random() % 2 ? 0x0000ff00 : 0) | 0xff;
if (type->unk20 == 0xff) {
type->unk20 |= 0x0000ff00 << ((random() % 3) * 8);
}
}
g_NextSparkGroupIndex = (g_NextSparkGroupIndex + 1) % ARRAYCOUNT(g_SparkGroups);
if (typenum == SPARKTYPE_SHALLOWWATER) {
if (group->age != 0) {
s32 newindex = -1;
for (i = 0; i < ARRAYCOUNT(g_SparkGroups) && newindex < 0; i++) {
if (g_SparkGroups[i].age == 0) {
newindex = i;
}
}
if (newindex == -1) {
return;
}
group = &g_SparkGroups[newindex];
}
}
if (arg3 != NULL && arg4 != NULL) {
f32 f0 = sqrtf(arg4->f[0] * arg4->f[0] + arg4->f[1] * arg4->f[1] + arg4->f[2] * arg4->f[2]);
arg4->x /= f0;
arg4->y /= f0;
arg4->z /= f0;
f0 = -2.0f * (arg3->f[0] * arg4->f[0] + arg3->f[1] * arg4->f[1] + arg3->f[2] * arg4->f[2]);
grouppos.x = arg3->x + f0 * arg4->f[0];
grouppos.y = arg3->y + f0 * arg4->f[1];
grouppos.z = arg3->z + f0 * arg4->f[2];
f0 = sqrtf(grouppos.f[0] * grouppos.f[0] + grouppos.f[1] * grouppos.f[1] + grouppos.f[2] * grouppos.f[2]);
if (f0 == 0.0f) {
f0 = 1.0f;
}
grouppos.x *= type->unk02 / f0;
grouppos.y *= type->unk02 / f0;
grouppos.z *= type->unk02 / f0;
} else if (arg3 != NULL && type->unk02 >= -1 && type->unk02 < 2) {
grouppos.x = arg3->x * 10.0f * type->unk02;
grouppos.y = arg3->y * 10.0f * type->unk02;
grouppos.z = arg3->z * 10.0f * type->unk02;
} else {
grouppos.x = 0.0f;
grouppos.y = 0.0f;
grouppos.z = 0.0f;
}
group->type = typenum;
group->age = 1;
group->startindex = g_NextSparkIndex;
group->numsparks = type->numsparks;
group->pos.x = pos->x;
group->pos.y = pos->y;
group->pos.z = pos->z;
group->room = room;
group->prop = prop;
for (i = 0; i < type->numsparks; i++) {
sparkgroupEnsureFreeSparkSlot(group);
sparkCreate(&grouppos, type);
}
switch (typenum) {
case SPARKTYPE_DEFAULT:
roomFlashLighting(group->room, 24, 32);
break;
case SPARKTYPE_ENVIRONMENTAL1:
if (g_Vars.stagenum != STAGE_CRASHSITE) {
roomFlashLighting(group->room, 32, 128);
}
break;
case SPARKTYPE_ENVIRONMENTAL2:
if (g_Vars.stagenum != STAGE_CRASHSITE) {
roomFlashLighting(group->room, 64, 128);
}
break;
case SPARKTYPE_ENVIRONMENTAL3:
if (g_Vars.stagenum != STAGE_CRASHSITE) {
roomFlashLighting(group->room, 200, 255);
}
break;
}
g_SparksAreActive = true;
}
Gfx *sparksRender(Gfx *gdl)
{
struct sparkgroup *group;
s32 axis;
bool render;
f32 f0;
f32 f12;
s32 i;
s32 j;
s32 k;
struct coord *campos;
struct sparktype *type;
Col *colours;
s32 index;
f32 sp13c;
f32 sp138;
Mtxf *mtx;
s32 v1;
struct coord sp124;
f32 sp120;
s32 diff1;
s32 diff2;
f32 frac;
Mtxf spd4;
if (g_SparksAreActive) {
if (ABS(g_Vars.currentplayer->cam_look.y) > ABS(g_Vars.currentplayer->cam_look.x)) {
axis = ABS(g_Vars.currentplayer->cam_look.z) > ABS(g_Vars.currentplayer->cam_look.y) ? 2 : 1;
} else {
axis = ABS(g_Vars.currentplayer->cam_look.z) > ABS(g_Vars.currentplayer->cam_look.x) ? 2 : 0;
}
texSelect(&gdl, &g_TexSparkConfigs[0], 4, 0, 2, 1, NULL);
gDPSetCycleType(gdl++, G_CYC_1CYCLE);
gDPSetColorDither(gdl++, G_CD_DISABLE);
gDPSetRenderMode(gdl++, G_RM_AA_ZB_XLU_SURF, G_RM_NOOP2);
gDPSetAlphaCompare(gdl++, G_AC_NONE);
gDPSetTextureLOD(gdl++, G_TL_TILE);
gDPSetTextureConvert(gdl++, G_TC_FILT);
gDPSetCombineMode(gdl++, G_CC_CUSTOM_04, G_CC_CUSTOM_04);
for (i = 0; i < ARRAYCOUNT(g_SparkGroups); i++) {
group = &g_SparkGroups[i];
if (group->age != 0) {
render = true;
sp138 = 1.0f;
if (group->prop) {
if ((group->prop->flags & PROPFLAG_ONTHISSCREENTHISTICK) == 0) {
render = false;
}
} else {
if ((g_Rooms[group->room].flags & ROOMFLAG_ONSCREEN) == 0) {
render = false;
}
}
if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) {
f0 = sqrtf((group->pos.f[0] - g_Vars.currentplayer->eraserpos.f[0]) * (group->pos.f[0] - g_Vars.currentplayer->eraserpos.f[0])
+ (group->pos.f[1] - g_Vars.currentplayer->eraserpos.f[1]) * (group->pos.f[1] - g_Vars.currentplayer->eraserpos.f[1])
+ (group->pos.f[2] - g_Vars.currentplayer->eraserpos.f[2]) * (group->pos.f[2] - g_Vars.currentplayer->eraserpos.f[2]));
f12 = g_Vars.currentplayer->eraserpropdist - 150.0f;
sp13c = f0 / g_Vars.currentplayer->eraserpropdist;
if (g_Vars.currentplayer->eraserpropdist < f0) {
render = false;
}
if (f12 < f0) {
sp138 = 1.0f - (f0 - f12) / 150.0f;
}
if (sp13c > 1.0f) {
sp13c = 1.0f;
}
}
if (render) {
campos = &g_Vars.currentplayer->cam_pos;
sp124.x = campos->x - group->pos.x;
sp124.y = campos->y - group->pos.y;
sp124.z = campos->z - group->pos.z;
sp120 = sqrtf(sp124.f[0] * sp124.f[0] + sp124.f[1] * sp124.f[1] + sp124.f[2] * sp124.f[2]);
if (sp120 > 20000.0f) {
render = false;
}
}
if (render) {
type = &g_SparkTypes[group->type];
colours = gfxAllocateColours(2);
if (USINGDEVICE(DEVICE_NIGHTVISION) || USINGDEVICE(DEVICE_IRSCANNER)) {
colours[0].word = PD_BE32(type->unk1c);
colours[1].word = PD_BE32(type->unk20);
} else if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) {
v1 = ((u32) (sp13c * 255.0f) << 24) | ((u32) ((1.0f - sp13c) * 255.0f) << 16);
// @bug? Second part also reads from type->unk1c
colours[0].word = PD_BE32(v1 | (u32) (sp138 * (f32) (type->unk1c & 0xff)) | 0x3f00);
colours[1].word = PD_BE32(v1 | (u32) (sp138 * (f32) (type->unk1c & 0xff)) | 0x3f00);
} else {
colours[0].word = PD_BE32(type->unk1c);
colours[1].word = PD_BE32(type->unk20);
}
if (type->unk12 < type->maxage && type->unk12 < group->age) {
diff1 = (type->maxage - type->unk12);
diff2 = group->age - type->unk12;
frac = (f32)(diff1 - diff2) / diff1;
colours[0].a *= frac;
colours[1].a *= frac;
}
gSPColor(gdl++, osVirtualToPhysical(colours), 2);
sp120 *= 0.2f;
sp120 *= viGetFovY() / 60.0f;
mtx4LoadIdentity(&spd4);
spd4.m[0][0] = 0.05f;
spd4.m[1][1] = 0.05f;
spd4.m[2][2] = 0.05f;
spd4.m[3][3] = 0.05f;
mtx4SetTranslation(&group->pos, &spd4);
mtx00015be0(camGetWorldToScreenMtxf(), &spd4);
mtx = gfxAllocateMatrix();
mtxF2L(&spd4, mtx);
gSPMatrix(gdl++, osVirtualToPhysical(mtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
index = group->startindex;
for (j = 0; j < group->numsparks; j++) {
struct spark *spark = &g_Sparks[index];
if (spark->ttl != 0) {
Vtx *vertices = gfxAllocateVertices(3);
f32 f2;
for (k = 0; k < 3; k++) {
vertices[k].s = 0;
vertices[k].t = 0;
}
f2 = sqrtf(spark->speed.f[0] * spark->speed.f[0] + spark->speed.f[1] * spark->speed.f[1] + spark->speed.f[2] * spark->speed.f[2]);
f2 = (sp120 + (type->unk04 + group->age * type->unk08)) / f2;
vertices[0].x = spark->pos.x;
vertices[0].y = spark->pos.y;
vertices[0].z = spark->pos.z;
vertices[0].colour = 4;
vertices[1].x = spark->pos.x + spark->speed.f[0] * f2;
vertices[1].y = spark->pos.y + spark->speed.f[1] * f2;
vertices[1].z = spark->pos.z + spark->speed.f[2] * f2;
vertices[1].colour = 0;
vertices[2].x = spark->pos.x + spark->speed.f[0] * f2;
vertices[2].y = spark->pos.y + spark->speed.f[1] * f2;
vertices[2].z = spark->pos.z + spark->speed.f[2] * f2;
vertices[2].colour = 0;
vertices[0].s = 128;
vertices[0].t = -256;
vertices[1].s = -32;
vertices[1].t = 496;
vertices[2].s = 288;
vertices[2].t = 496;
switch (axis) {
case 0:
if (ABS(spark->speed.z) > ABS(spark->speed.y)) {
vertices[1].y = vertices[1].y - type->unk06 - group->age * type->unk0a - (s32)sp120;
vertices[2].y = vertices[2].y + type->unk06 + group->age * type->unk0a + (s32)sp120;
} else {
vertices[1].z = vertices[1].z - type->unk06 - group->age * type->unk0a - (s32)sp120;
vertices[2].z = vertices[2].z + type->unk06 + group->age * type->unk0a + (s32)sp120;
}
break;
case 1:
if (ABS(spark->speed.x) > ABS(spark->speed.z)) {
vertices[1].z = vertices[1].z - type->unk06 - group->age * type->unk0a - (s32)sp120;
vertices[2].z = vertices[2].z + type->unk06 + group->age * type->unk0a + (s32)sp120;
} else {
vertices[1].x = vertices[1].x - type->unk06 - group->age * type->unk0a - (s32)sp120;
vertices[2].x = vertices[2].x + type->unk06 + group->age * type->unk0a + (s32)sp120;
}
break;
case 2:
if (ABS(spark->speed.x) > ABS(spark->speed.y)) {
vertices[1].y = vertices[1].y - type->unk06 - group->age * type->unk0a - (s32)sp120;
vertices[2].y = vertices[2].y + type->unk06 + group->age * type->unk0a + (s32)sp120;
} else {
vertices[1].x = vertices[1].x - type->unk06 - group->age * type->unk0a - (s32)sp120;
vertices[2].x = vertices[2].x + type->unk06 + group->age * type->unk0a + (s32)sp120;
}
break;
}
gSPVertex(gdl++, osVirtualToPhysical(vertices), 3, 0);
gSP1Triangle(gdl++, 0, 1, 2, 0);
}
index = (index + 1) % ARRAYCOUNT(g_Sparks);
}
}
}
}
}
return gdl;
}