#include "driver2.h" #include "debris.h" #include "motion_c.h" #include "texture.h" #include "pres.h" #include "director.h" #include "pause.h" #include "sound.h" #include "main.h" #include "system.h" #include "cars.h" #include "camera.h" #include "dr2roads.h" #include "convert.h" #include "map.h" #include "mission.h" #include "draw.h" #include "models.h" #include "players.h" #include "shadow.h" #include "cosmetic.h" #include "denting.h" #include "gamesnd.h" #include "ASM/rndrasm.h" struct DAMAGED_LAMP { int index; char damage; }; struct DAMAGED_OBJECT { CELL_OBJECT cop; char active; char damage; int rot_speed; SVECTOR velocity; int vx; }; struct SMOKE { UnpaddedHackVector position; UnpaddedCharVector drift; UnpaddedCharVector drift_change; UnpaddedHackVector final_tail_pos; u_char step; u_char pos; short start_w; short final_w; char life; char halflife; u_short flags; u_char num; u_char t_step; short transparency; }; struct DEBRIS { VECTOR position; SVECTOR direction; u_short life; u_short flags; u_short num; u_short pos; RGB rgb; char step; char type; }; struct LEAF { VECTOR position; SVECTOR direction; u_short life; u_short flags; u_short num; u_short pos; RGB rgb; char step; char type; short sin_index1; short sin_index2; char sin_addition1; char sin_addition2; }; struct TRI_POINT { BVECTOR v0; BVECTOR v1; BVECTOR v2; }; struct TRI_POINT_LONG { VECTOR_NOPAD v0; VECTOR_NOPAD v1; VECTOR_NOPAD v2; }; struct RAIN_TYPE { VECTOR_NOPAD position; SVECTOR oldposition; }; struct LAMP_STREAK { SXYPAIR light_trails[4]; int id; short clock; char set; }; TEXTURE_DETAILS digit_texture; TRI_POINT debris_rot1[32]; // offset 0xC0A60 TRI_POINT debris_rot2[32]; // offset 0xC0BE0 TRI_POINT debris_rot3[32]; // offset 0xC0D60 TRI_POINT leaf_rot[32]; // offset 0xC1DC0 TRI_POINT litter_rot[32]; // offset 0xC08D0 TRI_POINT* debris_rot_table[5] = { debris_rot1, leaf_rot, litter_rot, debris_rot2, debris_rot3, }; CVECTOR debris_colour[4][31] = { { { 100, 100, 100, 0 }, { 214, 214, 244, 0 }, { 195, 79, 65, 0 }, { 83, 83, 101, 0 }, { 197, 142, 80, 0 }, { 222, 204, 196, 0 }, { 189, 168, 114, 0 }, { 203, 180, 121, 0 }, { 132, 145, 103, 0 }, { 168, 143, 122, 0 }, { 107, 107, 107, 0 }, { 192, 110, 110, 0 }, { 130, 130, 130, 0 }, { 101, 129, 145, 0 }, { 130, 130, 130, 0 }, { 181, 88, 88, 0 }, { 130, 105, 83, 0 }, { 164, 164, 164, 0 }, { 126, 143, 108, 0 }, { 140, 163, 181, 0 }, { 143, 129, 152, 0 }, { 156, 138, 118, 0 }, { 190, 190, 190, 0 }, { 203, 112, 112, 0 }, { 255, 242, 201, 0 }, { 167, 145, 90, 0 }, { 190, 190, 190, 0 }, { 150, 164, 184, 0 }, { 102, 102, 102, 0 }, { 140, 114, 99, 0 }, { 75, 63, 134, 0 }, }, { { 100, 100, 100, 0 }, { 83, 82, 97, 0 }, { 138, 179, 201, 0 }, { 114, 159, 183, 0 }, { 107, 61, 46, 0 }, { 162, 120, 76, 0 }, { 235, 227, 214, 0 }, { 197, 138, 121, 0 }, { 159, 169, 131, 0 }, { 146, 178, 195, 0 }, { 181, 151, 101, 0 }, { 230, 191, 139, 0 }, { 147, 147, 151, 0 }, { 182, 127, 138, 0 }, { 160, 165, 127, 0 }, { 175, 203, 225, 0 }, { 211, 175, 117, 0 }, { 209, 167, 118, 0 }, { 157, 147, 140, 0 }, { 210, 191, 145, 0 }, { 155, 185, 148, 0 }, { 158, 210, 254, 0 }, { 206, 176, 134, 0 }, { 236, 173, 117, 0 }, { 146, 146, 146, 0 }, { 88, 103, 128, 0 }, { 96, 96, 96, 0 }, { 125, 92, 92, 0 }, { 184, 174, 155, 0 }, { 42, 42, 42, 0 }, { 219, 37, 130, 0 }, }, { { 100, 100, 100, 0 }, { 112, 110, 112, 0 }, { 230, 212, 214, 0 }, { 178, 181, 175, 0 }, { 120, 120, 120, 0 }, { 102, 101, 115, 0 }, { 70, 83, 100, 0 }, { 206, 108, 88, 0 }, { 220, 136, 107, 0 }, { 97, 97, 97, 0 }, { 139, 116, 150, 0 }, { 173, 173, 173, 0 }, { 104, 133, 173, 0 }, { 224, 196, 139, 0 }, { 108, 146, 141, 0 }, { 82, 82, 82, 0 }, { 123, 123, 123, 0 }, { 140, 67, 67, 0 }, { 103, 92, 121, 0 }, { 219, 192, 148, 0 }, { 160, 185, 195, 0 }, { 158, 173, 130, 0 }, { 183, 183, 183, 0 }, { 126, 98, 84, 0 }, { 126, 125, 156, 0 }, { 36, 74, 203, 0 }, { 105, 105, 105, 0 }, { 162, 179, 183, 0 }, { 102, 130, 162, 0 }, { 149, 88, 88, 0 }, { 119, 145, 129, 0 }, }, { { 100, 100, 100, 0 }, { 153, 149, 150, 0 }, { 118, 110, 131, 0 }, { 135, 110, 89, 0 }, { 191, 102, 66, 0 }, { 95, 90, 101, 0 }, { 157, 171, 186, 0 }, { 203, 184, 132, 0 }, { 221, 100, 100, 0 }, { 149, 149, 149, 0 }, { 100, 118, 145, 0 }, { 78, 78, 78, 0 }, { 105, 128, 107, 0 }, { 203, 94, 94, 0 }, { 163, 178, 152, 0 }, { 167, 119, 117, 0 }, { 117, 139, 142, 0 }, { 160, 160, 160, 0 }, { 92, 92, 92, 0 }, { 229, 144, 136, 0 }, { 145, 167, 149, 0 }, { 198, 173, 173, 0 }, { 137, 163, 175, 0 }, { 173, 173, 173, 0 }, { 143, 143, 143, 0 }, { 218, 198, 154, 0 }, { 104, 134, 78, 0 }, { 172, 116, 86, 0 }, { 155, 170, 185, 0 }, { 122, 142, 147, 0 }, { 193, 193, 193, 0 } } }; u_char grassColour[4][3] = { {110, 115, 67}, {64, 55, 49}, {91, 104, 56}, {118, 108, 89} }; TRI_POINT_LONG debris1_vert = { {-16,0,0}, {0,-16,0}, {16,16,0} }; TRI_POINT_LONG debris2_vert = { {-4,4,0}, {0,-4,0}, {4,4,0} }; TRI_POINT_LONG debris3_vert = { {-80,0,15}, {0, 0,15}, {80,0,-15} }; TRI_POINT_LONG leaf_vert = { {-30,5,7}, {0,0,10}, {0,0,-7} }; TRI_POINT_LONG litter_vert = { {-25,0,25}, {25,0,25}, {-25,0,-25} }; TRI_POINT_LONG* debris_data[5] = { &debris1_vert, &leaf_vert, &litter_vert, &debris2_vert, &debris3_vert, }; VECTOR dummy = { 0 }; int gNight = 0; u_char gRainCount = 30; int gEffectsTimer = 41; int NextDamagedPmeter = 0; int SmashablesHit = 0; DAMAGED_OBJECT damaged_object[MAX_SMASHED_OBJECTS]; int next_debris = 0; short debris_alloc[MAX_DEBRIS]; int next_leaf = 0; short leaf_alloc[MAX_LEAVES]; int next_smoke = 0; short smoke_alloc[MAX_SMOKE]; int gNextRainDrop = 0; short gRainAlloc[MAX_RAIN_DROPS]; RAIN_TYPE gRain[MAX_RAIN_DROPS]; char PoolPrimData[16] = { 0x0, 0x8, 0x2, 0x9, 0x8, 0x1, 0x9, 0x3, 0x4, 0xA, 0x6, 0xB, 0xA, 0x5, 0xB, 0x7 }; int LightSortCorrect = 0; TEXTURE_DETAILS smoke_texture; TEXTURE_DETAILS debris_texture; TEXTURE_DETAILS litter_texture; TEXTURE_DETAILS cop_texture; TEXTURE_DETAILS light_texture; TEXTURE_DETAILS gTyreTexture; TEXTURE_DETAILS flare_texture; TEXTURE_DETAILS sea_texture; TEXTURE_DETAILS bird_texture1; TEXTURE_DETAILS bird_texture2; TEXTURE_DETAILS lensflare_texture; TEXTURE_DETAILS sun_texture; TEXTURE_DETAILS moon_texture; TEXTURE_DETAILS drop_texture; TEXTURE_DETAILS collon_texture; TEXTURE_DETAILS texturePedHead; TEXTURE_DETAILS tannerShadow_texture; TEXTURE_DETAILS lightref_texture; TEXTURE_DETAILS light_pool_texture; LAMP_STREAK Known_Lamps[MAX_LAMP_STREAKS]; int NewLamp[MAX_LAMP_STREAKS]; int LightIndex = 0; int variable_weather = 0; int gDoLeaves = 1; SMOKE* smoke_table; SMOKE smoke[MAX_SMOKE]; SVECTOR leaf_rotvec; LEAF leaf[MAX_LEAVES]; SVECTOR debris_rotvec; DEBRIS debris[MAX_DEBRIS]; int StreakCount1 = 0; int main_cop_light_pos = 0; int NextDamagedLamp = 0; CELL_OBJECT ground_debris[MAX_GROUND_DEBRIS]; int groundDebrisIndex = 0; DAMAGED_LAMP damaged_lamp[MAX_DAMAGED_LAMPS]; MATRIX debris_mat; MATRIX leaf_mat; // [D] [T] void PlacePoolForCar(CAR_DATA *cp, CVECTOR *col, int front, int in_car) { short brightness; POLY_FT4 *poly; int i; SVECTOR s[27]; SVECTOR sout[27]; VECTOR s1[12]; VECTOR mid_position; VECTOR toss; VECTOR *pos; CAR_COSMETICS* car_cos; CVECTOR color; int Z; int sub_level; int car_road_height; int count; pos = (VECTOR*)cp->hd.where.t; car_cos = &car_cosmetics[cp->ap.model]; // [A] there was check that prevented in_car lights in game, but it was working in quick replays... if (front) { s1[3].vz = -(car_cos->colBox.vz + 50); s1[8].vz = s1[3].vz - 1160; s1[6].vz = s1[3].vz; s1[7].vz = s1[3].vz; if (in_car) { // slightly shifted vertices to make it look more beautiful s1[1].vz = s1[8].vz + 600; s1[0].vx = 136; s1[1].vx = -344; s1[2].vx = -21; s1[3].vx = -143; s1[4].vx = 344; s1[5].vx = -136; s1[6].vx = 143; s1[7].vx = 21; s1[8].vz = s1[8].vz - 400; s1[9].vz = s1[3].vz + 10; s1[8].vx = -82; s1[10].vx = 82; s1[9].vx = -82; s1[11].vx = 82; s1[4].vz = s1[1].vz; s1[5].vz = s1[1].vz; s1[10].vz = s1[8].vz; s1[11].vz = s1[9].vz; LightSortCorrect = -800; sub_level = 3; } else { s1[1].vz = s1[8].vz + 100; s1[0].vx = 136; s1[1].vx = -344; s1[2].vx = -21; s1[3].vx = -143; s1[4].vx = 344; s1[5].vx = -136; s1[6].vx = 143; s1[7].vx = 21; s1[10].vx = 82; s1[11].vx = 82; s1[8].vx = -82; s1[9].vx = -82; s1[4].vz = s1[1].vz; s1[5].vz = s1[1].vz; s1[9].vz = s1[3].vz; s1[10].vz = s1[8].vz; s1[11].vz = s1[3].vz; sub_level = 3; if (player[CurrentPlayerView].cameraView == 2 && cp == &car_data[player[CurrentPlayerView].playerCarId]) LightSortCorrect = -320; else LightSortCorrect = -200; } } else { // back light s1[0].vx = -204; s1[1].vx = 204; s1[2].vx = -204; s1[3].vx = 204; s1[3].vz = (car_cos->colBox.vz - 10); s1[1].vz = s1[3].vz + 204; sub_level = 0; } s1[0].vz = s1[1].vz; s1[2].vz = s1[3].vz; SetRotMatrix(&cp->hd.drawCarMat); mid_position.vx = 0; mid_position.vy = 0; mid_position.vz = -500; _MatrixRotate(&mid_position); mid_position.vx += pos->vx; mid_position.vy += pos->vy; mid_position.vz += pos->vz; car_road_height = MapHeight(&mid_position); if (sub_level == 3) count = 12; else count = 4; // adjust height and poisition for each vertex for(i = 0; i < count; i++) { int temp_y; s1[i].vy = 0; _MatrixRotate(&s1[i]); toss.vx = s1[i].vx + pos->vx; toss.vy = s1[i].vy + pos->vy; toss.vz = s1[i].vz + pos->vz; s[i].vx = toss.vx - camera_position.vx; s[i].vz = toss.vz - camera_position.vz; temp_y = MapHeight(&toss); if (ABS(-temp_y + car_road_height) > 500) s[i].vy = -car_road_height - camera_position.vy; else s[i].vy = -temp_y - camera_position.vy; } if (FIXEDH(s[0].vy * s[1].vz - s[0].vz * s[1].vy) * s[2].vx + FIXEDH(s[0].vz * s[1].vx - s[0].vx * s[1].vz) * s[2].vy + FIXEDH(s[0].vx * s[1].vy - s[0].vy * s[1].vx) * s[2].vz >= 0) { gte_SetRotMatrix(&inv_camera_matrix); gte_SetTransVector(&dummy); if (sub_level == 0) { gte_ldv3(&s[0], &s[1], &s[2]); gte_rtpt(); gte_stszotz(&Z); if (Z > 40) Z -= 40; if (Z > 49) { poly = (POLY_FT4 *)current->primptr; // [A] Emit poly only after ot z checked setPolyFT4(poly); setSemiTrans(poly, 1); *(ushort*)&poly->u0 = *(ushort*)&light_pool_texture.coords.u0; *(ushort*)&poly->u1 = *(ushort*)&light_pool_texture.coords.u1; *(ushort*)&poly->u2 = *(ushort*)&light_pool_texture.coords.u2; *(ushort*)&poly->u3 = *(ushort*)&light_pool_texture.coords.u3; poly->r0 = col->r / 2; poly->g0 = col->g / 2; poly->b0 = col->b / 2; gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); poly->tpage = light_pool_texture.tpageid | 0x20; poly->clut = light_pool_texture.clutid; gte_ldv0(&s[3]); gte_rtps(); gte_stsxy(&poly->x3); addPrim(current->ot + (Z >> 1), poly); current->primptr += sizeof(POLY_FT4); } } else if (sub_level == 3) { for(i = 0; i < 12; i++) { gte_ldv0(&s[i]); gte_rtv0tr(); gte_stsv(&sout[i]); } // draw front light quads for(i = 0; i < 4; i++) { char* VertIdx; VertIdx = PoolPrimData + i * 4; gte_SetRotMatrix(&identity); gte_SetTransVector(&dummy); if (i & 2) brightness = LeftLight + LeftLight * 4; else brightness = RightLight + RightLight * 4; if (brightness) { int test = col->r * brightness; color.r = MIN(255, col->r * brightness >> 4); color.g = MIN(255, col->g * brightness >> 4); color.b = MIN(255, col->b * brightness >> 4); if (i & 1) { sQuad(sout + VertIdx[0], sout + VertIdx[2], sout + VertIdx[3], sout + VertIdx[1], &color, LightSortCorrect); } else { sQuad(sout + VertIdx[1], sout + VertIdx[3], sout + VertIdx[2], sout + VertIdx[0], &color, LightSortCorrect); } } } } LightSortCorrect = -10; } } // [D] [T] int AllocateLeaf(void) { if (next_leaf < MAX_LEAVES) return leaf_alloc[next_leaf++]; return -1; } // [D] [T] void ReleaseLeaf(short num) { leaf_alloc[--next_leaf] = num; } // [D] [T] void AddLeaf(VECTOR *Position, int num_leaves, int Type) { int num; int temprand; int i; if (gDoLeaves == 0) return; Position->vy = -Position->vy; Position->pad = MapHeight(Position); for (i = 0; i < num_leaves; i++) { num = AllocateLeaf(); if (num == -1) return; LEAF* myleaf = &leaf[num]; temprand = rand(); myleaf->position.vx = Position->vx + (temprand & 0xfe); myleaf->position.vz = Position->vz + (temprand >> 8 & 0xfe); if (Type == 1) myleaf->position.vy = -Position->vy; else myleaf->position.vy = -Position->pad; myleaf->position.pad = Position->pad; myleaf->life = 600; myleaf->flags = 0x2; myleaf->direction.vx = 0; myleaf->direction.vy = 0; myleaf->direction.vz = 0; myleaf->pos = (temprand >> 7) & 0xff; myleaf->step = (temprand & 7) + 1; if (Type == 1) { // tree leaves if ((temprand & 3) == 0) { myleaf->rgb.r = 110; myleaf->rgb.g = 112; myleaf->rgb.b = 15; } else if ((temprand & 3) == 1) { myleaf->rgb.r = 20; myleaf->rgb.g = 44; myleaf->rgb.b = 0; } else { myleaf->rgb.r = 60; myleaf->rgb.g = 50; myleaf->rgb.b = 30; } } else { // news, papers etc myleaf->rgb.r = myleaf->rgb.g = myleaf->rgb.b = temprand & 0x1f; } // apply colors if (gTimeOfDay == 3) { *(u_int*)&myleaf->rgb = *(u_int*)&myleaf->rgb >> 2 & 0x3f3f3f3f; } else if (gWeather == 1 || gWeather == 2) { *(u_int*)&myleaf->rgb = *(u_int*)&myleaf->rgb >> 1 & 0x7f7f7f7f; } myleaf->sin_index1 = temprand & 0xfff; myleaf->sin_index2 = temprand >> 4 & 0xfff; myleaf->sin_addition2 = -(temprand >> 8 & 7); myleaf->sin_addition1 = -(temprand & 3); myleaf->type = Type; } } // [D] [T] void SwirlLeaves(CAR_DATA *cp) { int XDiff; int ZDiff; LEAF *lpLeaf; int count; VECTOR plpos; lpLeaf = leaf; plpos.vx = cp->hd.where.t[0]; plpos.vy = cp->hd.where.t[1]; plpos.vz = cp->hd.where.t[2]; if (cp->hd.wheel_speed + 39999U <= 0x1d4be || gDoLeaves == 0 || pauseflag != 0) return; for (count = 0; count < MAX_LEAVES; count++) { XDiff = plpos.vx - lpLeaf->position.vx; ZDiff = plpos.vz - lpLeaf->position.vz; if ((lpLeaf->flags & 0x2) && lpLeaf->position.vy + plpos.vy > -180 && XDiff > -360 && XDiff < 360 && ZDiff > -360 && ZDiff < 360) { // set lifting direction lpLeaf->direction.vy = -25 - (rand() & 0x1f); lpLeaf->position.vy -= 1; } lpLeaf++; } } // [D] [T] void InitDebrisNames(void) { GetTextureDetails("SMOKE", &smoke_texture); GetTextureDetails("DEBRIS", &debris_texture); GetTextureDetails("LITTER", &litter_texture); GetTextureDetails("COPLIGHT", &cop_texture); GetTextureDetails("LIGHT", &light_texture); GetTextureDetails("SKID", &gTyreTexture); GetTextureDetails("FLARE", &flare_texture); GetTextureDetails("SPLASH", &sea_texture); GetTextureDetails("SWBIRD1", &bird_texture1); GetTextureDetails("SWBIRD2", &bird_texture2); GetTextureDetails("LENSFLR", &lensflare_texture); GetTextureDetails("SKYSUN", &sun_texture); GetTextureDetails("SKYMOON", &moon_texture); GetTextureDetails("DROP", &drop_texture); GetTextureDetails("DIGIT", &digit_texture); SetCLUT16Flags(digit_texture.clutid, 6, 0); GetTextureDetails("COLLON", &collon_texture); GetTextureDetails("JEANS1", &jeans_texture); GetTextureDetails("ARM1", &arm1_texture); GetTextureDetails("FOREARM1", &forearm1_texture); GetTextureDetails("CHEST1", &chest1_texture); GetTextureDetails("LOWHEAD", &head1_texture); GetTextureDetails("ADDCAM", &addcam); GetTextureDetails("FRAMEADV", &frameadv); GetTextureDetails("AUTO", &autocam); GetTextureDetails("CHASEC", &chasecar); GetTextureDetails("CHOOSECA", &choosecar); GetTextureDetails("CLOCK", &clock); GetTextureDetails("DELCAM", &delcam); GetTextureDetails("EDITCAM", &editcam); GetTextureDetails("FIXEDCA", &fixedcam); GetTextureDetails("INCAR", &incar); GetTextureDetails("LENSCHA", &lenschan); GetTextureDetails("LOOKCAR", &lookcar); GetTextureDetails("MOVECMP", &movecam); GetTextureDetails("MOVECAM", &movecampos); GetTextureDetails("OK", &ok); GetTextureDetails("PAUSE", &pause); GetTextureDetails("PLAYCAM", &playcam); GetTextureDetails("PLAYPAU", &playpause); GetTextureDetails("SAVE2CA", &save2card); GetTextureDetails("RESTREP", &restart); GetTextureDetails("HEAD1", &texturePedHead); GetTextureDetails("TSHADOW", &tannerShadow_texture); head1_texture.coords.u1 = head1_texture.coords.u0 + 8; head1_texture.coords.u3 = head1_texture.coords.u1; GetTextureDetails("LIGHTREF", &lightref_texture); GetTextureDetails("LIGHT", &light_pool_texture); InitButtonTextures(); InitTannerShadow(); } // [D] [T] void InitDebris(void) { int i, j; TRI_POINT_LONG temptri; StreakCount1 = 0; next_debris = 0; next_smoke = 0; next_leaf = 0; NextDamagedLamp = 0; smoke_table = NULL; main_cop_light_pos = rand() % 7; gDoLeaves = (NumPlayers == 1); // [A] disable in multiplayer (temporarily) due to their flicker for (i = 0; i < MAX_LAMP_STREAKS; i++) { Known_Lamps[i].set = 0; } for (i = 0; i < MAX_DEBRIS; i++) { debris_alloc[i] = i; debris[i].pos = 0; debris[i].flags = 0; debris[i].num = i; } for (i = 0; i < MAX_GROUND_DEBRIS; i++) { ground_debris[i].type = 0xffff; } groundDebrisIndex = 0; debris_rotvec.vz = 0; debris_rotvec.vy = 0; debris_rotvec.vx = 0; leaf_rotvec.vz = 0; leaf_rotvec.vy = 0; leaf_rotvec.vx = 0; for (i = 0; i < 32; i++) { RotMatrixXYZ(&debris_mat, &debris_rotvec); RotMatrixXYZ(&leaf_mat, &leaf_rotvec); debris_rotvec.vx += 128; debris_rotvec.vy += 256; debris_rotvec.vz += 128; leaf_rotvec.vy += 128; for (j = 0; j < 5; j++) { if (j == 1) SetRotMatrix(&leaf_mat); else SetRotMatrix(&debris_mat); temptri = *debris_data[j]; _MatrixRotate((VECTOR *)&temptri.v0); _MatrixRotate((VECTOR *)&temptri.v1); _MatrixRotate((VECTOR *)&temptri.v2); debris_rot_table[j][i].v0.vx = temptri.v0.vx; debris_rot_table[j][i].v0.vy = temptri.v0.vy; debris_rot_table[j][i].v0.vz = temptri.v0.vz; debris_rot_table[j][i].v1.vx = temptri.v1.vx; debris_rot_table[j][i].v1.vy = temptri.v1.vy; debris_rot_table[j][i].v1.vz = temptri.v1.vz; debris_rot_table[j][i].v2.vx = temptri.v2.vx; debris_rot_table[j][i].v2.vy = temptri.v2.vy; debris_rot_table[j][i].v2.vz = temptri.v2.vz; } } for (i = 0; i < MAX_SMOKE; i++) { smoke_alloc[i] = i; smoke[i].pos = 0; smoke[i].flags = 0; smoke[i].num = i; } for (i = 0; i < MAX_LEAVES; i++) { leaf_alloc[i] = i; leaf[i].pos = 0; leaf[i].flags = 0; leaf[i].num = i; } ClearMem((char*)&damaged_lamp, sizeof(damaged_lamp)); for (i = 0; i < MAX_SMASHED_OBJECTS; i++) damaged_object[i].active = 0; LightSortCorrect = -10; SmashablesHit = 0; } // [D] [T] int AllocateDebris(void) { if (next_debris < MAX_DEBRIS) return debris_alloc[next_debris++]; return -1; } // [D] [T] void ReleaseDebris(short num) { debris_alloc[--next_debris] = num; } // [D] [T] int AllocateSmoke(void) { if (next_smoke < MAX_SMOKE) return smoke_alloc[next_smoke++]; return -1; } // [D] [T] void ReleaseSmoke(short num) { smoke_alloc[--next_smoke] = num; } // [D] [T] void AddGroundDebris(void) { int seed; int number; int zbound; int xbound; int type; CELL_OBJECT *cop; MODEL *model; int count; VECTOR Position; if (car_data[0].hd.wheel_speed + 99999U <= 0x30d3e) return; count = 0; cop = ground_debris; do { if (cop->type != 0xffff) { model = modelpointers[cop->type]; xbound = ABS(cop->pos.vx - camera_position.vx); zbound = ABS(cop->pos.vz - camera_position.vz); if (xbound <= 9000 && zbound <= 9000 && (xbound > 7000 || zbound > 7000)) { if (next_leaf >= MAX_LEAVES) return; seed = rand(); Position.vy = cop->pos.vy - 45; Position.vx = cop->pos.vx + ((seed & 0x3ff) - 512); Position.vz = cop->pos.vz + ((rand() & 0x3ff) - 512); number = seed & 7; if (model->flags2 & MODEL_FLAG_TREE) { type = 1; // ground leaves } else { number = seed & 3; type = 2; // paper } AddLeaf(&Position, number + 1, type); } } count++; cop++; } while (count < MAX_GROUND_DEBRIS); } // [D] [T] [A] void DrawSmashable_sprites(void) { DAMAGED_OBJECT *dam; MODEL *model; int count; VECTOR pos; MATRIX object_matrix; dam = damaged_object; count = 0; do { if (dam->active) { model = modelpointers[dam->cop.type]; InitMatrix(object_matrix); if ((model->shape_flags & SHAPE_FLAG_SPRITE) == 0) RotMatrixY(dam->rot_speed * dam->damage * 3 & 0xfff, &object_matrix); RotMatrixZ(dam->rot_speed * dam->damage & 0xfff, &object_matrix); pos.vx = dam->vx - camera_position.vx; pos.vy = dam->cop.pos.vy - camera_position.vy; pos.vz = dam->cop.pos.vz - camera_position.vz; Apply_Inv_CameraMatrix(&pos); gte_SetRotMatrix(&object_matrix); gte_SetTransVector(&pos); pos.vx = dam->vx; pos.vy = dam->cop.pos.vy; pos.vz = dam->cop.pos.vz; SetFrustrumMatrix(); if (FrustrumCheck(&pos, model->bounding_sphere) != -1) { if (model->shape_flags & SHAPE_FLAG_SPRITE) { UNIMPLEMENTED(); if (gWeather - 1U < 2 || gTimeOfDay == 3) { plotContext.colour = NightAmbient << 0x10 | NightAmbient << 8 | NightAmbient | 0x2c000000; } else { plotContext.colour = 0x2c808080; } // [A] // TODO: //current->primptr = Asm_PlotSprite(model, current->primptr, current->ot, 0); } else { PlotMDL_less_than_128(model); } } } count++; dam++; } while (count < MAX_SMASHED_OBJECTS); } // [D] [T] int MoveSmashable_object(void) { DAMAGED_OBJECT *dam; int count; dam = damaged_object; count = 0; do { if (dam->active) { if (dam->cop.pos.vy < 50 - player[0].pos[1]) { dam->vx += dam->velocity.vx; dam->cop.pos.vy += dam->velocity.vy; dam->cop.pos.vz += dam->velocity.vz; dam->velocity.vy += 10; dam->damage++; } else { dam->active = 0; } } count++; dam++; } while (count < MAX_SMASHED_OBJECTS); return 0; } // [D] [T] void DisplayLightReflections(VECTOR* v1, CVECTOR* col, short size, TEXTURE_DETAILS* texture) { POLY_FT4* poly; SVECTOR vert[4]; CVECTOR thiscol; int z; if (wetness > 9 && v1->vy > camera_position.vy) { thiscol.r = col->r * wetness >> 16; thiscol.g = col->g * wetness >> 16; thiscol.b = col->b * wetness >> 16; gte_SetTransVector(v1); Apply_Inv_CameraMatrix(v1); gte_SetTransVector(v1); gte_SetRotMatrix(&face_camera); vert[0].vx = -size; vert[2].vx = -size; vert[1].vx = size; vert[3].vx = size; vert[0].vy = 0; vert[0].vz = 0; vert[1].vy = 0; vert[1].vz = 0; vert[2].vy = 0; vert[2].vz = 0; vert[3].vy = 0; vert[3].vz = 0; gte_ldv0(&vert[0]); gte_rtps(); gte_stsz(&z); if (z >= 150) { poly = (POLY_FT4*)current->primptr; setPolyFT4(poly); setSemiTrans(poly, 1); gte_stsxy(&poly->x0); vert[2].vy = (z >> 3) + 0xfa; vert[3].vy = (z >> 3) + 0xfa; gte_ldv3(&vert[1], &vert[2], &vert[3]); gte_rtpt(); gte_stsxy3(&poly->x1, &poly->x2, &poly->x3); poly->u0 = texture->coords.u0; poly->v0 = texture->coords.v0; poly->u1 = texture->coords.u1; poly->v1 = texture->coords.v1; poly->u2 = texture->coords.u2; poly->v2 = texture->coords.v2; poly->u3 = texture->coords.u3; poly->v3 = texture->coords.v3; poly->tpage = texture->tpageid | 0x20; poly->clut = texture->clutid; poly->r0 = thiscol.r; poly->g0 = thiscol.g; poly->b0 = thiscol.b; addPrim(current->ot + (z >> 4), poly); current->primptr += sizeof(POLY_FT4); } } } // [D] [T] int find_lamp_streak(int LampId) { int count; for (count = 0; count < MAX_LAMP_STREAKS; count++) { if (Known_Lamps[count].id == LampId) { Known_Lamps[count].set = 1; return count; } } // allocate new streak if (StreakCount1 < MAX_LAMP_STREAKS) { NewLamp[StreakCount1++] = LampId; } return -1; } // [D] [T] void AddSmallStreetLight(CELL_OBJECT *cop, int x, int y, int z, int type) { int count; DAMAGED_LAMP* dam; int halo_size; short size; short angle; VECTOR v1; VECTOR v2; VECTOR v3; SVECTOR pos; CVECTOR col; CVECTOR col1; SVECTOR dpos; dam = damaged_lamp; col = {140, 140, 140}; col1 = {45, 45, 45}; angle = cop->yang; if (type == 0) { halo_size = 25; size = 150; } else if (type == 1) { halo_size = 50; size = 150; } else { halo_size = 100; size = 300; } count = 0; do { if (dam->index == cop->pos.vx + cop->pos.vz) { if (dam->damage > 2) return; // do flicker col.r = col.g = col.b = (rand() & 0x3f) - (dam->damage * 32 - 90); col1.r = col1.g = col1.b = col.r / 2; break; } count++; dam++; } while (count < 4); dpos.vx = cop->pos.vx - camera_position.vx; dpos.vy = cop->pos.vy - camera_position.vy; dpos.vz = cop->pos.vz - camera_position.vz; if (angle & 0xf) { pos.vx = x; pos.vy = y; pos.vz = z; gte_SetRotMatrix(&matrixtable[angle]); gte_ldv0(&pos); gte_rtv0(); gte_stsv(&pos); v1.vx = dpos.vx + pos.vx; v1.vy = dpos.vy + pos.vy; v1.vz = dpos.vz + pos.vz; } else { angle >>= 4; if (angle == 0) { v1.vx = dpos.vx + x; v1.vz = dpos.vz + z; } else if (angle == 1) { v1.vx = dpos.vx + z; v1.vz = dpos.vz - x; } else if (angle == 2) { v1.vx = dpos.vx - x; v1.vz = dpos.vz - z; } else if (angle == 3) { v1.vx = dpos.vx - z; v1.vz = dpos.vz + x; } v1.vy = dpos.vy + y; } v2.vx = v1.vx; v2.vz = v1.vz; v2.vy = -camera_position.vy - MapHeight((VECTOR*)&cop->pos); LightSortCorrect = -30; col.cd = 0; v3 = v1; LightIndex = find_lamp_streak(cop->pos.vx + cop->pos.vz + x); // [A] was pointer. if (LightIndex > -1) col.cd = 0x60; ShowLight(&v3, &col, halo_size, &light_texture); ShowLight1(&v3, &col1, size, &light_texture); DisplayLightReflections(&v2, &col1, halo_size * 2, &lightref_texture); LightSortCorrect = -10; } // [D] [T] void AddLightEffect(CELL_OBJECT *cop, int x, int y, int z, int type, int colour) { short yang; int angle; int size; VECTOR v1; VECTOR v2; VECTOR dpos; SVECTOR pos; CVECTOR col; yang = cop->yang; angle = yang; dpos.vx = cop->pos.vx - camera_position.vx; dpos.vy = cop->pos.vy - camera_position.vy; dpos.vz = cop->pos.vz - camera_position.vz; if (yang & 0xf) { pos.vx = x; pos.vy = y; pos.vz = z; gte_SetRotMatrix(&matrixtable[angle]); gte_ldv0(&pos); gte_rtv0(); gte_stsv(&pos); v1.vx = dpos.vx + pos.vx; v1.vy = dpos.vy + pos.vy; v1.vz = dpos.vz + pos.vz; } else { yang >>= 4; if (yang == 0) { v1.vx = dpos.vx + x; v1.vz = dpos.vz + z; } else if (yang == 1) { v1.vx = dpos.vx + z; v1.vz = dpos.vz - x; } else if (yang == 2) { v1.vx = dpos.vx - x; v1.vz = dpos.vz - z; } else if (yang == 3) { v1.vx = dpos.vx - z; v1.vz = dpos.vz + x; } v1.vy = dpos.vy + y; } if (colour == 0) { col.r = 40; col.g = 10; col.b = 0; } else if (colour == 1) { col.r = 0; col.g = 40; col.b = 0; } else if (colour == 2) { col.g = 70; col.r = 85; col.b = 5; } else if (colour == 3) { col.g = 40; col.b = 35; col.r = 40; } if (type == 0) { size = 400; } else if (type == 1) { size = 300; } else if (type == 2) { size = 200; } else if (type == 3) { size = 150; } v2.vx = v1.vx; v2.vz = v1.vz; v2.vy = -camera_position.vy - MapHeight((VECTOR*)&cop->pos); LightSortCorrect = -10; col.cd = 0; Apply_Inv_CameraMatrix(&v1); gte_SetRotMatrix(&identity); gte_SetTransVector(&v1); ShowLight1(&v1, &col, size, &light_texture); DisplayLightReflections(&v2, &col, (size << 0xd) >> 0x10, &lightref_texture); } // [D] [T] void PreLampStreak(void) { int count; for (count = 0; count < MAX_LAMP_STREAKS && StreakCount1 > 0; count++) { if (Known_Lamps[count].set == 0) { Known_Lamps[count].id = NewLamp[--StreakCount1]; Known_Lamps[count].clock = FrameCnt - 2; } } for (count = 0; count < MAX_LAMP_STREAKS; count++) { Known_Lamps[count].set = 0; NewLamp[count] = 0; } StreakCount1 = 0; } // [D] [T] int damage_lamp(CELL_OBJECT *cop) { int old_damage; int count; DAMAGED_LAMP *dam; count = 0; dam = damaged_lamp; do { // [A] slow but works if (dam->index == cop->pos.vx + cop->pos.vz) { old_damage = dam->damage; dam->damage++; if (old_damage < 3) return ((old_damage + 1) < 3) ^ 1; return 0; } dam++; count++; } while (count < MAX_DAMAGED_LAMPS); // store new cell object dam = &damaged_lamp[NextDamagedLamp]; dam->damage = 0; dam->index = cop->pos.vx + cop->pos.vz; // copy if (++NextDamagedLamp > MAX_DAMAGED_LAMPS) NextDamagedLamp = 0; return 0; } // [D] [T] int damage_object(CELL_OBJECT *cop, VECTOR *velocity) { DAMAGED_OBJECT *dam; PACKED_CELL_OBJECT *pcop; dam = &damaged_object[NextDamagedPmeter]; SmashablesHit++; if (NextDamagedPmeter < MAX_SMASHED_OBJECTS-1) NextDamagedPmeter++; else NextDamagedPmeter = 0; dam->active = 1; dam->damage = 0; dam->cop = *cop; // copy dam->vx = cop->pos.vx; dam->velocity.vx = velocity->vx >> 10; dam->velocity.vz = velocity->vz >> 10; pcop = pcoplist[cop->pad]; pcop->value = 0xffff; pcop->pos.vy = 1; if (dam->velocity.vx < 0) dam->velocity.vy = velocity->vx; else dam->velocity.vy = -velocity->vx; if (dam->velocity.vz < 0) dam->velocity.vy += velocity->vz; else dam->velocity.vy -= velocity->vz; dam->velocity.vy /= 2; if ((rand() & 1) == 0) dam->rot_speed = -dam->velocity.vy; else dam->rot_speed = dam->velocity.vy; if (dam->velocity.vy < -67) dam->velocity.vy = -67; cop->pos.vx = OBJECT_SMASHED_MARK; return 0; } // [D] [T] void ShowFlare(VECTOR* v1, CVECTOR* col, short size, int rotation) { POLY_FT4* poly; SVECTOR vert[4]; SVECTOR direction; MATRIX temp_matrix; int z; gte_SetTransVector(v1); direction.vy = 0; direction.vx = 0; direction.vz = rotation; RotMatrixXYZ(&temp_matrix, &direction); gte_SetRotMatrix(&temp_matrix); vert[0].vx = -size; vert[0].vy = -size; vert[0].vz = 0; vert[1].vx = -size; vert[1].vy = size; vert[1].vz = 0; vert[2].vx = size; vert[2].vy = -size; vert[2].vz = 0; vert[3].vx = size; vert[3].vy = size; vert[3].vz = 0; gte_ldv3(&vert[0], &vert[1], &vert[2]); gte_rtpt(); poly = (POLY_FT4*)current->primptr; poly->u0 = flare_texture.coords.u0; poly->v0 = flare_texture.coords.v0; poly->u1 = flare_texture.coords.u1; poly->v1 = flare_texture.coords.v1; poly->u2 = flare_texture.coords.u2; poly->v2 = flare_texture.coords.v2 - 1; poly->u3 = flare_texture.coords.u3; poly->v3 = flare_texture.coords.v3 - 1; setPolyFT4(poly); setSemiTrans(poly, 1); poly->r0 = col->r >> 1; poly->g0 = col->g >> 1; poly->b0 = col->b >> 1; gte_stsz(&z); if (z >> 3 > 39) { z = (z >> 3) + LightSortCorrect; if (z < 1) z = 1; gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); gte_ldv0(&vert[3]); gte_rtps(); gte_stsxy(&poly->x3); poly->tpage = flare_texture.tpageid | 0x20; poly->clut = flare_texture.clutid; addPrim(current->ot + z, poly); current->primptr += sizeof(POLY_FT4); } } // [D] [T] void AddTrafficLight(CELL_OBJECT *cop, int x, int y, int z, int flag, int yang) { int tempfade; int lDiffAnglesX, lDiffAnglesY; int AbsX, AbsY; CVECTOR a, c; VECTOR v1, v2; v1.vy = (cop->pos.vy - camera_position.vy) + y; v1.vx = (cop->pos.vx - camera_position.vx) + FIXEDH(RCOS(yang) * x + RSIN(yang) * z); v1.vz = (cop->pos.vz - camera_position.vz) + FIXEDH(RCOS(yang) * z - RSIN(yang) * x); a.cd = 0; if (flag & 0x200) { a.r = 255; a.g = 25; a.b = 25; } else if (flag & 0x400) { a.r = 255; a.g = 100; a.b = 35; } else if (flag & 0x800) { a.r = 25; a.g = 255; a.b = 25; } lDiffAnglesX = DIFF_ANGLES(0, camera_angle.vx);// (camera_angle.vx + 2048) & 0xfff) - 2048; AbsX = ABS(lDiffAnglesX); lDiffAnglesY = DIFF_ANGLES(yang, -camera_angle.vy & 4095); //((-camera_angle.vy & 0xfffU) - yang + 2048 & 0xfff) - 2048; AbsY = ABS(lDiffAnglesY); c.r = a.r >> 3; c.b = a.b >> 3; c.g = a.g >> 3; v2.vx = v1.vx; v2.vz = v1.vz; v2.vy = -camera_position.vy - MapHeight((VECTOR*)&cop->pos); if (gNight) ShowGroundLight(&v2, &c, 300); if (AbsY < 1000) { if (AbsX + AbsY < 1000) { tempfade = 1000 - (AbsX + AbsY); if (tempfade < 0) tempfade = 0; a.r = (a.r * tempfade) >> 10; a.b = (a.b * tempfade) >> 10; a.g = (a.g * tempfade) >> 10; LightSortCorrect = -140; LightIndex = find_lamp_streak(cop->pos.vx + cop->pos.vz + x + y); // [A] was pointer. if (LightIndex < 0) a.cd = 0; else a.cd = 0x20; ShowLight(&v1, &a, 30, &light_texture); a.r >>= 1; a.b >>= 1; a.g >>= 1; if (gNight) ShowFlare(&v1, &a, 150, lDiffAnglesX + lDiffAnglesY + v1.vx + v1.vz >> 3 & 0x1ffe); DisplayLightReflections(&v2, &a, 50, &lightref_texture); } LightSortCorrect = -10; } } // [D] [T] void InitFXPos(VECTOR *vec, SVECTOR *svec, CAR_DATA *cp) { SVECTOR svectmp; gte_SetRotMatrix(&cp->hd.drawCarMat); gte_SetTransVector(vec); gte_ldv0(svec); gte_rtv0tr(); gte_stlvnl(vec); } int CarLightFadeBack = 0; int CarLightFadeFront = 0; // [D] [T] void FindCarLightFade(MATRIX *carToCamera) { int zz; zz = carToCamera->m[2][2] / 4; CarLightFadeFront = zz - 124; CarLightFadeBack = -124 - zz; } // [D] [T] void ShowCarlight(SVECTOR *v1, CAR_DATA *cp, CVECTOR *col, short size, short flare_size, TEXTURE_DETAILS *texture,int flag) { int CarLightFade; VECTOR v1t; VECTOR v1l; CVECTOR flareCol; CarLightFade = 255; if (flag != 0xFF) { if (flag & 1) CarLightFade = CarLightFadeFront; else CarLightFade = CarLightFadeBack; if (CarLightFade < 0) return; } else flag = 0; flareCol.r = (col->r * CarLightFade) >> 10; flareCol.b = (col->b * CarLightFade) >> 10; flareCol.g = (col->g * CarLightFade) >> 10; flareCol.cd = flag; gte_SetRotMatrix(&cp->hd.drawCarMat); v1l.vx = cp->hd.where.t[0] - camera_position.vx; v1l.vz = cp->hd.where.t[2] - camera_position.vz; v1l.vy = -camera_position.vy - cp->hd.where.t[1]; InitFXPos(&v1l, v1, cp); if (wetness > 9) { v1t.vx = v1l.vx; v1t.vz = v1l.vz; v1t.vy = -camera_position.vy - MapHeight((VECTOR *)cp->hd.where.t); DisplayLightReflections(&v1t, &flareCol, flare_size / 2, &lightref_texture); } col->cd = flag; ShowLight(&v1l, &flareCol, size, texture); flareCol.r /= 2; flareCol.g /= 2; flareCol.b /= 2; ShowFlare(&v1l, &flareCol, flare_size, (v1->vx + v1->vz) / 4 + (cp->hd.direction - camera_angle.vy) * 2); } // [D] [T] void ShowLight1(VECTOR *v1, CVECTOR *col, short size, TEXTURE_DETAILS *texture) { POLY_FT4* poly; SVECTOR vert[4]; int z; poly = (POLY_FT4*)current->primptr; vert[0].vz = 0; vert[1].vz = 0; vert[2].vz = 0; vert[3].vz = 0; vert[0].vx = -size; vert[0].vy = -size; vert[1].vx = size; vert[1].vy = -size; vert[2].vx = -size; vert[2].vy = size; vert[3].vx = size; vert[3].vy = size; gte_ldv3(&vert[0], &vert[1], &vert[2]); gte_rtpt(); poly->u0 = (texture->coords).u0; poly->v0 = (texture->coords).v0; poly->u1 = (texture->coords).u1; poly->v1 = (texture->coords).v1; poly->u2 = (texture->coords).u2; poly->v2 = (texture->coords).v2; poly->u3 = (texture->coords).u3; poly->v3 = (texture->coords).v3;; setPolyFT4(poly); SetSemiTrans(poly, 1); poly->r0 = col->r; poly->g0 = col->g; poly->b0 = col->b; gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); gte_stsz(&z); if (z > 39) { gte_ldv0(&vert[3]); gte_rtps(); poly->tpage = texture->tpageid | 0x20; poly->clut = texture->clutid; z = (z >> 3) + LightSortCorrect; if (z < 0) z = 0; gte_stsxy(&poly->x3); addPrim(current->ot + z, poly); current->primptr += sizeof(POLY_FT4); } } // [D] [T] void ShowLight(VECTOR *v1, CVECTOR *col, short size, TEXTURE_DETAILS *texture) { int x, y; POLY_FT3 *null; POLY_G4 *trail; POLY_FT4 *poly; int i; SVECTOR vert[4]; int z; int index; SXYPAIR* trails; short* clock; int tail_width; // apply transform Apply_Inv_CameraMatrix(v1); gte_SetRotMatrix(&identity); gte_SetTransVector(v1); vert[0].vz = 0; vert[1].vz = 0; vert[2].vz = 0; vert[3].vz = 0; vert[0].vx = -size; vert[0].vy = -size; vert[1].vx = size; vert[1].vy = -size; vert[2].vx = -size; vert[2].vy = size; vert[3].vx = size; vert[3].vy = size; gte_ldv3(&vert[0], &vert[1], &vert[2]); gte_rtpt(); gte_stsz(&z); // discard if too close if (z < 38) return; poly = (POLY_FT4 *)current->primptr; setPolyFT4(poly); setSemiTrans(poly, 1); poly->u0 = texture->coords.u0; poly->v0 = texture->coords.v0; poly->u1 = texture->coords.u1; poly->v1 = texture->coords.v1; poly->u2 = texture->coords.u2; poly->v2 = texture->coords.v2; poly->u3 = texture->coords.u3; poly->v3 = texture->coords.v3; poly->r0 = col->r; poly->g0 = col->g; poly->b0 = col->b; gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); gte_ldv0(&vert[3]); gte_rtps(); gte_stsxy(&poly->x3); poly->tpage = texture->tpageid | 0x20; poly->clut = texture->clutid; z = (z >> 3) + LightSortCorrect; if (z < 0) z = 0; if (z < 10000) tail_width = (10000 - z) >> 0xd; else tail_width = 0; addPrim(current->ot + z, poly); current->primptr += sizeof(POLY_FT4); if (CameraCnt <= 4 || NumPlayers > 1) // [A] don't draw trails in multiplayer return; if ((col->cd & 0x20) && gLightsOn) { trails = Known_Lamps[LightIndex].light_trails; clock = &Known_Lamps[LightIndex].clock; } else { // get light index by flag if (col->cd & 0x2) index = 0; else if (col->cd & 0x4) index = 1; else if (col->cd & 0x8) index = 2; else if (col->cd & 0x10) index = 3; else index = -1; if (index == -1) return; trails = car_data[gcar_num].ap.light_trails[index]; clock = &car_data[gcar_num].ap.old_clock[index]; } #ifndef PSX x = (poly->x0 + poly->x3) / 2.0f; y = (poly->y0 + poly->y3) / 2.0f; #else x = (poly->x0 + poly->x3) / 2; y = (poly->y0 + poly->y3) / 2; #endif // unified drawing both for car and lamps if (CameraChanged == 0 && *clock == (FrameCnt & 0xffffU)-1) { int old_x, old_y; old_x = trails[FrameCnt - 3U & 3].x; old_y = trails[FrameCnt - 3U & 3].y; trails[FrameCnt & 3].x = x; trails[FrameCnt & 3].y = y; if (size > 1 && ABS(old_x - x) + ABS(old_y - y) > 1) { int angle, width; VERTTYPE dx, dy; trail = (POLY_G4 *)current->primptr; setPolyG4(trail); setSemiTrans(trail, 1); angle = -ratan2(old_x - x,old_y - y) & 0xfff; width = ABS(poly->x0 - poly->x3); #ifdef PSX dx = RCOS(angle) * width * 3; dy = RSIN(angle) * width * 3; if (col->cd & 0x40) { dx >>= 0x10; dy >>= 0x10; } else { dx >>= 0xf; dy >>= 0xf; } trail->x0 = x + dx * tail_width; trail->y0 = y + dy * tail_width; trail->x1 = x - dx * tail_width; trail->y1 = y - dy * tail_width; trail->x2 = old_x + dx; trail->y2 = old_y + dy; trail->x3 = old_x - dx; trail->y3 = old_y - dy; #else // [A] slightly bigger light trail dx = RCOS(angle); dy = RSIN(angle); if (col->cd & 0x40) { dx = dx / 40000.0f; dy = dy / 40000.0f; } else { dx = dx / 32768.0f; dy = dy / 32768.0f; } trail->x0 = x + dx * width * 3 * tail_width; trail->y0 = y + dy * width * 3 * tail_width; trail->x1 = x - dx * width * 3 * tail_width; trail->y1 = y - dy * width * 3 * tail_width; trail->x2 = old_x + dx * width * 3; trail->y2 = old_y + dy * width * 3; trail->x3 = old_x - dx * width * 3; trail->y3 = old_y - dy * width * 3; #endif if (col->cd & 0x18) { trail->r0 = trail->r1 = col->r / 2; trail->g0 = trail->g1 = col->g / 2; trail->b0 = trail->b1 = col->b / 2; } else { trail->r0 = trail->r1 = col->r; trail->g0 = trail->g1 = col->g; trail->b0 = trail->b1 = col->b; } trail->r2 = trail->r3 = 0; trail->g2 = trail->g3 = 0; trail->b2 = trail->b3 = 0; addPrim(current->ot + z, trail); current->primptr += sizeof(POLY_G4); null = (POLY_FT3 *)current->primptr; setPolyFT3(null); null->x0 = -1; null->y0 = -1; null->x1 = -1; null->y1 = -1; null->x2 = -1; null->y2 = -1; null->tpage = 0x20; addPrim(current->ot + z, null); current->primptr += sizeof(POLY_FT3); } } else { for (i = 0; i < 4; i++) { trails[i].x = x; trails[i].y = y; } } *clock = FrameCnt; } // [D] [T] void ShowGroundLight(VECTOR *v1, CVECTOR *col, short size) { POLY_FT4 *poly; SVECTOR vert[4]; int z; #ifndef PSX // [A] limit drawing distance to avoid artifacts if (ABS(v1->vx) > 32000 || ABS(v1->vz) > 32000) return; #endif gte_SetRotMatrix(&inv_camera_matrix); gte_SetTransVector(&dummy); // [A] might be incorrect vert[0].vx = v1->vx - size; vert[0].vy = v1->vy; vert[0].vz = v1->vz + size; vert[1].vx = v1->vx + size; vert[1].vy = v1->vy; vert[1].vz = v1->vz + size; vert[2].vx = v1->vx - size; vert[2].vy = v1->vy; vert[2].vz = v1->vz - size; vert[3].vx = v1->vx + size; vert[3].vy = v1->vy; vert[3].vz = v1->vz - size; gte_ldv3(&vert[0], &vert[1], &vert[2]); gte_rtpt(); gte_stsz(&z); if (z - 150 < 9851) { poly = (POLY_FT4 *)current->primptr; setPolyFT4(poly); setSemiTrans(poly, 1); *(ushort*)&poly->u0 = *(ushort*)&light_texture.coords.u0; *(ushort*)&poly->u1 = *(ushort*)&light_texture.coords.u1; *(ushort*)&poly->u2 = *(ushort*)&light_texture.coords.u2; *(ushort*)&poly->u3 = *(ushort*)&light_texture.coords.u3; poly->tpage = light_texture.tpageid | 0x20; poly->clut = light_texture.clutid;; poly->r0 = col->r; poly->g0 = col->g; poly->b0 = col->b; gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); gte_ldv0(&vert[3]); gte_rtps(); gte_stsxy(&poly->x3); addPrim(current->ot + (z >> 3), poly); current->primptr += sizeof(POLY_FT4); } } // [D] [T] void RoundShadow(VECTOR *v1, CVECTOR *col, short size) { POLY_FT4* poly; SVECTOR vert[4]; int z; gte_SetRotMatrix(&inv_camera_matrix); gte_SetTransVector(&dummy); vert[0].vz = 0; vert[1].vz = 0; vert[2].vz = 0; vert[3].vz = 0; vert[0].vx = v1->vx - size; vert[0].vy = v1->vy; vert[0].vz = size + v1->vz; vert[1].vx = size + v1->vx; vert[1].vy = v1->vy; vert[1].vz = size + v1->vz; vert[2].vx = v1->vx - size; vert[2].vy = v1->vy; vert[2].vz = v1->vz - size; vert[3].vx = size + v1->vx; vert[3].vy = v1->vy; vert[3].vz = v1->vz - size; gte_ldv3(&vert[0], &vert[1], &vert[2]); gte_rtpt(); poly = (POLY_FT4*)current->primptr; poly->u0 = light_texture.coords.u0; poly->v0 = light_texture.coords.v0; poly->u1 = light_texture.coords.u1; poly->v1 = light_texture.coords.v1; poly->u2 = light_texture.coords.u2; poly->v2 = light_texture.coords.v2; poly->u3 = light_texture.coords.u3; poly->v3 = light_texture.coords.v3; poly->tpage = light_texture.tpageid | 0x40; poly->clut = light_texture.clutid; setPolyFT4(poly); setSemiTrans(poly, 1); poly->r0 = col->r; poly->g0 = col->g; poly->b0 = col->b; gte_stsz(&z); if (z - 150 < 9851) { gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); gte_ldv0(&vert[3]); gte_rtps(); gte_stsxy(&poly->x3); addPrim(current->ot + (z >> 3), poly); current->primptr += sizeof(POLY_FT4); } } // [D] [T weird and unused] void DisplayWater(SMOKE *smoke) { POLY_FT4* poly; VECTOR v; SVECTOR vert[4]; int size; int z; int z1; int z2; int z3; int z4; gte_SetRotMatrix(&inv_camera_matrix); gte_SetTransVector(&dummy); size = smoke->start_w; vert[0].vx = (smoke->position.vx - size) - camera_position.vx; vert[0].vy = 50 - camera_position.vy; vert[0].vz = (smoke->position.vz + size) - camera_position.vz; vert[1].vx = (smoke->position.vx + size) - camera_position.vx; vert[1].vy = 50 - camera_position.vy; vert[1].vz = (smoke->position.vz + size) - camera_position.vz; vert[2].vx = (smoke->position.vx - size) - camera_position.vx; vert[2].vy = 50 - camera_position.vy; vert[2].vz = (smoke->position.vz - size) - camera_position.vz; vert[3].vx = (smoke->position.vx + size) - camera_position.vx; vert[3].vy = 50 - camera_position.vy; vert[3].vz = (smoke->position.vz - size) - camera_position.vz; poly = (POLY_FT4*)current->primptr; gte_ldv3(&vert[0], &vert[1], &vert[2]); gte_rtpt(); setPolyFT4(poly); poly->r0 = NightAmbient; poly->g0 = NightAmbient; poly->b0 = NightAmbient; poly->tpage = sea_texture.tpageid; gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); gte_stsz3(&z1, &z2, &z3); gte_ldv0(&vert[3]); gte_rtps(); gte_stsxy(&poly->x3); poly->u0 = sea_texture.coords.u0; poly->v0 = sea_texture.coords.v0; poly->u1 = sea_texture.coords.u1; poly->v1 = sea_texture.coords.v1; poly->u2 = sea_texture.coords.u2; poly->v2 = sea_texture.coords.v2; poly->u3 = sea_texture.coords.u3; poly->v3 = sea_texture.coords.v3; poly->clut = sea_texture.clutid; gte_stsz(&z4); z = z1 + z2 + z3 + z4 >> 5; if (z < 9) z = 9; addPrim(current->ot + z, poly); current->primptr += sizeof(POLY_FT4); } // [D] [T] void DisplaySpark(SMOKE *spark) { int colorind; POLY_G3 *poly; SVECTOR v[3]; SVECTOR TrailPos; int z; TrailPos.vx = spark->position.vx - camera_position.vx; TrailPos.vy = spark->position.vy - camera_position.vy; TrailPos.vz = spark->position.vz - camera_position.vz; gte_SetRotMatrix(&inv_camera_matrix); gte_SetTransVector(&dummy); v[0].vx = TrailPos.vx; v[0].vy = TrailPos.vy; v[0].vz = TrailPos.vz; v[1].vx = TrailPos.vx + 5; v[1].vy = TrailPos.vy; v[1].vz = TrailPos.vz + 5; v[2].vx = spark->final_tail_pos.vx - camera_position.vx; v[2].vy = spark->final_tail_pos.vy - camera_position.vy; v[2].vz = spark->final_tail_pos.vz - camera_position.vz; poly = (POLY_G3 *)current->primptr; gte_ldv3(&v[0], &v[1], &v[2]); gte_rtpt(); setPolyG3(poly); if (spark->start_w == 2) { colorind = spark->drift.vy * 3 & 3; if (gTimeOfDay == 1) { poly->r0 = grassColour[colorind][0]; poly->g0 = grassColour[colorind][1]; poly->b0 = grassColour[colorind][2]; poly->r1 = grassColour[colorind][0]; poly->g1 = grassColour[colorind][1]; poly->b1 = grassColour[colorind][2]; colorind = (spark->drift.vy + 2U) * 3 & 3; poly->r2 = grassColour[colorind][0]; poly->g2 = grassColour[colorind][1]; poly->b2 = grassColour[colorind][2]; } else { poly->r0 = 0; poly->g0 = (spark->transparency >> 3); poly->r1 = 0; poly->b0 = (spark->transparency >> 4); poly->g1 = (spark->transparency >> 3); poly->r2 = 12; poly->g2 = 4; poly->b2 = 4; poly->b1 = (spark->transparency >> 4); } } else { poly->r0 = spark->transparency; poly->g0 = spark->transparency; poly->b0 = spark->transparency / 2; poly->r1 = spark->transparency; poly->g1 = spark->transparency; poly->b1 = spark->transparency / 2; poly->r2 = spark->transparency; poly->g2 = 0; poly->b2 = 0; } gte_stsz(&z); if (z > 50) { if (z >> 3 < 9) z = 72; gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); addPrim(current->ot + (z >> 3), poly); current->primptr += sizeof(POLY_G3); } } int SmokeCnt = 0; // [D] [T] void GetSmokeDrift(VECTOR *Wind) { static int SinTabIndex1 = 10; static int SinTabIndex2 = 0; static int SinTabIndex3 = 5; static int SinX = 0; static int CosX = 0; static int WindMagnitude = 0; if (SmokeCnt != CameraCnt) { SmokeCnt = CameraCnt; SinTabIndex1 = SinTabIndex1 + 3 & 0xfff; SinTabIndex2 = SinTabIndex2 + 5 & 0xfff; SinTabIndex3 = SinTabIndex3 + 7 & 0xfff; SinX = isin(SinTabIndex1) + isin(SinTabIndex2); CosX = icos(SinTabIndex1) + icos(SinTabIndex2); WindMagnitude = isin(SinTabIndex3) >> 0xb; } Wind->vy = 0; Wind->vx = FIXEDH(WindMagnitude * CosX); Wind->vz = FIXEDH(-WindMagnitude * SinX); } // [D] [T] void Setup_Debris(VECTOR *ipos, VECTOR *ispeed, int num_debris, int type) { int num; int seed; int col; int i; DEBRIS *mydebris; col = type >> 0x10; for (i = 0; i < num_debris; i++) { num = AllocateDebris(); if (num == -1) return; mydebris = &debris[num]; mydebris->position.vx = ipos->vx; mydebris->position.vy = ipos->vy; mydebris->position.vz = ipos->vz; if ((type & 0xffffU) < 8) { seed = rand(); mydebris->step = seed; mydebris->rgb.r = debris_colour[GameLevel][col].r; mydebris->rgb.g = debris_colour[GameLevel][col].g; mydebris->rgb.b = debris_colour[GameLevel][col].b; if (gTimeOfDay == 3) { mydebris->rgb.r >>= 1; mydebris->rgb.g >>= 1; mydebris->rgb.b >>= 1; } mydebris->direction.vx = FIXED((ispeed->vx + ((seed & 0x7f) - 64) * num_debris) * 1024); mydebris->direction.vy = -FIXED((seed & 0x7f00) * num_debris * 2); mydebris->direction.vz = FIXED(ispeed->vz + ((rand() & 0x7fff) - 16384) * num_debris * 2); } else { mydebris->step = 2; mydebris->rgb.b = 60; mydebris->rgb.g = 60; mydebris->rgb.r = 60; mydebris->direction.vx = FIXED(ispeed->vx); mydebris->direction.vy = -FIXED(ispeed->vy); mydebris->direction.vz = FIXED(ispeed->vz); } mydebris->type = type & 7; mydebris->life = 128; mydebris->flags = 0x2; mydebris->pos = i & 0x1f; } } // [D] [T] void Setup_Smoke(VECTOR *ipos, int start_w, int end_w, int SmokeType, int WheelSpeed, VECTOR *Drift, int Exhaust) { int num; SMOKE *mysmoke; num = AllocateSmoke(); if (num == -1) return; mysmoke = &smoke[num]; if (SmokeType == SMOKE_FIRE) { mysmoke->position.vx = ipos->vx; mysmoke->position.vy = ipos->vy; mysmoke->start_w = start_w; mysmoke->final_w = end_w; mysmoke->position.vz = ipos->vz; mysmoke->step = end_w - start_w >> 7 << 2; mysmoke->flags = 0x1000 | 0x4 | 0x2; mysmoke->life = 20; mysmoke->halflife = 10; if (WheelSpeed > 200000) mysmoke->transparency = (800000 - WheelSpeed >> 0xb); else mysmoke->transparency = 0xff; mysmoke->t_step = end_w - start_w >> 2; } else if (SmokeType == SMOKE_BLACK) { if (Exhaust) { mysmoke->position.vx = ipos->vx + (rand() & 9); mysmoke->position.vy = ipos->vy; mysmoke->position.vz = ipos->vz + (rand() & 9); mysmoke->flags = 0x2000 | 0x4 | 0x2; mysmoke->transparency = 140; mysmoke->t_step = 5; mysmoke->step = 1; } else { mysmoke->position.vx = ipos->vx; mysmoke->position.vy = ipos->vy; mysmoke->position.vz = ipos->vz; if (WheelSpeed > 200000) mysmoke->transparency = (800000 - WheelSpeed >> 0xb); else mysmoke->transparency = 255; mysmoke->t_step = end_w - start_w >> 5; mysmoke->step = (end_w - start_w) / 128 * 4; } mysmoke->start_w = start_w; mysmoke->final_w = end_w; mysmoke->flags = 0x2000 | 0x4 | 0x2; mysmoke->life = 40; mysmoke->halflife = 20; } else if (SmokeType == SMOKE_WHITE || SmokeType == 5) { if (Exhaust) { mysmoke->position.vx = ipos->vx + (rand() & 7); mysmoke->position.vy = ipos->vy; mysmoke->position.vz = ipos->vz + (rand() & 7); mysmoke->flags = 0x4000 | 0x4 | 0x2; mysmoke->transparency = 55; mysmoke->t_step = 2; mysmoke->step = 1; mysmoke->life = 24; } else { mysmoke->position.vx = ipos->vx + (rand() & 0x3f); mysmoke->position.vy = ipos->vy; mysmoke->position.vz = ipos->vz + (rand() & 0x3f); mysmoke->flags = 0x10 | 0x4 | 0x2; if (SmokeType == 5) // UNUSED { mysmoke->life = 32; mysmoke->step = end_w >> 5 << 2; mysmoke->t_step = end_w - start_w >> 5; mysmoke->transparency = WheelSpeed; } else { mysmoke->life = 128; mysmoke->step = (end_w - start_w) / 128 * 8; mysmoke->t_step = (end_w - start_w >> 6); mysmoke->transparency = 80; } } mysmoke->start_w = start_w; mysmoke->final_w = end_w; mysmoke->halflife = 64; } else if (SmokeType == 6) // UNUSED { mysmoke->position.vx = ipos->vx; mysmoke->position.vy = ipos->vy; mysmoke->position.vz = ipos->vz; mysmoke->flags = 0x40 | 0x4 | 0x2; mysmoke->transparency = 160; mysmoke->step = 20; mysmoke->t_step = 5; mysmoke->start_w = start_w; mysmoke->final_w = end_w; mysmoke->life = 78; mysmoke->halflife = 32; } else { mysmoke->position.vx = ipos->vx + (rand() & 0x3f); mysmoke->position.vy = ipos->vy; mysmoke->flags = 0x20 | 0x4 | 0x2; mysmoke->transparency = 60; mysmoke->t_step = 5; mysmoke->start_w = start_w; mysmoke->final_w = end_w; mysmoke->position.vz = ipos->vz + (rand() & 0x3f); mysmoke->step = (end_w / 128) * 8; mysmoke->life = 128; mysmoke->halflife = 64; } if (Exhaust != 0) { mysmoke->drift.vx = Drift->vx; mysmoke->drift.vy = Drift->vy; mysmoke->drift.vz = Drift->vz; mysmoke->drift_change.vx = 0; mysmoke->drift_change.vy = 0; mysmoke->drift_change.vz = 0; } else { mysmoke->drift.vx = 0; mysmoke->drift.vy = 0; mysmoke->drift.vz = 0; if (mysmoke->life < 40 || SmokeType == 4) { mysmoke->drift_change.vx = 0; mysmoke->drift_change.vy = 1; mysmoke->drift_change.vz = 0; } else { mysmoke->drift_change.vx = Drift->vx; mysmoke->drift_change.vy = Drift->vy; mysmoke->drift_change.vz = Drift->vz; } } } // [D] [T] void Setup_Sparks(VECTOR *ipos, VECTOR *ispeed, int num_sparks, char SparkType) { int num; int seed; int vz; int vy; int vx; int i; SMOKE *mysmoke; if (pauseflag != 0 || 0 >= num_sparks) return; for (i = 0; i < num_sparks; i++) { num = AllocateSmoke(); if (num == -1) return; mysmoke = &smoke[num]; seed = rand(); mysmoke->position.vx = mysmoke->final_tail_pos.vx = ipos->vx; mysmoke->position.vy = mysmoke->final_tail_pos.vy = ipos->vy; mysmoke->position.vz = mysmoke->final_tail_pos.vz = ipos->vz; mysmoke->pos = (i << 2); mysmoke->step = seed & 0x3f; mysmoke->drift.vx = 2; mysmoke->flags = 0x8 | 0x2; vx = ispeed->vx; vy = ispeed->vy; vz = ispeed->vz; mysmoke->drift_change.vx = FIXED((vx - 16384 + (seed & 0x7f00)) * 4); mysmoke->drift_change.vy = -FIXED((vy + (seed & 0x7f)) * 1024); mysmoke->drift_change.vz = FIXED(vz - 64 + (rand() & 0x7f) >> 2); if (SparkType == 1) { mysmoke->life = 10; mysmoke->transparency = 200; mysmoke->t_step = 2; mysmoke->start_w = 0; } else if (SparkType == 2) { mysmoke->life = 10; mysmoke->transparency = 0xff; mysmoke->t_step = 10; mysmoke->start_w = 2; mysmoke->drift.vy = rand() & 3; } else { mysmoke->life = 40; mysmoke->transparency = 0xff; mysmoke->t_step = 10; mysmoke->start_w = 1; } } } // [D] [T] void DisplayDebris(DEBRIS *debris, char type) { int uVar3; TRI_POINT* tv; POLY_GT4 *poly1; POLY_FT3 *poly; SVECTOR v[4]; VECTOR debrisvec; int z; debrisvec.vx = debris->position.vx - camera_position.vx; debrisvec.vy = debris->position.vy - camera_position.vy; debrisvec.vz = debris->position.vz - camera_position.vz; if (debrisvec.vx >= -10000 && debrisvec.vz >= -10000 && debrisvec.vx <= 10000 && debrisvec.vz <= 10000) { tv = debris_rot_table[debris->type & 7] + (debris->pos >> 3 & 0x1fU); v[0].vx = tv->v0.vx + debrisvec.vx; v[0].vy = tv->v0.vy + debrisvec.vy; v[0].vz = tv->v0.vz + debrisvec.vz; v[1].vx = tv->v1.vx + debrisvec.vx; v[1].vy = tv->v1.vy + debrisvec.vy; v[1].vz = tv->v1.vz + debrisvec.vz; v[2].vx = tv->v2.vx + debrisvec.vx; v[2].vy = tv->v2.vy + debrisvec.vy; v[2].vz = tv->v2.vz + debrisvec.vz; gte_ldv3(&v[0], &v[1], &v[2]); gte_rtpt(); if (type - 1U < 2) { poly1 = (POLY_GT4 *)current->primptr; gte_stsxy3(&poly1->x0, &poly1->x1, &poly1->x2); gte_stsz(&z); if (z > 223) { *(ushort*)&poly1->u0 = *(ushort*)&litter_texture.coords.u0; *(ushort*)&poly1->u1 = *(ushort*)&litter_texture.coords.u1; *(ushort*)&poly1->u2 = *(ushort*)&litter_texture.coords.u2; *(ushort*)&poly1->u3 = *(ushort*)&litter_texture.coords.u3; poly1->clut = litter_texture.clutid; poly1->tpage = litter_texture.tpageid; v[3].vx = debrisvec.vx - tv->v0.vx; v[3].vy = debrisvec.vy - tv->v0.vy; v[3].vz = debrisvec.vz - tv->v0.vz; gte_ldv0(&v[3]); gte_rtps(); gte_stsxy(&poly1->x3); if (type == 2) uVar3 = (debris->rgb.b + combointensity) * 0x10000 | (debris->rgb.g + combointensity) * 0x100 | 0x3c000000 | debris->rgb.r + combointensity; else uVar3 = debris->rgb.b << 0x10 | debris->rgb.g << 8 | 0x3c000000 | debris->rgb.r; *(u_int *)&poly1->r0 = uVar3; *(u_int *)&poly1->r2 = uVar3; *(u_int *)&poly1->r1 = uVar3 + 0x202020; *(u_int *)&poly1->r3 = uVar3 + 0x303030; setPolyGT4(poly1); addPrim(current->ot + (z >> 3), poly1); current->primptr += sizeof(POLY_GT4); } } else { poly = (POLY_FT3 *)current->primptr; gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); gte_stsz(&z); if (z > 223) { *(ushort*)&poly->u0 = *(ushort*)&debris_texture.coords.u0; *(ushort*)&poly->u1 = *(ushort*)&debris_texture.coords.u1; *(ushort*)&poly->u2 = *(ushort*)&debris_texture.coords.u2; poly->r0 = debris->rgb.r; poly->g0 = debris->rgb.g; poly->b0 = debris->rgb.b; poly->tpage = debris_texture.tpageid; poly->clut = debris_texture.clutid; setPolyFT3(poly); addPrim(current->ot + (z >> 3), poly); current->primptr += sizeof(POLY_FT3); } } } else { debris->life = 1; } } // [D] [T] void DisplaySmoke(SMOKE* smoke) { int Z; int tmode; POLY_FT4* poly; VECTOR v; SVECTOR smokemesh[4]; int smoke_z_offset; smoke_z_offset = 0; v.vx = smoke->position.vx - camera_position.vx; v.vy = smoke->position.vy - camera_position.vy; v.vz = smoke->position.vz - camera_position.vz; if (ABS(v.vx) > 20480 || ABS(v.vz) > 20480) return; Apply_Inv_CameraMatrix(&v); gte_SetTransVector(&v); gte_SetRotMatrix(&identity); smokemesh[0].vx = -smoke->start_w; smokemesh[0].vy = -smoke->start_w; smokemesh[0].vz = 0; smokemesh[1].vx = smoke->start_w; smokemesh[1].vy = -smoke->start_w; smokemesh[1].vz = 0; smokemesh[2].vx = -smoke->start_w; smokemesh[2].vy = smoke->start_w; smokemesh[2].vz = 0; smokemesh[3].vx = smoke->start_w; smokemesh[3].vy = smoke->start_w; smokemesh[3].vz = 0; poly = (POLY_FT4*)current->primptr; gte_ldv3(&smokemesh[0], &smokemesh[1], &smokemesh[2]); gte_rtpt(); tmode = 0x20; if (smoke->flags & 0x4000) { poly->r0 = smoke->transparency; poly->g0 = smoke->transparency; poly->b0 = smoke->transparency; } else if (smoke->flags & 0x2000) { if (gNight) { poly->r0 = smoke->transparency / 2; poly->g0 = smoke->transparency / 2; poly->b0 = smoke->transparency / 2; } else { poly->r0 = smoke->transparency >> 2; poly->g0 = smoke->transparency >> 2; poly->b0 = smoke->transparency >> 2; } tmode = 0x40; smoke_z_offset = 17; } else if (smoke->flags & 0x1000) { if ((smoke->transparency >> 3) + 50 & 0xff < 60) poly->g0 = (smoke->transparency >> 3); else poly->g0 = smoke->transparency >> 2; smoke_z_offset = 18; poly->r0 = smoke->transparency; poly->b0 = smoke->transparency >> 3; } else if (smoke->flags & 0x20) { poly->r0 = smoke->transparency >> 1; poly->g0 = smoke->transparency; poly->b0 = smoke->transparency + 10; tmode = 0x40; } else if (smoke->flags & 0x40) { if (gNight == 0) { poly->r0 = smoke->transparency >> 2; poly->g0 = smoke->transparency >> 2; poly->b0 = smoke->transparency >> 2; } else { poly->r0 = smoke->transparency >> 3; poly->g0 = smoke->transparency >> 3; poly->b0 = smoke->transparency + 10 >> 3; } } else { if (gNight == 0) { poly->r0 = smoke->transparency; poly->g0 = smoke->transparency; poly->b0 = smoke->transparency + 10; } else { poly->r0 = smoke->transparency / 2; poly->g0 = smoke->transparency / 2; poly->b0 = smoke->transparency + 10 >> 1; } smoke_z_offset = 25; } gte_stsxy3(&poly->x0, &poly->x1, &poly->x2); gte_stsz(&Z); gte_ldv0(&smokemesh[3]); gte_rtps(); poly->u0 = smoke_texture.coords.u0; poly->v0 = smoke_texture.coords.v0; poly->u1 = smoke_texture.coords.u1; poly->v1 = smoke_texture.coords.v1; poly->u2 = smoke_texture.coords.u2; poly->v2 = smoke_texture.coords.v2 - 4; // [A] ??? poly->u3 = smoke_texture.coords.u3; poly->v3 = smoke_texture.coords.v3 - 4; // [A] ??? poly->tpage = smoke_texture.tpageid | tmode; poly->clut = smoke_texture.clutid; setPolyFT4(poly); setSemiTrans(poly, 1); if (Z >> 3 > 0) { int x, y; smoke_z_offset = (Z >> 3) - smoke_z_offset; if (smoke_z_offset < 9) smoke_z_offset = 9; gte_stsxy(&poly->x3); addPrim(current->ot + smoke_z_offset, poly); // reduce size? if ((poly->x1 - poly->x0) / 2 > 100) { x = (poly->x0 + poly->x3) / 2; y = (poly->y0 + poly->y3) / 2; // FIXME: * 0x10000 is needed because clipping issue poly->x0 = (y - 50) << 0x10; poly->y0 = x - 50; poly->x1 = (y - 50) << 0x10; poly->y1 = x + 50; poly->x2 = (y + 50) << 0x10; poly->y2 = x - 50; poly->x3 = (y + 50) << 0x10; poly->y3 = x + 50; } current->primptr += sizeof(POLY_FT4); } } int NoRainIndoors = 0; // [D] [T] void HandleDebris(void) { int Height; SMOKE *sm; DEBRIS *db; LEAF *lf; int i; VECTOR Drift; GetSmokeDrift(&Drift); MoveHubcap(); SetRotMatrix(&inv_camera_matrix); gte_SetTransVector(&dummy); db = debris; i = next_debris; while (i > 0) { if (db->flags & 0x2) { DisplayDebris(db, 0); if (pauseflag == 0) { if (--db->life == 0 || db->position.vy > 0) { db->flags = 0; ReleaseDebris(db->num); } else { db->position.vx += db->direction.vx; db->position.vy += db->direction.vy; db->position.vz += db->direction.vz; db->pos += db->step; if (db->type == 3) db->direction.vy += 1; else db->direction.vy += 6; } } } db++; i--; } lf = leaf; i = next_leaf; // Move leaves while (i > 0) { if (lf->flags & 0x2) { DisplayDebris((DEBRIS *)lf, lf->type); if (pauseflag == 0) { if (lf->life == 1) { lf->flags = 0; ReleaseLeaf(lf->num); } else { int sn1, sn2, cs1, cs2; GetSmokeDrift(&Drift); Height = -(lf->position.pad + 20); // first we move debris // SwirlLeaves basically changed direction vector // in order to lift leaf from ground fast if (lf->position.vy < Height) { lf->position.vx += lf->direction.vx + Drift.vx; lf->position.vy += lf->direction.vy + Drift.vy; lf->position.vz += lf->direction.vz + Drift.vz; lf->pos += lf->step; lf->pos &= 0xff; } else { lf->position.vy = Height; } lf->sin_index1 += lf->sin_addition1; lf->sin_index2 += lf->sin_addition2; lf->sin_index1 &= 0xfff; lf->sin_index2 &= 0xfff; sn1 = RSIN(lf->sin_index1); sn2 = RSIN(lf->sin_index2); cs1 = RCOS(lf->sin_index1); cs2 = RCOS(lf->sin_index2); // then we compute completely new direction lf->direction.vy = ((sn1 + sn2) >> 0xb) + 4; lf->direction.vx = ((sn1 + sn2) * 5 >> 0xb); lf->direction.vz = ((cs1 + cs2) * 5 >> 0xb); } } } lf++; i--; } for (i = 0; i < MAX_SMOKE; i++) { sm = &smoke[i]; if (sm->flags & 0x2) { if (sm->flags & 0x8) { DisplaySpark(sm); // yup, smoke particles are sparks too } else if (sm->flags & 0x4) { if (sm->flags & 0x8000) DisplayWater(sm); // Really obsolete, water was only a thing in Driver 1 else DisplaySmoke(sm); } } if (sm->flags & 0x2 && pauseflag == 0) { if (sm->flags & 0x8000) { // OBSOLETE DRIVER 1 CODE /* ROUTE_DATA routeData; ROADS_GetRouteData(sm->position.vx - sm->start_w, sm->position.vz - sm->start_w, &routeData); ROADS_GetRouteData(sm->position.vx + sm->start_w, sm->position.vz + sm->start_w, &routeData); if (sm->start_w < 800 && (modelpointers[routeData.type]->shape_flags & MODEL_FLAG_ALLEY)) sm->start_w += sm->step; else*/ sm->start_w -= sm->step; } else if (sm->flags & 0x8) { sm->position.vx += sm->drift_change.vx; sm->position.vy += sm->drift_change.vy; sm->position.vz += sm->drift_change.vz; sm->drift_change.vy += 6; if (sm->drift.vx == 0) { sm->final_tail_pos.vx += sm->drift_change.vx; sm->final_tail_pos.vy += sm->drift_change.vy - 12; sm->final_tail_pos.vz += sm->drift_change.vz; } else { sm->drift.vx -= 1; } if (sm->position.vy > 0) { sm->flags = 0; ReleaseSmoke(sm->num); continue; } } else { if (sm->start_w < 800) sm->start_w += sm->step; sm->position.vx += sm->drift.vx; sm->position.vy += sm->drift.vy; sm->position.vz += sm->drift.vz; if (sm->halflife < sm->life) { sm->drift.vx -= sm->drift_change.vx; sm->drift.vy -= sm->drift_change.vy; sm->drift.vz -= sm->drift_change.vz; } } if (sm->flags & 0x900C) { sm->transparency -= sm->t_step; if (sm->transparency < 1) { sm->transparency = 0; sm->life = 1; } if (--sm->life == 0) { sm->flags = 0; ReleaseSmoke(sm->num); } } } } if (pauseflag == 0) { main_cop_light_pos++; main_cop_light_pos &= 7; variable_weather = 1; if (variable_weather != 0) { static int weather_level = 0; weather_level = RSIN(CameraCnt) + RSIN(CameraCnt / 4); if (weather_level < 1) gRainCount = -weather_level >> 8; else gRainCount = weather_level >> 8; if (gRainCount > MAX_RAIN_DROPS) gRainCount = MAX_RAIN_DROPS; } } } // [D] [T] void add_haze(int top_col, int bot_col, short ot_pos) { TILE *polys; if (top_col > 9 && FastForward == 0) { polys = (TILE *)current->primptr; setTile(polys); polys->r0 = top_col; polys->g0 = top_col; polys->b0 = top_col; setSemiTrans(polys, 1); #ifdef PSX polys->x0 = 0; polys->w = 320; #else polys->x0 = -500; polys->w = 1200; #endif polys->y0 = 0; polys->h = 256; addPrim(current->ot + ot_pos, polys); current->primptr += sizeof(TILE); POLY_FT3* null = (POLY_FT3*)current->primptr; setPolyFT3(null); null->x0 = -1; null->y0 = -1; null->x1 = -1; null->y1 = -1; null->x2 = -1; null->y2 = -1; null->tpage = 0x20; addPrim(current->ot + ot_pos, null); current->primptr += sizeof(POLY_FT3); } } // [D] [T] void SetupRain(void) { gNextRainDrop = 0; do { gRainAlloc[gNextRainDrop] = gNextRainDrop; gRain[gNextRainDrop].oldposition.pad = gNextRainDrop; gNextRainDrop++; } while (gNextRainDrop < MAX_RAIN_DROPS); gNextRainDrop = 0; } // [D] [T] int AllocateRainDrop(void) { if (gNextRainDrop < MAX_RAIN_DROPS) return gRainAlloc[gNextRainDrop++]; return -1; } // [D] [T] void ReleaseRainDrop(int RainIndex) { gNextRainDrop--; gRainAlloc[gNextRainDrop] = RainIndex; } // [D] [T] void DisplaySplashes(void) { static u_int rand; int d1; int d2; VECTOR CamGnd; VECTOR Gnd1; VECTOR Gnd2; VECTOR Position; CVECTOR col = { 25, 25, 25 }; int ang; int SplashNo, SplashFrac; if (pauseflag != 0) return; if (gRainCount >> 2 > 30) SplashNo = 30; else SplashNo = (gRainCount >> 2); SplashFrac = FIXEDH(SplashNo * FrAng * 3); gte_SetRotMatrix(&identity); // [A] norot CamGnd.vx = camera_position.vx; CamGnd.vz = camera_position.vz; CamGnd.vy = -camera_position.vy - MapHeight(&CamGnd); ang = FrAng - camera_angle.vy; Gnd1.vx = RSIN(ang) + camera_position.vx; Gnd1.vz = RCOS(ang) + camera_position.vz; Gnd1.vx = Gnd1.vx - CamGnd.vx; Gnd1.vy = -camera_position.vy - MapHeight(&Gnd1) - CamGnd.vy; Gnd1.vz = Gnd1.vz - CamGnd.vz; ang = -FrAng - camera_angle.vy; Gnd2.vx = RSIN(ang) + camera_position.vx; Gnd2.vz = RCOS(ang) + camera_position.vz; Gnd2.vx = Gnd2.vx - CamGnd.vx; Gnd2.vy = (-camera_position.vy - MapHeight(&Gnd2)) - CamGnd.vy; Gnd2.vz = Gnd2.vz - CamGnd.vz; while (--SplashFrac >= 0) { d2 = rand * 0x19660d + 0x3c6ef35f; d1 = d2 >> 4 & 0xfff; rand = d2 * 0x19660d + 0x3c6ef35f; d2 = rand >> 0xe & 0xfff; Position.vx = FIXEDH(Gnd1.vx * d1 + Gnd2.vx * d2); Position.vy = FIXEDH(Gnd1.vy * d1 + Gnd2.vy * d2) + CamGnd.vy; Position.vz = FIXEDH(Gnd1.vz * d1 + Gnd2.vz * d2); ShowLight(&Position, &col, 12, &drop_texture); } } #define RAIN_DROP_SPEED 30 // [A] was 20 // [D] [T] void DrawRainDrops(void) { int z; int Count; POLY_GT3 *poly; RAIN_TYPE *RainPtr; int col; int bright; SVECTOR v; VECTOR drift; if (gNextRainDrop == 0) return; GetSmokeDrift(&drift); bright = 70; if (bright < 50) bright = 50; if (gNight != 0) bright -= -15; col = bright >> 1 | (bright >> 1) << 8; col |= col | col << 0x10; DisplaySplashes(); gte_SetRotMatrix(&inv_camera_matrix); gte_SetTransVector(&dummy); RainPtr = gRain; Count = gNextRainDrop-1; poly = (POLY_GT3 *)current->primptr; while (Count > 0) { v.vx = RainPtr->position.vx - camera_position.vx; v.vy = RainPtr->position.vy - camera_position.vy; v.vz = RainPtr->position.vz - camera_position.vz; if (pauseflag) { // [A] old position imitation // works effectively when player not moving gte_ldv0(&v); gte_rtps(); gte_stsxy(&poly->x0); v.vy += RAIN_DROP_SPEED; v.vx -= drift.vx * 2; v.vz -= drift.vz * 2; } else { RainPtr->position.vy += RAIN_DROP_SPEED; RainPtr->position.vx -= drift.vx * 2; RainPtr->position.vz -= drift.vz * 2; *(u_int *)&poly->x0 = *(u_int *)&RainPtr->oldposition; } gte_ldv0(&v); gte_rtps(); *(u_int *)&poly->r2 = col; *(u_int *)&poly->r1 = col; *(u_int *)&poly->r0 = 0; setPolyGT3(poly); setSemiTrans(poly, 1); gte_stsxy(&poly->x2); gte_stsz(&z); if (z - 151U < 2000 && poly->x2 > -101 && poly->x2 < 421 && poly->y2 > -51 && poly->y2 < 257) { if (*(u_int *)&RainPtr->oldposition != 0) { poly->x1 = poly->x2 - ((z >> 10) - 1); poly->x2 = poly->x2 + ((z >> 10) - 1); poly->y1 = poly->y2; *(u_int *)&RainPtr->oldposition = *(u_int *)&poly->x2; poly->clut = light_texture.clutid; poly->tpage = light_texture.tpageid | 0x20; *(ushort *)&poly->u0 = *(ushort *)&light_texture.coords.u0; *(ushort *)&poly->u1 = *(ushort *)&light_texture.coords.u1; *(ushort *)&poly->u2 = *(ushort *)&light_texture.coords.u2; addPrim(current->ot + (z >> 1), poly); poly++; } else *(u_int *)&RainPtr->oldposition = *(u_int *)&poly->x2; } else { if(pauseflag == 0) ReleaseRainDrop(RainPtr->oldposition.pad); } RainPtr++; Count--; } current->primptr = (char*)poly; } // [D] [T] void AddRainDrops(void) { static u_int rand; int first; int RainIndex; int tmp; int i; SVECTOR v; ROUTE_DATA routeData; int count; RAIN_TYPE* rt; count = gRainCount; first = 1; if (pauseflag != 0 || NoRainIndoors != 0) return; wetness += count / 6; if (wetness > 7000) wetness = 7000; gte_SetRotMatrix(&camera_matrix); gte_SetTransVector(&camera_position); i = 0; while (i < count) { i++; RainIndex = AllocateRainDrop(); if (RainIndex < 0) return; tmp = rand * 0x19660d + 0x3c6ef35f; v.vz = (tmp >> 0x14 & 0x1ffU) + 400; tmp = tmp * 0x19660d + 0x3c6ef35f; v.vy = -((tmp >> 0x14) & 0x1ff); rand = tmp * 0x19660d + 0x3c6ef35f; v.vx = ((rand >> 0x14) & 0x1ff) - 256; if (v.vz > 512) { int depth; depth = (v.vz >> 8) + 1; v.vx *= depth; v.vy *= depth; } gte_ldv0(&v); gte_rtv0tr(); rt = &gRain[RainIndex]; rt->oldposition.vx = 0; rt->oldposition.vy = 0; rt->oldposition.vz = 0; rt->oldposition.pad = RainIndex; gte_stlvnl(&rt->position); // OBSOLETE DRIVER 1 CODE /* if(first) { ROADS_GetRouteData(rt->position.vx, rt->position.vz, &routeData); if (modelpointers[routeData.type]->flags2 & MODEL_FLAG_INDOORS) break; } */ first = 0; } } int lightning = 0; int LightningTimer = 10; int ThunderTimer = 0; static int ThunderDistance = 0; // [D] [T] void DoLightning(void) { if (pauseflag != 0) return; if (LightningTimer < -10) LightningTimer = rand() & 0xff; else LightningTimer--; if (LightningTimer < 0 && (rand() & 1) == 0) { RequestThunder(); if ((rand() & 1) == 0) { NightAmbient = NightAmbient << 1; if (NightAmbient > 128) NightAmbient = 128; lightning = 2; return; } add_haze(50, 0, 4222); } lightning = 0; } // [D] [T] void InitThunder(void) { ThunderTimer = -1; ThunderDistance = rand() % 5000; } // [D] [T] void RequestThunder(void) { ThunderTimer = ThunderDistance >> 8; if (ThunderTimer < 1) ThunderTimer = 1; } // [D] [T] void DoThunder(void) { if (pauseflag) return; ThunderDistance = (ThunderDistance + 40) - rand() % 80; if (ThunderDistance < 250) ThunderDistance = 250; if (ThunderDistance > 5000) ThunderDistance = 5000; if (ThunderTimer > -1) { ThunderTimer--; if(ThunderTimer == 0) StartSound(-1, SOUND_BANK_SFX, 8, -ThunderDistance, (rand() % 2048) + 3072); } } // [D] [T] void DoWeather(int weather) { if (weather != 1) return; if(pauseflag == 0) { if (gEffectsTimer < 41) { if ((FrameCnt & 7U) == 0) gEffectsTimer++; } else { AddRainDrops(); if ((FrameCnt & 7U) == 0) gRainCount++; if (gRainCount > 35) gRainCount = 35; } } DrawRainDrops(); } // [D] [T] int GetDebrisColour(CAR_DATA *cp) { int car_model; car_model = MissionHeader->residentModels[cp->ap.model]; if (car_model == 0) return 1; if(car_model < 8) return (car_model-1) * 6 + cp->ap.palette + 7; return car_model - 6; }