diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e550430..8384b9ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,8 @@ if(DETHRACE_WERROR) endif() endif() +option(DETHRACE_FIX_BUGS "Fix Dethrace bugs" ON) + add_subdirectory(src/harness) add_subdirectory(src/S3) add_subdirectory(src/BRSRC13) diff --git a/src/BRSRC13/CORE/V1DB/prepmesh.c b/src/BRSRC13/CORE/V1DB/prepmesh.c index ddd68c39..948b048a 100644 --- a/src/BRSRC13/CORE/V1DB/prepmesh.c +++ b/src/BRSRC13/CORE/V1DB/prepmesh.c @@ -604,8 +604,8 @@ void BrModelUpdate(br_model* model, br_uint_16 flags) { if (model->flags & BR_MODF_PREPREPARED) { return; } - if (!model->faces || !model->vertices) { - BrFailure("BrModelUpdate: model has no faces or vertices (%s)", model->identifier ? model->identifier : ""); + if (model->faces == NULL || model->vertices == NULL) { + BrFailure("BrModelUpdate: model has no faces or vertices (%s)", model->identifier != NULL ? model->identifier : ""); } if (flags & BR_MODU_UNKNOWN) { flags |= BR_MODU_NORMALS; diff --git a/src/DETHRACE/CMakeLists.txt b/src/DETHRACE/CMakeLists.txt index 663b376c..47a9ee1a 100644 --- a/src/DETHRACE/CMakeLists.txt +++ b/src/DETHRACE/CMakeLists.txt @@ -1,8 +1,6 @@ # Create object files so we can link them into the main binary and into tests without building twice. add_library(dethrace_obj OBJECT) -option(DETHRACE_FIX_BUGS "Fix Dethrace bugs" ON) - target_include_directories(dethrace_obj PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} @@ -35,7 +33,7 @@ else() -Wno-format-overflow ) endif() -if(BRENDER_FIX_BUGS) +if(DETHRACE_FIX_BUGS) target_compile_definitions(dethrace_obj PRIVATE DETHRACE_FIX_BUGS) endif() diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index db1f6a4a..ef4c550d 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -1276,7 +1276,64 @@ void TestAutoSpecialVolume(tCollision_info* pCar) { int i; LOG_TRACE("(%p)", pCar); - STUB_ONCE(); + mat = &pCar->car_master_actor->t.t.mat; + highest_p = 0.f; + for (i = 0; i < 3; i++) { + highest_p += BrVector3Dot((br_vector3*)mat->m[i], &pCar->water_normal) * pCar->bounds[0].min.v[i]; + } + highest_p += BrVector3Dot((br_vector3*)mat->m[3], &pCar->water_normal) / WORLD_SCALE; + lowest_p = highest_p; + for (i = 0; i < 3; i++) { + val = (pCar->bounds[0].max.v[i] - pCar->bounds[0].min.v[i]) * BrVector3Dot((br_vector3*)mat->m[i], &pCar->water_normal); + if (val >= 0.f) { + highest_p += val; + } else { + lowest_p += val; + } + } + + if (pCar->water_d > lowest_p) { + if (pCar->water_d >= highest_p) { + pCar->water_depth_factor = 1.f; + } else { + pCar->water_depth_factor = (pCar->water_d - lowest_p) / (highest_p - lowest_p); + } + if (pCar->auto_special_volume == NULL) { + vol = GetDefaultSpecialVolumeForWater(); + if (vol == NULL) { + pCar->water_depth_factor = 1.f; + pCar->auto_special_volume = NULL; + } else { + BrVector3Scale(&tv, &pCar->bounds[0].min, WORLD_SCALE); + BrMatrix34ApplyP(&lp, &tv, mat); + BrVector3InvScale(&lp, &lp, WORLD_SCALE); + BrVector3Copy(&hp, &lp); + for (i = 0; i < 3; i++) { + val = pCar->bounds[0].max.v[i] - pCar->bounds[0].min.v[i]; + BrVector3Scale(&tv, (br_vector3*)mat->m[i], val); + if (BrVector3Dot(&pCar->water_normal, &tv) > 0.f) { + BrVector3Accumulate(&hp, &tv); + } else { + BrVector3Accumulate(&lp, &tv); + } + } + BrVector3Sub(&dir, &hp, &lp); + DisablePlingMaterials(); + FindFloorInBoxBU(&lp, &dir, &tv, &d, pCar); + EnablePlingMaterials(); + FindFloorInBoxBU(&pos, &dir, &tv, &d2, pCar); + if (d2 <= d) { + pCar->water_depth_factor = 1.f; + pCar->auto_special_volume = NULL; + } else { + pCar->auto_special_volume = vol; + } + } + } + } else { + pCar->auto_special_volume = NULL; + pCar->water_depth_factor = 1.f; + } } // IDA: void __usercall MoveAndCollideCar(tCar_spec *car@, br_scalar dt) @@ -3765,222 +3822,113 @@ int AddEdgeCollPoints(br_vector3* p1, br_vector3* p2, br_bounds* pB, br_matrix34 float scale; plane1 = LineBoxColl(p1, p2, pB, &hp1); - if (!plane1) { + if (plane1 == 0) { return 0; } if (n + 2 > pMax_pnts) { return 0; } plane2 = LineBoxColl(p2, p1, pB, &hp2); - if (!plane2) { + if (plane2 == 0) { return 0; } - if (plane1 == 8 || plane2 == 8 || (plane1 ^ plane2) != 4) { - if (plane1 != 8 || plane2 == 8) { - if (plane2 != 8 || plane1 == 8) { - if (plane1 == 8 || plane2 == 8) { - if (plane1 == 8 && plane2 == 8) { - BrMatrix34ApplyP(&op1, p1, pMold); - plane3 = LineBoxColl(&op1, p1, pB, &pPoint_list[n]); - GetPlaneNormal(&pNorm_list[n], plane3); - d = n + (plane3 != 8); - BrMatrix34ApplyP(&op1, p2, pMold); - plane3 = LineBoxColl(&op1, p2, pB, &pPoint_list[d]); - GetPlaneNormal(&pNorm_list[d], plane3); - return (n != d) + (plane3 != 8); - } else { - return 0; - } - } else { - op1.v[0] = hp2.v[0] + hp1.v[0]; - op1.v[1] = hp2.v[1] + hp1.v[1]; - op1.v[2] = hp2.v[2] + hp1.v[2]; - op1.v[0] = op1.v[0] * 0.5; - op1.v[1] = op1.v[1] * 0.5; - op1.v[2] = op1.v[2] * 0.5; - BrMatrix34ApplyP(&op2, &op1, pMold); - plane3 = LineBoxColl(&op2, &op1, pB, &hp3); - if (plane3 != 8 && plane3) { - if (plane1 == plane3 || plane2 == plane3) { - GetBoundsEdge( - &pPoint_list[n], - &edge, - pB, - plane1, - plane2, - &op2, - &hp1, - &hp2, - c->collision_flag); - op1.v[0] = hp1.v[0] - hp2.v[0]; - op1.v[1] = hp1.v[1] - hp2.v[1]; - op1.v[2] = hp1.v[2] - hp2.v[2]; - op2.v[0] = edge.v[1] * op1.v[2] - op1.v[1] * edge.v[2]; - op2.v[1] = edge.v[2] * op1.v[0] - op1.v[2] * edge.v[0]; - op2.v[2] = op1.v[1] * edge.v[0] - edge.v[1] * op1.v[0]; - scale = sqrt(op2.v[1] * op2.v[1] + op2.v[2] * op2.v[2] + op2.v[0] * op2.v[0]); - if (scale <= 2.3841858e-7) { - pNorm_list[n].v[0] = 1.0; - pNorm_list[n].v[1] = 0.0; - pNorm_list[n].v[2] = 0.0; - } else { - scale = 1.0 / scale; - pNorm_list[n].v[0] = op2.v[0] * scale; - pNorm_list[n].v[1] = op2.v[1] * scale; - pNorm_list[n].v[2] = op2.v[2] * scale; - } - op1.v[0] = pB->max.v[0] + pB->min.v[0]; - op1.v[1] = pB->min.v[1] + pB->max.v[1]; - op1.v[2] = pB->max.v[2] + pB->min.v[2]; - op1.v[0] = op1.v[0] * 0.5; - op1.v[1] = op1.v[1] * 0.5; - op1.v[2] = op1.v[2] * 0.5; - op1.v[0] = pPoint_list[n].v[0] - op1.v[0]; - op1.v[1] = pPoint_list[n].v[1] - op1.v[1]; - op1.v[2] = pPoint_list[n].v[2] - op1.v[2]; - if (pNorm_list[n].v[1] * op1.v[1] + pNorm_list[n].v[2] * op1.v[2] + pNorm_list[n].v[0] * op1.v[0] > 0.0) { - pNorm_list[n].v[0] = -pNorm_list[n].v[0]; - pNorm_list[n].v[1] = -pNorm_list[n].v[1]; - pNorm_list[n].v[2] = -pNorm_list[n].v[2]; - } - op1 = pNorm_list[n]; - BrMatrix34ApplyV(&pNorm_list[n], &op1, pMold); - return 1; - } else { - GetBoundsEdge( - &pPoint_list[n], - &edge, - pB, - plane1, - plane3, - &hp3, - &hp1, - &hp2, - c->collision_flag); - GetBoundsEdge( - &pPoint_list[n + 1], - &edge, - pB, - plane2, - plane3, - &hp3, - &hp1, - &hp2, - c->collision_flag); - GetPlaneNormal(&pNorm_list[n], plane3); - pNorm_list[n + 1] = pNorm_list[n]; - return 2; - } - } else { - return 0; - } - } - } else { - BrMatrix34ApplyP(&b, p2, pMold); - plane3 = LineBoxColl(&b, p2, pB, &hp3); - if (plane3 == 8) { - return 0; - } else { - pPoint_list[n] = hp3; - GetPlaneNormal(&pNorm_list[n], plane1); - if (plane1 == plane3 || (plane3 ^ plane1) == 4) { - return 1; - } else { - GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane1, plane3, p2, &hp1, &hp3, c->collision_flag); - op1.v[0] = p1->v[0] - p2->v[0]; - op1.v[1] = p1->v[1] - p2->v[1]; - op1.v[2] = p1->v[2] - p2->v[2]; - pNorm_list[n + 1].v[0] = edge.v[1] * op1.v[2] - op1.v[1] * edge.v[2]; - pNorm_list[n + 1].v[1] = edge.v[2] * op1.v[0] - op1.v[2] * edge.v[0]; - pNorm_list[n + 1].v[2] = op1.v[1] * edge.v[0] - edge.v[1] * op1.v[0]; - scale = sqrt( - pNorm_list[n + 1].v[0] * pNorm_list[n + 1].v[0] - + pNorm_list[n + 1].v[1] * pNorm_list[n + 1].v[1] - + pNorm_list[n + 1].v[2] * pNorm_list[n + 1].v[2]); - if (scale <= 2.3841858e-7) { - pNorm_list[n + 1].v[0] = 1.0; - pNorm_list[n + 1].v[1] = 0.0; - pNorm_list[n + 1].v[2] = 0.0; - } else { - scale = 1.0 / scale; - pNorm_list[n + 1].v[0] = pNorm_list[n + 1].v[0] * scale; - pNorm_list[n + 1].v[1] = pNorm_list[n + 1].v[1] * scale; - pNorm_list[n + 1].v[2] = pNorm_list[n + 1].v[2] * scale; - } - d = (plane1 - 1) & 3; - if ((pNorm_list[n + 1].v[d] < 0.0) == (plane1 & 4) >> 2) { - pNorm_list[n + 1].v[0] = -pNorm_list[n + 1].v[0]; - pNorm_list[n + 1].v[1] = -pNorm_list[n + 1].v[1]; - pNorm_list[n + 1].v[2] = -pNorm_list[n + 1].v[2]; - } - op1 = pNorm_list[n + 1]; - BrMatrix34ApplyV(&pNorm_list[n + 1], &op1, pMold); - return 2; - } - } - } - } else { - BrMatrix34ApplyP(&a, p1, pMold); - plane3 = LineBoxColl(&a, p1, pB, &hp3); - if (plane3 == 8) { - return 0; - } else { - pPoint_list[n] = hp3; - GetPlaneNormal(&pNorm_list[n], plane2); - if (plane2 == plane3 || (plane3 ^ plane2) == 4) { - return 1; - } else { - GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane2, plane3, p1, &hp2, &hp3, c->collision_flag); - op1.v[0] = p1->v[0] - p2->v[0]; - op1.v[1] = p1->v[1] - p2->v[1]; - op1.v[2] = p1->v[2] - p2->v[2]; - pNorm_list[n + 1].v[0] = edge.v[1] * op1.v[2] - op1.v[1] * edge.v[2]; - pNorm_list[n + 1].v[1] = edge.v[2] * op1.v[0] - op1.v[2] * edge.v[0]; - pNorm_list[n + 1].v[2] = op1.v[1] * edge.v[0] - edge.v[1] * op1.v[0]; - scale = sqrt( - pNorm_list[n + 1].v[0] * pNorm_list[n + 1].v[0] - + pNorm_list[n + 1].v[1] * pNorm_list[n + 1].v[1] - + pNorm_list[n + 1].v[2] * pNorm_list[n + 1].v[2]); - if (scale <= 2.3841858e-7) { - pNorm_list[n + 1].v[0] = 1.0; - pNorm_list[n + 1].v[1] = 0.0; - pNorm_list[n + 1].v[2] = 0.0; - } else { - scale = 1.0 / scale; - pNorm_list[n + 1].v[0] = pNorm_list[n + 1].v[0] * scale; - pNorm_list[n + 1].v[1] = pNorm_list[n + 1].v[1] * scale; - pNorm_list[n + 1].v[2] = pNorm_list[n + 1].v[2] * scale; - } - d = (plane2 - 1) & 3; - if ((pNorm_list[n + 1].v[d] < 0.0) == (plane2 & 4) >> 2) { - pNorm_list[n + 1].v[0] = -pNorm_list[n + 1].v[0]; - pNorm_list[n + 1].v[1] = -pNorm_list[n + 1].v[1]; - pNorm_list[n + 1].v[2] = -pNorm_list[n + 1].v[2]; - } - op1 = pNorm_list[n + 1]; - BrMatrix34ApplyV(&pNorm_list[n + 1], &op1, pMold); - return 2; - } - } - } - } else { - op1.v[0] = hp2.v[0] + hp1.v[0]; - op1.v[1] = hp2.v[1] + hp1.v[1]; - op1.v[2] = hp2.v[2] + hp1.v[2]; - op1.v[0] = op1.v[0] * 0.5; - op1.v[1] = op1.v[1] * 0.5; - op1.v[2] = op1.v[2] * 0.5; + if (plane1 != 8 && plane2 != 8 && (plane1 ^ plane2) == 4) { + BrVector3Add(&op1, &hp2, &hp1); + BrVector3Scale(&op1, &op1, .5f); BrMatrix34ApplyP(&op2, &op1, pMold); plane3 = LineBoxColl(&op2, &op1, pB, &hp3); if (plane3 == 8) { return 0; + } + GetBoundsEdge(&pPoint_list[n], &edge, pB, plane1, plane3, &op2, &hp1, &hp2, c->collision_flag); + GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane2, plane3, &op2, &hp1, &hp2, c->collision_flag); + GetPlaneNormal(&pNorm_list[n], plane3); + BrVector3Copy(&pNorm_list[n + 1], &pNorm_list[n]); + return 2; + } else if (plane1 == 8 && plane2 != 8) { + BrMatrix34ApplyP(&a, p1, pMold); + plane3 = LineBoxColl(&a, p1, pB, &hp3); + if (plane3 == 8) { + return 0; + } + BrVector3Copy(&pPoint_list[n], &hp3); + GetPlaneNormal(&pNorm_list[n], plane2); + if (plane2 == plane3 || (plane3 ^ plane2) == 4) { + return 1; + } + GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane2, plane3, p1, &hp2, &hp3, c->collision_flag); + BrVector3Sub(&op1, p1, p2); + BrVector3Cross(&pNorm_list[n + 1], &edge, &op1); + BrVector3Normalise(&pNorm_list[n + 1], &pNorm_list[n + 1]); + d = (plane2 - 1) & 3; + if ((pNorm_list[n + 1].v[d] < 0.f) == (plane2 & 4) >> 2) { + BrVector3Negate(&pNorm_list[n + 1], &pNorm_list[n + 1]); + } + BrVector3Copy(&op1, &pNorm_list[n + 1]); + BrMatrix34ApplyV(&pNorm_list[n + 1], &op1, pMold); + return 2; + } else if (plane2 == 8 && plane1 != 8) { + BrMatrix34ApplyP(&b, p2, pMold); + plane3 = LineBoxColl(&b, p2, pB, &hp3); + if (plane3 == 8) { + return 0; + } + pPoint_list[n] = hp3; + GetPlaneNormal(&pNorm_list[n], plane1); + if (plane1 == plane3 || (plane3 ^ plane1) == 4) { + return 1; + } + GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane1, plane3, p2, &hp1, &hp3, c->collision_flag); + BrVector3Sub(&op1, p1, p2); + BrVector3Cross(&pNorm_list[n + 1], &edge, &op1); + BrVector3Normalise(&pNorm_list[n + 1], &pNorm_list[n + 1]); + d = (plane1 - 1) & 3; + if ((pNorm_list[n + 1].v[d] < 0.f) == (plane1 & 4) >> 2) { + BrVector3Negate(&pNorm_list[n + 1], &pNorm_list[n + 1]); + } + BrVector3Copy(&op1, &pNorm_list[n + 1]); + BrMatrix34ApplyV(&pNorm_list[n + 1], &op1, pMold); + return 2; + } else if (plane1 != 8 && plane2 != 8) { + BrVector3Add(&op1, &hp2, &hp1); + BrVector3Scale(&op1, &op1, .5f); + BrMatrix34ApplyP(&op2, &op1, pMold); + plane3 = LineBoxColl(&op2, &op1, pB, &hp3); + if (plane3 == 8 || plane3 == 0) { + return 0; + } + if (plane1 == plane3 || plane2 == plane3) { + GetBoundsEdge(&pPoint_list[n], &edge, pB, plane1, plane2, &op2, &hp1, &hp2, c->collision_flag); + BrVector3Sub(&op1, &hp1, &hp2); + BrVector3Cross(&op2, &edge, &op1); + BrVector3Normalise(&pNorm_list[n], &op2); + BrVector3Add(&op1, &pB->max, &pB->min); + BrVector3Scale(&op1, &op1, .5f); + BrVector3Sub(&op1, &pPoint_list[n], &op1); + if (BrVector3Dot(&pNorm_list[n], &op1) > 0.f) { + BrVector3Negate(&pNorm_list[n], &pNorm_list[n]); + } + BrVector3Copy(&op1, &pNorm_list[n]); + BrMatrix34ApplyV(&pNorm_list[n], &op1, pMold); + return 1; } else { - GetBoundsEdge(&pPoint_list[n], &edge, pB, plane1, plane3, &op2, &hp1, &hp2, c->collision_flag); - GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane2, plane3, &op2, &hp1, &hp2, c->collision_flag); + GetBoundsEdge(&pPoint_list[n], &edge, pB, plane1, plane3, &hp3, &hp1, &hp2, c->collision_flag); + GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane2, plane3, &hp3, &hp1, &hp2, c->collision_flag); GetPlaneNormal(&pNorm_list[n], plane3); - pNorm_list[n + 1] = pNorm_list[n]; + BrVector3Copy(&pNorm_list[n + 1], &pNorm_list[n]); return 2; } + } else if (plane1 == 8 && plane2 == 8) { + BrMatrix34ApplyP(&op1, p1, pMold); + plane3 = LineBoxColl(&op1, p1, pB, &pPoint_list[n]); + GetPlaneNormal(&pNorm_list[n], plane3); + d = n + (plane3 != 8); + BrMatrix34ApplyP(&op1, p2, pMold); + plane3 = LineBoxColl(&op1, p2, pB, &pPoint_list[d]); + GetPlaneNormal(&pNorm_list[d], plane3); + return (n != d) + (plane3 != 8); + } else { + return 0; } } @@ -3990,9 +3938,7 @@ void GetPlaneNormal(br_vector3* n, int p) { LOG_TRACE("(%p, %d)", n, p); d = (p - 1) & 3; - n->v[0] = 0.0; - n->v[1] = 0.0; - n->v[2] = 0.0; + BrVector3Set(n, 0.f, 0.f, 0.f); if ((p & 4) != 0) { n->v[d] = 1.0; } else { @@ -4012,15 +3958,9 @@ int GetBoundsEdge(br_vector3* pos, br_vector3* edge, br_bounds* pB, int plane1, d1 = (plane1 - 1) & 3; d2 = (plane2 - 1) & 3; - n.v[0] = b->v[0] - a->v[0]; - n.v[1] = b->v[1] - a->v[1]; - n.v[2] = b->v[2] - a->v[2]; - p.v[0] = c->v[0] - a->v[0]; - p.v[1] = c->v[1] - a->v[1]; - p.v[2] = c->v[2] - a->v[2]; - q.v[0] = p.v[2] * n.v[1] - p.v[1] * n.v[2]; - q.v[1] = n.v[2] * p.v[0] - p.v[2] * n.v[0]; - q.v[2] = p.v[1] * n.v[0] - n.v[1] * p.v[0]; + BrVector3Sub(&n, b, a); + BrVector3Sub(&p, c, a); + BrVector3Cross(&q, &n, &p); if ((plane1 & 4) != 0) { pos->v[d1] = pB->min.v[d1]; } else { @@ -4032,11 +3972,11 @@ int GetBoundsEdge(br_vector3* pos, br_vector3* edge, br_bounds* pB, int plane1, pos->v[d2] = pB->max.v[d2]; } d3 = 3 - d1 - d2; - edge->v[d1] = 0.0; - edge->v[d2] = 0.0; - edge->v[d3] = 1.0; + edge->v[d1] = 0.f; + edge->v[d2] = 0.f; + edge->v[d3] = 1.f; if ((flag & 1) != 0) { - pos->v[d3] = (c->v[d3] + b->v[d3]) / 2.0; + pos->v[d3] = (c->v[d3] + b->v[d3]) / 2.f; } else { pos->v[d3] = a->v[d3] - ((pos->v[d2] - a->v[d2]) * q.v[d2] + (pos->v[d1] - a->v[d1]) * q.v[d1]) / q.v[d3]; } diff --git a/src/DETHRACE/common/cutscene.c b/src/DETHRACE/common/cutscene.c index e98e33e9..2d41a9dc 100644 --- a/src/DETHRACE/common/cutscene.c +++ b/src/DETHRACE/common/cutscene.c @@ -234,7 +234,11 @@ void DoFullVersionPowerpoint() { FadePaletteDown(); DRSetPalette(gRender_palette); - ShowCutScene(9, 0, 8503, gCut_delay_4); + if (harness_game_info.mode == eGame_splatpack_demo) { + PlaySmackerFile("DEMOEND.SMK"); + } else { + ShowCutScene(9, 0, 8503, gCut_delay_4); + } FadePaletteDown(); gLast_demo_end_anim = PDGetTotalTime(); diff --git a/src/DETHRACE/common/init.c b/src/DETHRACE/common/init.c index 9043b6ef..4f4b54bc 100644 --- a/src/DETHRACE/common/init.c +++ b/src/DETHRACE/common/init.c @@ -424,7 +424,7 @@ void InitGame(int pStart_race) { gNo_races_yet = 1; NetPlayerStatusChanged(ePlayer_status_loading); gProgram_state.current_race_index = pStart_race; - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { gProgram_state.current_car.power_up_levels[0] = gDemo_armour; gProgram_state.current_car.power_up_levels[1] = gDemo_power; gProgram_state.current_car.power_up_levels[2] = gDemo_offensive; diff --git a/src/DETHRACE/common/loading.c b/src/DETHRACE/common/loading.c index 14a6864f..9391f05f 100644 --- a/src/DETHRACE/common/loading.c +++ b/src/DETHRACE/common/loading.c @@ -1687,7 +1687,7 @@ void MungeWindscreen(br_model* pModel) { void SetModelFlags(br_model* pModel, int pOwner) { LOG_TRACE("(%p, %d)", pModel, pOwner); - if (pModel && pModel->nfaces) { + if (pModel != NULL&& pModel->nfaces != 0) { #if defined(DETHRACE_FIX_BUGS) /* Show Squad Car in the wreck gallery. */ if (gAusterity_mode) { #else @@ -1795,7 +1795,12 @@ void LoadCar(char* pCar_name, tDriver pDriver, tCar_spec* pCar_spec, int pOwner, FatalError(kFatalError_FileCorrupt_S, pCar_name); } if (*pDriver_name != '\0') { +#if defined(DETHRACE_FIX_BUGS) + // Make sure to not read and write out of bounds. + memcpy(pCar_spec->driver_name, pDriver_name, MIN(sizeof(pCar_spec->driver_name), strlen(pDriver_name))); +#else memcpy(pCar_spec->driver_name, pDriver_name, sizeof(pCar_spec->driver_name)); +#endif pCar_spec->driver_name[sizeof(pCar_spec->driver_name) - 1] = '\0'; } else { strcpy(pCar_spec->driver_name, "X"); @@ -2430,11 +2435,11 @@ void LoadRaces(tRace_list_spec* pRace_list, int* pCount, int pRace_type_index) { *pCount = number_of_racers; fclose(f); j = 0; - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { j = 99; } for (i = 0; i < number_of_racers; i++) { - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { pRace_list[i].suggested_rank = gDemo_rank; pRace_list[i].rank_required = j; j -= 3; diff --git a/src/DETHRACE/common/loadsave.c b/src/DETHRACE/common/loadsave.c index c318b202..6fabd590 100644 --- a/src/DETHRACE/common/loadsave.c +++ b/src/DETHRACE/common/loadsave.c @@ -446,7 +446,7 @@ int DoLoadGame() { int result; LOG_TRACE("()"); - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { DoFeatureUnavailableInDemo(); return 0; } @@ -933,7 +933,7 @@ int SaveGameInterface(int pDefault_choice) { void DoSaveGame(int pSave_allowed) { LOG_TRACE("()"); - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { DoFeatureUnavailableInDemo(); return; } diff --git a/src/DETHRACE/common/main.c b/src/DETHRACE/common/main.c index 9193be78..55440ffb 100644 --- a/src/DETHRACE/common/main.c +++ b/src/DETHRACE/common/main.c @@ -23,7 +23,7 @@ void QuitGame() { LOG_TRACE("()"); - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { DoDemoGoodbye(); } diff --git a/src/DETHRACE/common/mainloop.c b/src/DETHRACE/common/mainloop.c index e74c225d..1fddbc49 100644 --- a/src/DETHRACE/common/mainloop.c +++ b/src/DETHRACE/common/mainloop.c @@ -438,7 +438,7 @@ void CheckTimer() { RaceCompleted(eRace_over_out_of_time); } - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { if (harness_game_config.demo_timeout != 0) { time_left = harness_game_config.demo_timeout - GetRaceTime(); time_in_seconds = (time_left + 500) / 1000; diff --git a/src/DETHRACE/common/mainmenu.c b/src/DETHRACE/common/mainmenu.c index 5715d06d..672f2a1c 100644 --- a/src/DETHRACE/common/mainmenu.c +++ b/src/DETHRACE/common/mainmenu.c @@ -31,7 +31,7 @@ char* gPixels_copy__mainmenu; // suffix added to avoid duplicate symbol int MainMenuDone1(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) { LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out); - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { if (pCurrent_mode == 0) { if (pCurrent_choice == 7) { PreloadBunchOfFlics(7); @@ -74,7 +74,7 @@ int MainMenuDone1(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEs int MainMenuDone2(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) { LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out); - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { if (pCurrent_mode == 0) { if (pCurrent_choice == 4) { PreloadBunchOfFlics(7); diff --git a/src/DETHRACE/common/newgame.c b/src/DETHRACE/common/newgame.c index 2e487cb1..e648380a 100644 --- a/src/DETHRACE/common/newgame.c +++ b/src/DETHRACE/common/newgame.c @@ -331,7 +331,7 @@ int DoOnePlayerStart() { memcpy(&gProgram_state, &saved_state, sizeof(tProgram_state)); return 0; } - if ((harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) && gProgram_state.frank_or_anniness != eFrankie) { + if ((harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) && gProgram_state.frank_or_anniness != eFrankie) { DoFeatureUnavailableInDemo(); memset(&gProgram_state, 0, sizeof(gProgram_state)); return 0; @@ -851,7 +851,7 @@ int DoMultiPlayerStart() { int car_index; LOG_TRACE("()"); - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { SuspendPendingFlic(); DoFeatureUnavailableInDemo(); return 0; diff --git a/src/DETHRACE/common/racestrt.c b/src/DETHRACE/common/racestrt.c index 9c4aa3e7..778064e7 100644 --- a/src/DETHRACE/common/racestrt.c +++ b/src/DETHRACE/common/racestrt.c @@ -1672,7 +1672,7 @@ tSO_result DoSelectRace(int* pSecond_time_around) { DisposeFlicPanel(0); if (result == 2) { - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { DoFeatureUnavailableInDemo(); } else { RunFlic(192); diff --git a/src/DETHRACE/common/racesumm.c b/src/DETHRACE/common/racesumm.c index 38268155..0fddf5f1 100644 --- a/src/DETHRACE/common/racesumm.c +++ b/src/DETHRACE/common/racesumm.c @@ -1214,7 +1214,7 @@ tSO_result DoEndRaceSummary(int* pFirst_summary_done, tRace_result pRace_result) tSO_result result; LOG_TRACE("(%p, %d)", pFirst_summary_done, pRace_result); - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { gRank_etc_munged = 1; DoEndRaceSummary2(); return eSO_continue; diff --git a/src/DETHRACE/common/spark.c b/src/DETHRACE/common/spark.c index d1737b6b..84e15150 100644 --- a/src/DETHRACE/common/spark.c +++ b/src/DETHRACE/common/spark.c @@ -24,7 +24,7 @@ int gShrapnel_flags; br_model* gShrapnel_model[2]; int gSmoke_flags; int gSmoke_num; -int gOffset; +int gOffset = 0; int gColumn_flags; int gNext_column; br_pixelmap* gBlack_smoke_shade_table; @@ -838,7 +838,7 @@ void SmokeLine(int l, int x, br_scalar zbuff, int r_squared, tU8* scr_ptr, tU16* if (gProgram_state.cockpit_on) { depth_ptr += gOffset; } - z = (1.0 - zbuff) * 32768.0f; + z = (1.f - zbuff) * 32768.0f; r_multiplier_int = r_multiplier * 65536.0f; shade_offset_int = shade_offset * 65536.0f; @@ -897,7 +897,7 @@ void SmokeCircle(br_vector3* o, br_scalar r, br_scalar extra_z, br_scalar streng return; } shade_ptr = (tU8*)pShade_table->pixels + pShade_table->row_bytes * (pShade_table->base_y + 1); - shade_offset = strength * 14.99; + shade_offset = strength * 14.99f; r_multiplier = shade_offset / (double)max_r_squared; z_multiplier = extra_z / (double)max_r_squared; max_x = pRender_screen->width - ox - 1; @@ -910,7 +910,7 @@ void SmokeCircle(br_vector3* o, br_scalar r, br_scalar extra_z, br_scalar streng osp = scr_ptr; odp = depth_ptr; if (pRender_screen->height > oy && oy + ry >= 0.0) { - r_squared = (r * r); + r_squared = r * r; inc = -r; y = 0; y_limit = ry; @@ -951,7 +951,7 @@ void SmokeCircle(br_vector3* o, br_scalar r, br_scalar extra_z, br_scalar streng if (y_limit <= y) { break; } - ++y; + y++; scr_ptr -= pRender_screen->row_bytes; depth_ptr -= pDepth_buffer->row_bytes / 2; for (r_squared += (2 * y - 1) * aspect_squared; max_r_squared < r_squared && inc < 0; r_squared += 2 * inc - 1) { @@ -961,19 +961,19 @@ void SmokeCircle(br_vector3* o, br_scalar r, br_scalar extra_z, br_scalar streng l -= 2; } gOffset += IRandomBetween(-1, 1); - if (gOffset > r / 5.0) { - gOffset = r / 5.0; + if (gOffset > r / 5.f) { + gOffset = r / 5.f; } - if (gOffset < -(r / 5.0)) { - gOffset = -(r / 5.0); + if (gOffset < -(r / 5.f)) { + gOffset = -(r / 5.f); } } } if (pAspect < 1.0) { - aspect_squared = 9.0; - ry = r / 3.0; + aspect_squared = 9.f; + ry = r / 3.f; } - if (oy > 0 && oy <= pRender_screen->height + ry - 2.0) { + if (oy > 0 && oy <= pRender_screen->height + ry - 2.f) { r_squared = (r * r); inc = -r; y = 0; @@ -989,7 +989,7 @@ void SmokeCircle(br_vector3* o, br_scalar r, br_scalar extra_z, br_scalar streng inc = -sqrtf(max_r_squared - r_squared); r_squared += inc * inc; } - if (oy - ry < 0.0) { + if (oy - ry < 0.f) { y_limit = oy; } l = -2 * inc; diff --git a/src/DETHRACE/common/structur.c b/src/DETHRACE/common/structur.c index 2189dd60..823413ce 100644 --- a/src/DETHRACE/common/structur.c +++ b/src/DETHRACE/common/structur.c @@ -359,7 +359,7 @@ void SelectOpponents(tRace_info* pRace_info) { int had_scum; LOG_TRACE("(%p)", pRace_info); - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { pRace_info->number_of_racers = OPPONENT_COUNT; for (i = 0; i < OPPONENT_COUNT; i++) { pRace_info->opponent_list[i].index = gDemo_opponents[i]; @@ -573,7 +573,7 @@ void DoGame() { DisposeOpponentsCars(&gCurrent_race); } DisposeTrack(); - if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo) { + if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { DoFullVersionPowerpoint(); } gProgram_state.loaded = 0; diff --git a/src/DETHRACE/common/utility.c b/src/DETHRACE/common/utility.c index e94b8086..20fd51bd 100644 --- a/src/DETHRACE/common/utility.c +++ b/src/DETHRACE/common/utility.c @@ -26,16 +26,16 @@ #define MIN_SERVICE_INTERVAL 200 // << -int gIn_check_quit; -tU32 gLost_time; +int gIn_check_quit = 0; +tU32 gLost_time = 0; #if BR_ENDIAN_BIG -tU32 gLong_key[4] = { 0x6C1B995F, 0xB9CD5F13, 0xCB04200E, 0x5E1CA10E }; -tU32 gOther_long_key[4] = { 0x67A8D626, 0xB6DD451B, 0x327E2213, 0x15C29437}; +tU32 gLong_key[4] = { 0x6c1b995f, 0xb9cd5f13, 0xcb04200e, 0x5e1ca10e }; +tU32 gOther_long_key[4] = { 0x67a8d626, 0xb6dd451b, 0x327e2213, 0x15c29437}; #else -tU32 gLong_key[4] = { 0x5F991B6C, 0x135FCDB9, 0x0E2004CB, 0x0EA11C5E }; -tU32 gOther_long_key[4] = { 0x26D6A867, 0x1B45DDB6, 0x13227E32, 0x3794C215 }; +tU32 gLong_key[4] = { 0x5f991b6c, 0x135fcdb9, 0x0e2004cb, 0x0ea11c5e }; +tU32 gOther_long_key[4] = { 0x26d6a867, 0x1b45ddb6, 0x13227e32, 0x3794c215 }; #endif -int gEncryption_method; +int gEncryption_method = 0; char* gMisc_strings[250]; br_pixelmap* g16bit_palette; br_pixelmap* gSource_for_16bit_palette; @@ -120,13 +120,11 @@ void EncodeLine(char* pS) { len = strlen(pS); key = (char*)gLong_key; - if (!gEncryption_method) { - strcpy(the_path, gApplication_path); - strcat(the_path, gDir_separator); - strcat(the_path, "GENERAL.TXT"); + if (gEncryption_method == 0) { + PathCat(the_path, gApplication_path, "GENERAL.TXT"); test = fopen(the_path, "rt"); - if (test) { + if (test != NULL) { fgets(s, 256, test); if (s[0] != '@') { gEncryption_method = 2; @@ -144,45 +142,53 @@ void EncodeLine(char* pS) { } } while (len > 0 && (pS[len - 1] == '\r' || pS[len - 1] == '\n')) { - --len; - pS[len] = 0; + len--; + pS[len] = '\0'; } seed = len % 16; + for (i = 0; i < len; i++) { c = pS[i]; +#if defined(DETHRACE_FIX_BUGS) + // When loading game data, Carmageddon does not switch the XOR cypher when the comments start. if (i >= 2) { if (pS[i - 1] == '/' && pS[i - 2] == '/') { key = (char*)gOther_long_key; } } +#endif if (gEncryption_method == 1) { if (c == '\t') { - c = 0x80; + c = 0x9f; } + c -= 0x20; - if (!(c & 0x80)) { - c = (c ^ key[seed]) & 0x7f; - c += 0x20; - } + c ^= key[seed]; + c &= 0x7f; + c += 0x20; + seed += 7; - seed = seed % 16; + seed %= 16; - if (c == 0x80) { + if (c == 0x9f) { c = '\t'; } } else { if (c == '\t') { - c = 0x9f; + c = 0x80; } + c -= 0x20; - c = (c ^ key[seed]) & 0x7f; + if ((c & 0x80) == 0) { + c ^= key[seed] & 0x7f; + } c += 0x20; seed += 7; - seed = seed % 16; + seed %= 16; - if (c == 0x9f) { + if (c == 0x80) { c = '\t'; } } @@ -343,7 +349,7 @@ float tandeg(float pAngle) { LOG_TRACE("(%f)", pAngle); pAngle = DEG_TO_RAD(pAngle); - return sin(pAngle) / cos(pAngle); + return sinf(pAngle) / cosf(pAngle); } // IDA: tU32 __usercall GetFileLength@(FILE *pF@) @@ -368,7 +374,7 @@ br_pixelmap* DRPixelmapAllocate(br_uint_8 pType, br_uint_16 pW, br_uint_16 pH, v br_pixelmap* the_map; the_map = BrPixelmapAllocate(pType, pW, pH, pPixels, pFlags); - if (the_map) { + if (the_map != NULL) { the_map->origin_y = 0; the_map->origin_x = 0; } @@ -581,14 +587,12 @@ br_uint_32 DRActorEnumRecurseWithTrans(br_actor* pActor, br_matrix34* pMatrix, b int sign(int pNumber) { LOG_TRACE("(%d)", pNumber); - if (pNumber < 1) { - if (pNumber < 0) { - return -1; - } else { - return 0; - } - } else { + if (pNumber > 0) { return 1; + } else if (pNumber < 0) { + return -1; + } else { + return 0; } } @@ -1157,8 +1161,8 @@ void DecodeLine2(char* pS) { len = strlen(pS); key = (char*)gLong_key; while (len > 0 && (pS[len - 1] == '\r' || pS[len - 1] == '\n')) { - --len; - pS[len] = 0; + len--; + pS[len] = '\0'; } seed = len % 16; for (i = 0; i < len; i++) { @@ -1170,31 +1174,34 @@ void DecodeLine2(char* pS) { } if (gEncryption_method == 1) { if (c == '\t') { - c = 0x80; + c = 0x9f; } + c -= 0x20; - if (!(c & 0x80)) { - c = (c ^ key[seed]) & 0x7f; - c += 0x20; - } + c ^= key[seed]; + c &= 0x7f; + c += 0x20; + seed += 7; - seed = seed % 16; + seed %= 16; - if (c == 0x80) { + if (c == 0x9f) { c = '\t'; } } else { if (c == '\t') { - c = 0x9f; + c = 0x80; } c -= 0x20; - c = (c ^ key[seed]) & 0x7f; + if ((c & 0x80) == 0) { + c ^= key[seed] & 0x7f; + } c += 0x20; seed += 7; - seed = seed % 16; + seed %= 16; - if (c == 0x9f) { + if (c == 0x80) { c = '\t'; } } @@ -1214,37 +1221,39 @@ void EncodeLine2(char* pS) { len = strlen(pS); count = 0; key = (char*)gLong_key; - while (len > 0 && (pS[len - 1] == 13 || pS[len - 1] == 10)) { - --len; - pS[len] = 0; + while (len > 0 && (pS[len - 1] == '\r' || pS[len - 1] == '\n')) { + len--; + pS[len] = '\0'; } seed = len % 16; - for (i = 0; i < len; ++pS) { - if (count == 2) + for (i = 0; i < len; i++) { + if (count == 2) { key = (char*)gOther_long_key; - if (*pS == '/') { - ++count; + } + if (pS[i] == '/') { + count++; } else { count = 0; } - if (*pS == '\t') { - *pS = 0x80; + if (pS[i] == '\t') { + pS[i] = 0x80; } - c = *pS - 0x20; - if (!(c & 0x80)) { - c = c ^ (key[seed] & 0x7F); - c += 0x20; + + c = pS[i] - 0x20; + if ((c & 0x80) == 0) { + c ^= key[seed] & 0x7f; } + c += 0x20; + seed += 7; - seed = seed % 16; + seed %= 16; if (c == 0x80) { c = '\t'; } - *pS = c; - ++i; + pS[i] = c; } } @@ -1264,11 +1273,11 @@ void EncodeFile(char* pThe_path) { len = strlen(pThe_path); strcpy(new_file, pThe_path); - strcat(new_file, "ENC"); + strcpy(&new_file[len - 3], "ENC"); f = fopen(pThe_path, "rt"); if (f == NULL) { - FatalError(kFatalError_Open_S, new_file); + FatalError(kFatalError_Open_S, pThe_path); } ch = fgetc(f); @@ -1287,37 +1296,44 @@ void EncodeFile(char* pThe_path) { result = &line[1]; while (!feof(f)) { - fgets(result, 256, f); + s = fgets(result, 256, f); + + if (s == NULL) { + continue; + } - if (ch == '@') { + if (result[0] == '@') { decode = 1; } else { decode = 0; - s = &result[1]; - while (line[0] == ' ' || line[0] == '\t') { - memmove(result, s, strlen(result)); + // Strip leading whitespace + while (result[0] == ' ' || result[0] == '\t') { + memmove(result, &result[1], strlen(result)); } } - if (decode == 0) { - EncodeLine2(result + decode); + if (decode) { + DecodeLine2(&result[decode]); } else { - DecodeLine2(result + decode); + EncodeLine2(&result[decode]); } line[0] = '@'; fputs(&line[decode * 2], d); count = -1; - ch = fgetc(f); - while (ch == '\r' || ch == '\n') { + while (1) { count++; + ch = fgetc(f); + if (ch != '\r' && ch != '\n') { + break; + } } - if (count >= 2) { - fputc(0x0d, d); - fputc(0x0a, d); + if (count > 2) { + fputc('\r', d); + fputc('\n', d); } - fputc(0x0d, d); - fputc(0x0a, d); + fputc('\r', d); + fputc('\n', d); if (ch != -1) { ungetc(ch, f); diff --git a/src/DETHRACE/common/world.c b/src/DETHRACE/common/world.c index bf9ebcd8..96330835 100644 --- a/src/DETHRACE/common/world.c +++ b/src/DETHRACE/common/world.c @@ -4098,7 +4098,15 @@ void StopGroovidelic(br_actor* pActor) { tGroovidelic_spec* the_groove; LOG_TRACE("(%p)", pActor); - STUB(); + for (i = 0; i < gGroovidelics_array_size; i++) { + the_groove = &gGroovidelics_array[i]; + if (the_groove->actor == pActor) { + if (the_groove->path_interrupt_status == eInterrupt_none && the_groove->object_interrupt_status == eInterrupt_none) { + GrooveThisDelic(the_groove, gPrevious_groove_times[1], 1); + } + return; + } + } } // IDA: void __usercall SetGrooveInterrupt(int pGroove_index@, br_matrix34 *pMatrix@, int pPath_interrupt@, int pObject_interrupt@, float pPath_resumption, float pObject_resumption) diff --git a/src/harness/CMakeLists.txt b/src/harness/CMakeLists.txt index 24d4db8e..eb3229bb 100644 --- a/src/harness/CMakeLists.txt +++ b/src/harness/CMakeLists.txt @@ -16,6 +16,10 @@ target_include_directories(harness include ) +if(DETHRACE_FIX_BUGS) + target_compile_definitions(harness PRIVATE DETHRACE_FIX_BUGS) +endif() + target_link_libraries(harness PRIVATE brender compile_with_werror) if(WIN32) @@ -82,6 +86,8 @@ if (IO_PLATFORM STREQUAL "SDL_OpenGL") resources/3d_vert.glsl.h resources/3d_frag.glsl.h ) + target_include_directories(harness PRIVATE "${dethrace_SOURCE_DIR}/src/DETHRACE/common") + target_include_directories(harness PRIVATE "${dethrace_SOURCE_DIR}/src/S3/include") target_link_libraries(harness PRIVATE SDL2::SDL2 glad) endif() diff --git a/src/harness/harness.c b/src/harness/harness.c index 27683cd5..11bbc9bd 100644 --- a/src/harness/harness.c +++ b/src/harness/harness.c @@ -93,13 +93,13 @@ void Harness_DetectGameMode() { printf("Game mode: Splat Pack\n"); } else if (access("DATA/RACES/TINSEL.TXT", F_OK) != -1) { // Only the the splat x-mas demo has the tinsel track - harness_game_info.defines.INTRO_SMK_FILE = ""; + harness_game_info.defines.INTRO_SMK_FILE = "MIX_INTR.SMK"; harness_game_info.defines.GERMAN_LOADSCRN = ""; - harness_game_info.mode = eGame_splatpack_demo; + harness_game_info.mode = eGame_splatpack_xmas_demo; printf("Game mode: Splat Pack X-mas demo\n"); } else { // Assume we're using the splatpack demo - harness_game_info.defines.INTRO_SMK_FILE = ""; + harness_game_info.defines.INTRO_SMK_FILE = "MIX_INTR.SMK"; harness_game_info.defines.GERMAN_LOADSCRN = ""; harness_game_info.mode = eGame_splatpack_demo; printf("Game mode: Splat Pack demo\n"); @@ -165,6 +165,7 @@ void Harness_DetectGameMode() { harness_game_info.defines.ascii_shift_table = demo_ascii_shift_table; break; case eGame_splatpack_demo: + case eGame_splatpack_xmas_demo: harness_game_info.defines.ascii_table = splatpack_xmasdemo_ascii_table; harness_game_info.defines.ascii_shift_table = splatpack_xmasdemo_ascii_shift_table; break; @@ -192,6 +193,8 @@ void Harness_Init(int* argc, char* argv[]) { harness_game_config.enable_diagnostics = 0; // no volume multiplier harness_game_config.volume_multiplier = 1.0f; + // start window in windowed mode + harness_game_config.start_full_screen = 0; // install signal handler by default harness_game_config.install_signalhandler = 1; @@ -278,6 +281,9 @@ int Harness_ProcessCommandLine(int* argc, char* argv[]) { harness_game_config.volume_multiplier = atof(s + 1); LOG_INFO("Volume multiplier set to %f", harness_game_config.volume_multiplier); handled = 1; + } else if (strcasecmp(argv[i], "--full-screen") == 0) { + harness_game_config.start_full_screen = 1; + handled = 1; } if (handled) { diff --git a/src/harness/include/harness/config.h b/src/harness/include/harness/config.h index a4179e52..1240e3aa 100644 --- a/src/harness/include/harness/config.h +++ b/src/harness/include/harness/config.h @@ -7,6 +7,7 @@ typedef enum tHarness_game_type { eGame_splatpack, eGame_carmageddon_demo, eGame_splatpack_demo, + eGame_splatpack_xmas_demo, } tHarness_game_type; typedef enum { @@ -37,6 +38,7 @@ typedef struct tHarness_game_config { unsigned demo_timeout; int enable_diagnostics; float volume_multiplier; + int start_full_screen; int install_signalhandler; } tHarness_game_config; diff --git a/src/harness/io_platforms/sdl_gl.c b/src/harness/io_platforms/sdl_gl.c index 39410ae1..eebefdc3 100644 --- a/src/harness/io_platforms/sdl_gl.c +++ b/src/harness/io_platforms/sdl_gl.c @@ -6,8 +6,14 @@ #include "../renderers/gl/gl_renderer.h" #include "../renderers/renderer.h" + +#include "harness/config.h" #include "harness/trace.h" +#include "globvars.h" +#include "grafdata.h" +#include "pd/sys.h" + #define ARRAY_LEN(array) (sizeof((array)) / sizeof((array)[0])) int scancode_map[123]; @@ -129,7 +135,6 @@ struct { float x; float y; } sdl_window_scale; -int is_full_screen = 0; tRenderer gl_renderer = { GLRenderer_Init, @@ -175,6 +180,10 @@ tRenderer* Window_Create(char* title, int width, int height, int pRender_width, sdl_window_scale.x = ((float)pRender_width) / width; sdl_window_scale.y = ((float)pRender_height) / height; + if (harness_game_config.start_full_screen) { + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); + } + SDL_ShowCursor(SDL_DISABLE); context = SDL_GL_CreateContext(window); @@ -218,8 +227,7 @@ void Window_PollEvents() { } } else if (event.key.type == SDL_KEYUP) { if (is_only_key_modifier(event.key.keysym.mod, KMOD_ALT)) { - is_full_screen = !is_full_screen; - SDL_SetWindowFullscreen(window, is_full_screen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + SDL_SetWindowFullscreen(window, (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP); } } } @@ -304,6 +312,15 @@ void Input_GetMousePosition(int* pX, int* pY) { *pY -= vp_y; *pX *= sdl_window_scale.x; *pY *= sdl_window_scale.y; + +#if defined(DETHRACE_FIX_BUGS) + // In hires mode (640x480), the menus are still rendered at (320x240), + // so prescale the cursor coordinates accordingly. + *pX *= gGraf_specs[gGraf_data_index].phys_width; + *pX /= gGraf_specs[gReal_graf_data_index].phys_width; + *pY *= gGraf_specs[gGraf_data_index].phys_height; + *pY /= gGraf_specs[gReal_graf_data_index].phys_height; +#endif } void Input_GetMouseButtons(int* pButton1, int* pButton2) { diff --git a/test/DETHRACE/test_utility.c b/test/DETHRACE/test_utility.c index 36c9642a..6bc35d0b 100644 --- a/test/DETHRACE/test_utility.c +++ b/test/DETHRACE/test_utility.c @@ -6,7 +6,7 @@ void test_utility_EncodeLinex() { char buf[50]; - gEncryption_method = 1; + gEncryption_method = 2; // first line of GENERAL.TXT, "@" prefix and line ending stripped char input[] = "\x29\x2a\x9c\x22\x61\x4d\x5e\x5f\x60\x34\x64\x57\x8d\x2b\x82\x7b\x33\x4c"; strcpy(buf, input); @@ -18,7 +18,7 @@ void test_utility_EncodeLinex() { void test_utility_DecodeLine2() { char buf[50]; - gEncryption_method = 1; + gEncryption_method = 2; // first line of GENERAL.TXT, "@" prefix and line ending stripped char input[] = "\x29\x2a\x9c\x22\x61\x4d\x5e\x5f\x60\x34\x64\x57\x8d\x2b\x82\x7b\x33\x4c"; strcpy(buf, input); diff --git a/tools/decode_datatxt.py b/tools/decode_datatxt.py index 6e597f6a..f81c83a7 100755 --- a/tools/decode_datatxt.py +++ b/tools/decode_datatxt.py @@ -13,43 +13,94 @@ ) +class Byte: + def __init__(self, v: int): + self.v = v & 0xff + + def __add__(self, v: int): + return Byte(self.v + v) + + def __iadd__(self, v: "Byte"): + self.v = (self.v + v) & 0xff + return self + + def __sub__(self, v: int): + return Byte(self.v - v) + + def __isub__(self, v: "Byte"): + self.v = (self.v - v) & 0xff + return self + + def __mod__(self, v: int): + return Byte(self.v % v) + + def __imod__(self, v: int): + self.v %= v + return self + + def __xor__(self, v: int): + return Byte(self.v ^ v) + + def __ixor__(self, v: int): + self.v = (self.v ^ v) & 0xff + return self + + def __and__(self, v: int): + return Byte(self.v & v) + + def __iand__(self, v: int): + self.v = (self.v & v) & 0xff + return self + + def __eq__(self, other): + if isinstance(other, Byte): + return self.v == other.v + elif isinstance(other, int): + return self.v == (other & 0xff) + raise ValueError(f"Object {other:r} of invalid type {type(other)}") + + def decode_line(line: bytes, method: int) -> str: line = line.rstrip(b"\r\n") key = LONG_KEY - seed = len(line) % 16 + seed = len(line) % len(LONG_KEY) dline = bytearray(len(line)) for i, c in enumerate(line): - if i >= 2: - if line[i - 1] == b'/' and line[i - 2] == b'/': - key = OTHER_LONG_KEY + b = Byte(c) + if dline[i - 2:i] == b'//': + key = OTHER_LONG_KEY if method == 1: - if c == ord(b'\t'): - c = 0x80 - c -= 0x20 - if not (c & 0x80): - c ^= key[seed] - c &= 0x7f - c += 0x20 + if b == ord(b'\t'): + b = Byte(0x9f) + + b -= 0x20 + b ^= key[seed] + b &= 0x7f + b += 0x20 seed += 7 - seed %= 16 - if c == 0x80: - c = ord(b'\t') + seed %= len(key) + + if b == 0x9f: + b = Byte(ord(b'\t')) else: - if c == ord(b'\t'): - c = 0x9f - c -= 0x20 - c ^= key[seed] - c &= 0x7f - c += 0x20 + if b == ord(b'\t'): + b = Byte(0x80) + + b -= 0x20 + if (b & 0x80) == 0: + b ^= key[seed] & 0x7f + b += 0x20 seed += 7 - seed %= 16 - if c == 0x9f: - c = ord(b'\t') - dline[i] = c + seed %= len(key) + + if b == 0x80: + b = Byte(ord(b'\t')) + dline[i] = b.v return dline.decode(errors="replace") + def main(): parser = argparse.ArgumentParser(allow_abbrev=False, description="Decode a Carmageddon encoded file") parser.add_argument("file", metavar="FILE", nargs="?", help="input file (default=stdin)")