diff --git a/src/DETHRACE/CMakeLists.txt b/src/DETHRACE/CMakeLists.txt index 4961e5e0..cc85d166 100644 --- a/src/DETHRACE/CMakeLists.txt +++ b/src/DETHRACE/CMakeLists.txt @@ -61,6 +61,8 @@ endif() target_sources(dethrace_obj PRIVATE common/skidmark.c + common/opponent.c + common/brucetrk.c common/brucetrk.h common/car.c @@ -127,7 +129,7 @@ target_sources(dethrace_obj PRIVATE common/oil.h common/oppocar.c common/oppocar.h - common/opponent.c + common/opponent.h common/oppoproc.c common/oppoproc.h @@ -190,14 +192,15 @@ endif() if(MSVC_42_FOR_RECCMP) add_executable(dethrace WIN32) set(CMAKE_C_FLAGS_DEBUG "/Od /Oi /Zi /MLd /G5") + + add_compile_definitions(_DEBUG) set_target_properties(dethrace PROPERTIES OUTPUT_NAME "CARM95") target_link_options(dethrace PRIVATE /INCREMENTAL:NO /subsystem:windows /ENTRY:mainCRTStartup) set_source_files_properties(common/skidmark.c PROPERTIES COMPILE_FLAGS "/FAs") # set_source_files_properties(common/brucetrk.c PROPERTIES COMPILE_FLAGS "/G5") - - # set_source_files_properties(common/car.c PROPERTIES COMPILE_FLAGS "/GB") + set_source_files_properties(common/opponent.c PROPERTIES COMPILE_FLAGS "/FAs /G5") reccmp_add_target(dethrace ID CARM95) reccmp_configure() else() diff --git a/src/DETHRACE/common/loading.c b/src/DETHRACE/common/loading.c index cfbef261..84a08781 100644 --- a/src/DETHRACE/common/loading.c +++ b/src/DETHRACE/common/loading.c @@ -1375,17 +1375,17 @@ void ReadNonCarMechanicsData(FILE* pF, tNon_car_spec* non_car) { c = &non_car->collision_info; c->driver = 0; c->index = GetAnInt(pF); - ReadVector3(pF, non_car->free_cmpos.v[0], non_car->free_cmpos.v[1], non_car->free_cmpos.v[2]); - ReadVector3(pF, non_car->attached_cmpos.v[0], non_car->attached_cmpos.v[1], non_car->attached_cmpos.v[2]); - ReadVector3(pF, c->bounds[1].min.v[0], c->bounds[1].min.v[1], c->bounds[1].min.v[2]); - ReadVector3(pF, c->bounds[1].max.v[0], c->bounds[1].max.v[1], c->bounds[1].max.v[2]); + ReadThreeFloats(pF, non_car->free_cmpos.v[0], non_car->free_cmpos.v[1], non_car->free_cmpos.v[2]); + ReadThreeFloats(pF, non_car->attached_cmpos.v[0], non_car->attached_cmpos.v[1], non_car->attached_cmpos.v[2]); + ReadThreeFloats(pF, c->bounds[1].min.v[0], c->bounds[1].min.v[1], c->bounds[1].min.v[2]); + ReadThreeFloats(pF, c->bounds[1].max.v[0], c->bounds[1].max.v[1], c->bounds[1].max.v[2]); c->extra_point_num = GetAnInt(pF); if (c->extra_point_num > 6) { sprintf(s, "%d", c->index); FatalError(kFatalError_TooManyExtraPointsForCar_S, s); } for (i = 0; c->extra_point_num > i; ++i) { - ReadVector3(pF, c->extra_points[i].v[0], c->extra_points[i].v[1], c->extra_points[i].v[2]); + ReadThreeFloats(pF, c->extra_points[i].v[0], c->extra_points[i].v[1], c->extra_points[i].v[2]); } ReadPairOfFloats(pF, non_car->free_mass, non_car->attached_mass); @@ -1423,14 +1423,14 @@ void ReadNonCarMechanicsData(FILE* pF, tNon_car_spec* non_car) { non_car->I_over_M.v[1] = ts1 / 12.0f; ts1 = BR_SQR2(het, len); non_car->I_over_M.v[0] = ts1 / 12.0f; - DRVector3Scale(&non_car->free_cmpos, &non_car->free_cmpos, WORLD_SCALE); - DRVector3Scale(&non_car->attached_cmpos, &non_car->attached_cmpos, WORLD_SCALE); - DRVector3Scale(&non_car->I_over_M, &non_car->I_over_M, 47.61000061035156f); - DRVector3Scale(&c->bounds[1].min, &c->bounds[1].min, WORLD_SCALE); - DRVector3Scale(&c->bounds[1].max, &c->bounds[1].max, WORLD_SCALE); + BrVector3Scale(&non_car->free_cmpos, &non_car->free_cmpos, WORLD_SCALE); + BrVector3Scale(&non_car->attached_cmpos, &non_car->attached_cmpos, WORLD_SCALE); + BrVector3Scale(&non_car->I_over_M, &non_car->I_over_M, 47.61000061035156f); + BrVector3Scale(&c->bounds[1].min, &c->bounds[1].min, WORLD_SCALE); + BrVector3Scale(&c->bounds[1].max, &c->bounds[1].max, WORLD_SCALE); for (i = 0; c->extra_point_num > i; ++i) { - DRVector3Scale(&c->extra_points[i], &c->extra_points[i], WORLD_SCALE); + BrVector3Scale(&c->extra_points[i], &c->extra_points[i], WORLD_SCALE); } memcpy(&c->max_bounds[0], &c->bounds[0], sizeof(c->max_bounds[0])); memcpy(&c->max_bounds[1], &c->bounds[1], sizeof(c->max_bounds[0])); diff --git a/src/DETHRACE/common/opponent.c b/src/DETHRACE/common/opponent.c index 13069eeb..78397a14 100644 --- a/src/DETHRACE/common/opponent.c +++ b/src/DETHRACE/common/opponent.c @@ -110,7 +110,11 @@ tU32 gNext_elastication; // GLOBAL: CARM95 0x00507150 tU32 gNext_write_during_elastication; + +// GLOBAL: CARM95 0x00507154 char* gCop_name = "Faceless Cop"; + +// GLOBAL: CARM95 0x00507158 char* gDrone_name = "Innocent Civilian"; // GLOBAL: CARM95 0x0050715c @@ -215,9 +219,10 @@ void PointActorAlongThisBloodyVector(br_actor* pThe_actor, br_vector3* pThe_vect br_transform trans; trans.type = BR_TRANSFORM_LOOK_UP; + BrVector3Copy(&trans.t.look_up.t, &pThe_actor->t.t.translate.t); BrVector3Copy(&trans.t.look_up.look, pThe_vector); BrVector3Set(&trans.t.look_up.up, 0.f, 1.f, 0.f); - BrVector3Copy(&trans.t.look_up.t, &pThe_actor->t.t.translate.t); + BrTransformToTransform(&pThe_actor->t, &trans); } @@ -242,7 +247,6 @@ void ProcessCurrentObjective(tOpponent_spec* pOpponent_spec, tProcess_objective_ ProcessLevitate(pOpponent_spec, pCommand); break; case eOOT_knackered_and_freewheeling: - // FIXME: is keys correct? memset(&pOpponent_spec->car_spec->keys, 0, sizeof(pOpponent_spec->car_spec->keys)); pOpponent_spec->car_spec->acc_force = 0.f; pOpponent_spec->car_spec->brake_force = 0.f; @@ -254,8 +258,6 @@ void ProcessCurrentObjective(tOpponent_spec* pOpponent_spec, tProcess_objective_ case eOOT_wait_for_some_hapless_sod: ProcessWaitForSomeHaplessSod(pOpponent_spec, pCommand); break; - case eOOT_rematerialise: - break; case eOOT_return_to_start: ProcessReturnToStart(pOpponent_spec, pCommand); break; @@ -342,9 +344,11 @@ tS16 FindNearestPathNode(br_vector3* pActor_coords, br_scalar* pDistance) { for (i = 0; i < gProgram_state.AI_vehicles.number_of_path_nodes; i++) { BrVector3Sub(&actor_to_node, &gProgram_state.AI_vehicles.path_nodes[i].p, pActor_coords); distance = BrVector3Length(&actor_to_node); - if (distance < *pDistance && (!gAlready_elasticating || gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1] != i)) { - *pDistance = distance; - nearest_node = i; + if (distance < *pDistance) { + if (!gAlready_elasticating || gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1] != i) { + *pDistance = distance; + nearest_node = i; + } } } return nearest_node; @@ -380,10 +384,10 @@ tS16 FindNearestGeneralSection(tCar_spec* pPursuee, br_vector3* pActor_coords, b br_vector3 zero_vector; #endif - nearest_section = -1; nearest_node_section_no = -1; - closest_distance_squared = BR_SCALAR_MAX; + nearest_section = -1; nearest_node_distance_squared = BR_SCALAR_MAX; + closest_distance_squared = BR_SCALAR_MAX; #if defined(DETHRACE_FIX_BUGS) BrVector3Set(&zero_vector, 0.f, 0.f, 0.f); nearest_node_v = &zero_vector; @@ -406,57 +410,57 @@ tS16 FindNearestGeneralSection(tCar_spec* pPursuee, br_vector3* pActor_coords, b if (!gAlready_elasticating || gMobile_section != section_no) { BrVector3Sub(&a, finish, start); BrVector3Sub(&p, pActor_coords, start); - the_distance_squared = Vector3DistanceSquared(&p, &a); - if (the_distance_squared < closest_distance_squared) { - closest_distance_squared = the_distance_squared; - nearest_section = section_no; + BrVector3Sub(&wank, &p, &a); + the_distance_squared = BrVector3LengthSquared(&wank); + if (the_distance_squared < nearest_node_distance_squared) { + nearest_node_distance_squared = the_distance_squared; + nearest_node_section_no = section_no; nearest_node_v = finish; } the_distance_squared = BrVector3LengthSquared(&p); - if (the_distance_squared < closest_distance_squared) { - closest_distance_squared = the_distance_squared; - nearest_section = section_no; + if (the_distance_squared < nearest_node_distance_squared) { + nearest_node_distance_squared = the_distance_squared; + nearest_node_section_no = section_no; nearest_node_v = start; } length_squared_a = BrVector3LengthSquared(&a); - if (length_squared_a >= 0.0001f) { - t = BrVector3Dot(&p, &a) / length_squared_a; - if (t >= 0 && t <= 1.f) { - p.v[0] -= t * a.v[0]; - p.v[1] -= t * a.v[1]; - p.v[2] -= t * a.v[2]; - the_distance_squared = BrVector3LengthSquared(&p); - if (the_distance_squared < nearest_node_distance_squared) { - BrVector3Scale(&intersect, &a, t); - BrVector3Add(pIntersect, start, &intersect); - BrVector3NormaliseQuick(pPath_direction, &a); - nearest_node_distance_squared = the_distance_squared; - nearest_node_section_no = section_no; - } + if (length_squared_a < 0.0001f) { + continue; + } + t = BrVector3Dot(&p, &a) / length_squared_a; + if (t >= 0 && t <= 1.f) { + BrVector3Scale(&intersect, &a, t); + BrVector3Sub(&wank, &p, &intersect); + the_distance_squared = BrVector3LengthSquared(&wank); + if (the_distance_squared < closest_distance_squared) { + closest_distance_squared = the_distance_squared; + nearest_section = section_no; + BrVector3Add(pIntersect, start, &intersect); + BrVector3NormaliseQuick(pPath_direction, &a); } } } } - if (nearest_node_distance_squared > closest_distance_squared) { - nearest_node_section_no = nearest_section; + if (closest_distance_squared > nearest_node_distance_squared) { + nearest_section = nearest_node_section_no; if (pPursuee != NULL) { - start = &pPursuee->my_trail.trail_nodes[nearest_section]; - finish = &pPursuee->my_trail.trail_nodes[nearest_section + 1]; + start = &pPursuee->my_trail.trail_nodes[nearest_node_section_no]; + finish = &pPursuee->my_trail.trail_nodes[nearest_node_section_no + 1]; } else { - start = &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[nearest_section].node_indices[0]].p; - finish = &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[nearest_section].node_indices[1]].p; + start = &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[nearest_node_section_no].node_indices[0]].p; + finish = &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[nearest_node_section_no].node_indices[1]].p; } - BrVector3Sub(&p, finish, start); - BrVector3NormaliseQuick(pPath_direction, &p); + BrVector3Sub(&a, finish, start); + BrVector3NormaliseQuick(pPath_direction, &a); BrVector3Copy(pIntersect, nearest_node_v); - *pDistance = sqrt(closest_distance_squared); - } else { *pDistance = sqrt(nearest_node_distance_squared); + } else { + *pDistance = sqrt(closest_distance_squared); } if (pPursuee != NULL) { - nearest_node_section_no += 15000; + nearest_section += 15000; } - return nearest_node_section_no; + return nearest_section; } // IDA: void __usercall DeadStopCar(tCar_spec *pCar_spec@) @@ -507,23 +511,25 @@ void NewObjective(tOpponent_spec* pOpponent_spec, tOpponent_objective_type pObje if (pObjective_type == eOOT_pursue_and_twat) { pOpponent_spec->time_for_this_objective_to_finish += 90000; } + va_start(marker, pObjective_type); switch (pObjective_type) { case eOOT_complete_race: gNum_of_opponents_completing_race++; break; - case eOOT_pursue_and_twat: - va_start(marker, pObjective_type); - pOpponent_spec->pursue_car_data.pursuee = va_arg(marker, tCar_spec*); - va_end(marker); - break; case eOOT_get_near_player: gNum_of_opponents_getting_near++; break; + case eOOT_pursue_and_twat: + pOpponent_spec->pursue_car_data.pursuee = va_arg(marker, tCar_spec*); + gNum_of_opponents_pursuing++; + break; + default: break; } dr_dprintf("%s: NewObjective() - type %d", pOpponent_spec->car_spec->driver_name, pObjective_type); ProcessCurrentObjective(pOpponent_spec, ePOC_start); + va_end(marker); } // IDA: void __usercall CalcRaceRoute(tOpponent_spec *pOpponent_spec@) @@ -565,8 +571,8 @@ void CalcRaceRoute(tOpponent_spec* pOpponent_spec) { race_section_count = 0; normal_section_ok_direction_count = 0; normal_section_wrong_direction_count = 0; - for (i = 0; i < gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections; i++) { - section_no = gProgram_state.AI_vehicles.path_nodes[node_no].sections[i]; + for (section_no_index = 0; section_no_index < gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections; section_no_index++) { + section_no = gProgram_state.AI_vehicles.path_nodes[node_no].sections[section_no_index]; if (pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].section_no != section_no) { if (gProgram_state.AI_vehicles.path_sections[section_no].type == 1 && gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0] == node_no) { pOpponent_spec->complete_race_data.found_race_section = 1; @@ -586,7 +592,7 @@ void CalcRaceRoute(tOpponent_spec* pOpponent_spec) { } else if (normal_section_ok_direction_count != 0) { AddToOpponentsProjectedRoute(pOpponent_spec, temp_section_array[IRandomBetween(0, normal_section_ok_direction_count - 1)], 1); } else if (normal_section_wrong_direction_count != 0) { - AddToOpponentsProjectedRoute(pOpponent_spec, temp_section_array[IRandomBetween(0, normal_section_wrong_direction_count - 1)], 1); + AddToOpponentsProjectedRoute(pOpponent_spec, temp_section_array[IRandomBetween(0, normal_section_wrong_direction_count - 1)], 0); } else if (pOpponent_spec->complete_race_data.found_race_section) { pOpponent_spec->complete_race_data.finished_calcing_race_route = 1; } else { @@ -609,17 +615,14 @@ void TopUpRandomRoute(tOpponent_spec* pOpponent_spec, int pSections_to_add) { if (!pSections_to_add) { PDEnterDebugger("TopUpRandomRoute() called with no seed (woof, bark, etc.)"); } - if (pSections_to_add >= 0) { - target = MIN(pSections_to_add + pOpponent_spec->nnext_sections, 10); - } else { + if (pSections_to_add < 0) { target = 10; + } else { + target = MIN(pSections_to_add + pOpponent_spec->nnext_sections, 10); } while (pOpponent_spec->nnext_sections < target) { node_no = gProgram_state.AI_vehicles.path_sections[pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].section_no].node_indices[pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].direction]; - if (gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections <= 1) { - section_no = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].section_no; - direction = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].direction == 0; - } else { + if (gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections > 1) { num_of_temp_sections = 0; for (i = 0; i < gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections; i++) { section_no = gProgram_state.AI_vehicles.path_nodes[node_no].sections[i]; @@ -631,16 +634,19 @@ void TopUpRandomRoute(tOpponent_spec* pOpponent_spec, int pSections_to_add) { } } - if (num_of_temp_sections == 0) { - section_no = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].section_no; - direction = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].direction == 0; - } else if (num_of_temp_sections == 1) { - section_no = temp_section_array[0]; - direction = gProgram_state.AI_vehicles.path_sections[temp_section_array[0]].node_indices[1] != node_no; - } else { + if (num_of_temp_sections > 1) { section_no = temp_section_array[IRandomBetween(0, num_of_temp_sections - 1)]; direction = gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1] != node_no; + } else if (num_of_temp_sections == 1) { + section_no = temp_section_array[0]; + direction = gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1] != node_no; + } else { + section_no = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].section_no; + direction = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].direction == 0; } + } else { + section_no = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].section_no; + direction = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].direction == 0; } AddToOpponentsProjectedRoute(pOpponent_spec, section_no, direction); } @@ -661,9 +667,6 @@ int SearchForSection(tRoute_section* pTemp_store, tRoute_section* pPerm_store, i tS16 section_no_index; br_scalar distance_so_far; - // added by dethrace for readability (?) - tS16 section_no_dir_index; - gSFS_cycles_this_time++; if (pDepth == 1) { memset(gBit_per_node, 0, (gProgram_state.AI_vehicles.number_of_path_nodes + 7) / 8); @@ -681,42 +684,37 @@ int SearchForSection(tRoute_section* pTemp_store, tRoute_section* pPerm_store, i section_no = node_ptr->sections[section_no_index]; direction = gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1] != node_no; - section_no_dir_index = gProgram_state.AI_vehicles.path_sections[section_no].node_indices[direction]; - // int b = BYTE4(v8); - // int y = (int)(((BYTE4(v8) ^ (((BYTE4(v8) ^ v8) - BYTE4(v8)) & 7)) - BYTE4(v8))); - // int val = valx(v8); - // LOG_DEBUG("val %d, b %d, y %d", val, b, y); - // int x = ((BYTE4(v8) ^ (((BYTE4(v8) ^ v8) - BYTE4(v8)) & 7)) - BYTE4(v8)); - // int x2 = v8 & 7; - // if (x != x2 || val != x) { - // TELL_ME_IF_WE_PASS_THIS_WAY(); - // } - if ((gBit_per_node[section_no_dir_index / 8] & (1 << (section_no_dir_index & 7))) == 0 - && (!gProgram_state.AI_vehicles.path_sections[section_no].one_way || direction) - && (pOpponent_spec->cheating || gProgram_state.AI_vehicles.path_sections[section_no].type != ePST_cheat_only)) { + if ((gBit_per_node[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[direction] / 8] & (1 << (gProgram_state.AI_vehicles.path_sections[section_no].node_indices[direction] % 8))) != 0) { + continue; + } + if ((gProgram_state.AI_vehicles.path_sections[section_no].one_way && gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1] == node_no)) { + continue; + } + if (!pOpponent_spec->cheating && gProgram_state.AI_vehicles.path_sections[section_no].type == ePST_cheat_only) { + continue; + } - pTemp_store[pDepth].section_no = section_no; - pTemp_store[pDepth].direction = direction; - distance_so_far = gProgram_state.AI_vehicles.path_sections[section_no].length + pDistance_so_far; + pTemp_store[pDepth].section_no = section_no; + pTemp_store[pDepth].direction = direction; + distance_so_far = gProgram_state.AI_vehicles.path_sections[section_no].length + pDistance_so_far; + if (pTarget_section == section_no && distance_so_far <= shortest_dist) { + shortest_dist = distance_so_far; + *pNum_of_perm_store_sections = pDepth + 1; + memcpy(pPerm_store, pTemp_store, sizeof(tRoute_section) * *pNum_of_perm_store_sections); - if (pTarget_section == section_no && distance_so_far < shortest_dist) { - shortest_dist = distance_so_far; - *pNum_of_perm_store_sections = pDepth + 1; - memcpy(pPerm_store, pTemp_store, sizeof(tRoute_section) * *pNum_of_perm_store_sections); - // dword_530DD4 = ++routes_found - routes_found++; - if (routes_found >= 2) { - return 1; - } - break; - } - - if (pDepth < 9 - && SearchForSection(pTemp_store, pPerm_store, pNum_of_perm_store_sections, pTarget_section, pDepth + 1, distance_so_far, pOpponent_spec)) { + gWanky_arse_tit_fuck = routes_found + 1; + routes_found++; + if (routes_found >= 2) { return 1; + } else { + gBit_per_node[node_no / 8] &= ~(1 << (node_no % 8)); + return 0; } } + if (pDepth < 9 && SearchForSection(pTemp_store, pPerm_store, pNum_of_perm_store_sections, pTarget_section, pDepth + 1, distance_so_far, pOpponent_spec)) { + return 1; + } } gBit_per_node[node_no / 8] &= ~(1 << (node_no % 8)); return 0; @@ -769,27 +767,28 @@ void CalcGetNearPlayerRoute(tOpponent_spec* pOpponent_spec, tCar_spec* pPlayer) TopUpRandomRoute(pOpponent_spec, 1); } while (pOpponent_spec->nnext_sections < 6 && !fuck_it) { - temp_store[0] = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1]; + temp_store[0].section_no = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].section_no; + temp_store[0].direction = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].direction; dr_dprintf("%s: CalcGetNearPlayerRoute() - In loop; our section #%d, player's section #%d", pOpponent_spec->car_spec->driver_name, temp_store[0].section_no, players_section); gSFS_count++; gSFS_cycles_this_time = 0; SearchForSection(temp_store, perm_store, &num_of_perm_store_sections, players_section, 1, 0.f, pOpponent_spec); gSFS_total_cycles += gSFS_cycles_this_time; - if (gSFS_max_cycles < gSFS_cycles_this_time) { + if (gSFS_cycles_this_time > gSFS_max_cycles) { gSFS_max_cycles = gSFS_cycles_this_time; } - dr_dprintf(">>>SearchForSection() - max %d, avg %.1f", gSFS_max_cycles, gSFS_total_cycles / (float)gSFS_count); - if (num_of_perm_store_sections <= 1) { + dr_dprintf(">>>SearchForSection() - max %d, avg %.1f", gSFS_max_cycles, (float)gSFS_total_cycles / gSFS_count); + if (num_of_perm_store_sections > 1) { + sections_to_copy = MIN(COUNT_OF(pOpponent_spec->next_sections) - pOpponent_spec->nnext_sections, num_of_perm_store_sections - 1); + memcpy(&pOpponent_spec->next_sections[pOpponent_spec->nnext_sections], &perm_store[1], sizeof(tRoute_section) * sections_to_copy); + pOpponent_spec->nnext_sections += sections_to_copy; + TopUpRandomRoute(pOpponent_spec, 1); + } else { dr_dprintf("%s: CalcGetNearPlayerRoute() - SearchForSection() produced bugger all", pOpponent_spec->car_spec->driver_name); fuck_it = 1; if (pOpponent_spec->nnext_sections <= 4) { TopUpRandomRoute(pOpponent_spec, 4 - pOpponent_spec->nnext_sections + 4); } - } else { - sections_to_copy = MIN(COUNT_OF(pOpponent_spec->next_sections) - pOpponent_spec->nnext_sections, num_of_perm_store_sections - 1); - memcpy(&pOpponent_spec->next_sections[pOpponent_spec->nnext_sections], &perm_store[1], sizeof(tRoute_section) * sections_to_copy); - pOpponent_spec->nnext_sections += sections_to_copy; - TopUpRandomRoute(pOpponent_spec, 1); } } } @@ -811,34 +810,31 @@ void CalcReturnToStartPointRoute(tOpponent_spec* pOpponent_spec) { ClearOpponentsProjectedRoute(pOpponent_spec); section_no = FindNearestPathSection(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, §ion_v, &intersect, &distance); - distance = BrVector3Length(§ion_v); BrVector3Normalise(§ion_v, §ion_v); - if (BrVector3Dot(&pOpponent_spec->car_spec->direction, §ion_v) <= 0.0f) { - AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 0); - } else { + if (BrVector3Dot(&pOpponent_spec->car_spec->direction, §ion_v) > 0.0f) { AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 1); + } else { + AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 0); } - temp_store[0] = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1]; + temp_store[0].section_no = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].section_no; + temp_store[0].direction = pOpponent_spec->next_sections[pOpponent_spec->nnext_sections - 1].direction; gSFS_count++; gSFS_cycles_this_time = 0; SearchForSection(temp_store, perm_store, &num_of_perm_store_sections, pOpponent_spec->return_to_start_data.section_no, 1, 0.0f, pOpponent_spec); gSFS_total_cycles += gSFS_cycles_this_time; - if (gSFS_max_cycles < gSFS_cycles_this_time) { + if (gSFS_cycles_this_time > gSFS_max_cycles) { gSFS_max_cycles = gSFS_cycles_this_time; } - if (num_of_perm_store_sections <= 1) { - if (pOpponent_spec->nnext_sections <= 6) { - TopUpRandomRoute(pOpponent_spec, 4 - pOpponent_spec->nnext_sections + 4); - } - } else { - sections_to_copy = 10 - pOpponent_spec->nnext_sections; - if (sections_to_copy >= num_of_perm_store_sections - 1) { - sections_to_copy = num_of_perm_store_sections - 1; - } + if (num_of_perm_store_sections > 1) { + sections_to_copy = MIN(num_of_perm_store_sections - 1, 10 - pOpponent_spec->nnext_sections); memcpy(&pOpponent_spec->next_sections[pOpponent_spec->nnext_sections], &perm_store[1], sizeof(tRoute_section) * sections_to_copy); pOpponent_spec->nnext_sections += sections_to_copy; TopUpRandomRoute(pOpponent_spec, 1); + } else { + if (pOpponent_spec->nnext_sections <= 6) { + TopUpRandomRoute(pOpponent_spec, 4 - pOpponent_spec->nnext_sections + 4); + } } } @@ -853,13 +849,14 @@ void ClearOpponentsProjectedRoute(tOpponent_spec* pOpponent_spec) { // FUNCTION: CARM95 0x004030ef int AddToOpponentsProjectedRoute(tOpponent_spec* pOpponent_spec, tS16 pSection_no, int pDirection) { - if (pOpponent_spec->nnext_sections >= COUNT_OF(pOpponent_spec->next_sections)) { + if (pOpponent_spec->nnext_sections < COUNT_OF(pOpponent_spec->next_sections)) { + pOpponent_spec->next_sections[pOpponent_spec->nnext_sections].section_no = pSection_no; + pOpponent_spec->next_sections[pOpponent_spec->nnext_sections].direction = pDirection; + pOpponent_spec->nnext_sections++; + return 1; + } else { return 0; } - pOpponent_spec->next_sections[pOpponent_spec->nnext_sections].section_no = pSection_no; - pOpponent_spec->next_sections[pOpponent_spec->nnext_sections].direction = pDirection; - pOpponent_spec->nnext_sections++; - return 1; } // IDA: int __usercall ShiftOpponentsProjectedRoute@(tOpponent_spec *pOpponent_spec@, int pPlaces@) @@ -867,15 +864,16 @@ int AddToOpponentsProjectedRoute(tOpponent_spec* pOpponent_spec, tS16 pSection_n int ShiftOpponentsProjectedRoute(tOpponent_spec* pOpponent_spec, int pPlaces) { int i; - if (pOpponent_spec->nnext_sections <= pPlaces) { + if (pOpponent_spec->nnext_sections > pPlaces) { + for (i = 0; i < COUNT_OF(pOpponent_spec->next_sections) - pPlaces; i++) { + pOpponent_spec->next_sections[i].section_no = pOpponent_spec->next_sections[pPlaces + i].section_no; + pOpponent_spec->next_sections[i].direction = pOpponent_spec->next_sections[pPlaces + i].direction; + } + pOpponent_spec->nnext_sections -= pPlaces; + return 1; + } else { return 0; } - for (i = 0; i < COUNT_OF(pOpponent_spec->next_sections) - pPlaces; i++) { - pOpponent_spec->next_sections[i].section_no = pOpponent_spec->next_sections[pPlaces + i].section_no; - pOpponent_spec->next_sections[i].direction = pOpponent_spec->next_sections[pPlaces + i].direction; - } - pOpponent_spec->nnext_sections -= pPlaces; - return 1; } // IDA: void __usercall StunTheBugger(tOpponent_spec *pOpponent_spec@, int pMilliseconds@) @@ -904,6 +902,15 @@ void ProcessCompleteRace(tOpponent_spec* pOpponent_spec, tProcess_objective_comm int res; char str[256]; + initial_pos = &gProgram_state.initial_position; + car_actor = pOpponent_spec->car_spec->car_master_actor; + data = &pOpponent_spec->complete_race_data; + +#ifdef DETHRACE_FIX_BUGS + // fix use uninitialized error + res = eFPR_OK; +#endif + switch (pCommand) { case ePOC_start: dr_dprintf("%s: ProcessCompleteRace() - new objective started", pOpponent_spec->car_spec->driver_name); @@ -916,11 +923,13 @@ void ProcessCompleteRace(tOpponent_spec* pOpponent_spec, tProcess_objective_comm ShiftOpponentsProjectedRoute(pOpponent_spec, pOpponent_spec->follow_path_data.section_no - 20000); pOpponent_spec->follow_path_data.section_no = 20000; } - res = ProcessFollowPath(pOpponent_spec, ePOC_run, 0, 0, 0); - if (pOpponent_spec->nnext_sections == 0 || res == eFPR_end_of_path) { + + if (pOpponent_spec->nnext_sections == 0 + || (res = ProcessFollowPath(pOpponent_spec, ePOC_run, 0, 0, 0)) == eFPR_end_of_path) { dr_dprintf("%s: Giving up following race path because ran out of race path", pOpponent_spec->car_spec->driver_name); NewObjective(pOpponent_spec, eOOT_get_near_player); } + if (res != eFPR_OK) { if (res == eFPR_given_up) { dr_dprintf("%s: Giving up complete_race because ProcessFollowPath() gave up", pOpponent_spec->car_spec->driver_name); @@ -933,12 +942,15 @@ void ProcessCompleteRace(tOpponent_spec* pOpponent_spec, tProcess_objective_comm dr_dprintf("%s: Time to give up complete_race. Might be back in a sec, though!", pOpponent_spec->car_spec->driver_name); ObjectiveComplete(pOpponent_spec); } - if (pOpponent_spec->nnext_sections < 5 && !pOpponent_spec->complete_race_data.finished_calcing_race_route) { + if (pOpponent_spec->nnext_sections <= 4 && !data->finished_calcing_race_route) { CalcRaceRoute(pOpponent_spec); } break; + +#ifdef DETHRACE_FIX_BUGS default: break; +#endif } } @@ -978,41 +990,42 @@ void RecordNextTrailNode(tCar_spec* pPursuee) { int visible; trail = &pPursuee->my_trail; - if (trail->time_of_next_recording >= gTime_stamp_for_this_munging) { - return; - } - trail->time_of_next_recording = gTime_stamp_for_this_munging + 500; - trail->nodes_shifted_this_frame = 0; - if (BrVector3Dot(&trail->base_heading, &pPursuee->direction) < FastScalarCos(30)) { - trail->has_deviated_recently = 1; - } - BrVector3Sub(&car_to_last_point_v, &trail->trail_nodes[trail->number_of_nodes - 2], &pPursuee->car_master_actor->t.t.translate.t); - length = BrVector3Length(&car_to_last_point_v); - if (length < 0.3f) { - return; - } - CalcNegativeXVector(&offset_v, &trail->trail_nodes[trail->number_of_nodes - 2], &pPursuee->car_master_actor->t.t.translate.t, 0.5f); - - BrVector3Add(&start1, &trail->trail_nodes[trail->number_of_nodes - 2], &offset_v); - BrVector3Add(&finish1, &pPursuee->car_master_actor->t.t.translate.t, &offset_v); - BrVector3Sub(&start2, &trail->trail_nodes[trail->number_of_nodes - 2], &offset_v); - BrVector3Sub(&finish2, &pPursuee->car_master_actor->t.t.translate.t, &offset_v); visible = 1; - if ((trail->has_deviated_recently - || !(visible = PointVisibleFromHere(&start1, &finish1)) - || !(visible = PointVisibleFromHere(&start2, &finish2)) - || !(visible = PointVisibleFromHere(&trail->trail_nodes[trail->number_of_nodes - 2], &pPursuee->car_master_actor->t.t.translate.t))) - && ((visible && length > 2.0f) || (!visible && length > 1.5f))) { - if (trail->number_of_nodes >= COUNT_OF(trail->trail_nodes)) { - memmove(trail->trail_nodes, &trail->trail_nodes[1], (COUNT_OF(trail->trail_nodes) - 1) * sizeof(trail->trail_nodes[0])); - trail->nodes_shifted_this_frame = 1; - } else { - trail->number_of_nodes++; + trail->nodes_shifted_this_frame = 0; + if (trail->time_of_next_recording < gTime_stamp_for_this_munging) { + + trail->time_of_next_recording = gTime_stamp_for_this_munging + 500; + if (BrVector3Dot(&pPursuee->direction, &trail->base_heading) < FastScalarCos(30)) { + trail->has_deviated_recently = 1; } - trail->has_deviated_recently = 0; - BrVector3Copy(&trail->base_heading, &pPursuee->direction); + BrVector3Sub(&car_to_last_point_v, &trail->trail_nodes[trail->number_of_nodes - 2], &pPursuee->car_master_actor->t.t.translate.t); + length = BrVector3Length(&car_to_last_point_v); + if (length < 0.3f) { + return; + } + CalcNegativeXVector(&offset_v, &trail->trail_nodes[trail->number_of_nodes - 2], &pPursuee->car_master_actor->t.t.translate.t, 0.5f); + + BrVector3Add(&start1, &trail->trail_nodes[trail->number_of_nodes - 2], &offset_v); + BrVector3Add(&finish1, &pPursuee->car_master_actor->t.t.translate.t, &offset_v); + BrVector3Sub(&start2, &trail->trail_nodes[trail->number_of_nodes - 2], &offset_v); + BrVector3Sub(&finish2, &pPursuee->car_master_actor->t.t.translate.t, &offset_v); + + if ((trail->has_deviated_recently + || !(visible = PointVisibleFromHere(&start1, &finish1)) + || !(visible = PointVisibleFromHere(&start2, &finish2)) + || !(visible = PointVisibleFromHere(&trail->trail_nodes[trail->number_of_nodes - 2], &pPursuee->car_master_actor->t.t.translate.t))) + && ((visible && length > 2.0f) || (!visible && length > 1.5f))) { + if (trail->number_of_nodes < COUNT_OF(trail->trail_nodes)) { + trail->number_of_nodes++; + } else { + memmove(trail->trail_nodes, &trail->trail_nodes[1], (COUNT_OF(trail->trail_nodes) - 1) * sizeof(trail->trail_nodes[0])); + trail->nodes_shifted_this_frame = 1; + } + trail->has_deviated_recently = 0; + BrVector3Copy(&trail->base_heading, &pPursuee->direction); + } + BrVector3Copy(&trail->trail_nodes[trail->number_of_nodes - 1], &pPursuee->car_master_actor->t.t.translate.t); } - BrVector3Copy(&trail->trail_nodes[trail->number_of_nodes - 1], &pPursuee->car_master_actor->t.t.translate.t); } // IDA: tS16 __usercall FindNearestTrailSection@(tOpponent_spec *pOpponent_spec@, tCar_spec *pPursuee@, br_vector3 *pSection_v@, br_vector3 *pIntersect@, br_scalar *pDistance) @@ -1028,13 +1041,13 @@ tS16 CalcNextTrailSection(tOpponent_spec* pOpponent_spec, int pSection) { int section_no; tPursuee_trail* trail; - trail = &pOpponent_spec->pursue_car_data.pursuee->my_trail; section_no = pSection - 15000; + trail = &pOpponent_spec->pursue_car_data.pursuee->my_trail; - if (trail->number_of_nodes - 2 > section_no) { - return pSection + 1; + if (trail->number_of_nodes - 2 <= section_no) { + return -1; } - return -1; + return section_no + 15001; } // IDA: void __usercall ProcessPursueAndTwat(tOpponent_spec *pOpponent_spec@, tProcess_objective_command pCommand@) @@ -1053,7 +1066,8 @@ void ProcessPursueAndTwat(tOpponent_spec* pOpponent_spec, tProcess_objective_com tS16 section_no; data = &pOpponent_spec->pursue_car_data; - if (pCommand == ePOC_start) { + switch (pCommand) { + case ePOC_start: dr_dprintf("%s: ProcessPursueAndTwat() - new objective started", pOpponent_spec->car_spec->driver_name); data->direct_line_nodes[0].number_of_sections = 1; data->direct_line_nodes[0].sections[0] = 10000; @@ -1074,139 +1088,153 @@ void ProcessPursueAndTwat(tOpponent_spec* pOpponent_spec, tProcess_objective_com data->time_last_away_from_pursuee = gTime_stamp_for_this_munging; data->state = ePCS_what_now; return; - } - if (pCommand != ePOC_run) { - return; - } + case ePOC_run: - if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec) && pOpponent_spec->distance_from_home > 75.0f) { - dr_dprintf("%s: Completing pursuit objective because I'm out of my precinct", pOpponent_spec->car_spec->driver_name); - NewObjective(pOpponent_spec, eOOT_return_to_start); - return; - } + if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec) && pOpponent_spec->distance_from_home > 75.0f) { + dr_dprintf("%s: Completing pursuit objective because I'm out of my precinct", pOpponent_spec->car_spec->driver_name); + NewObjective(pOpponent_spec, eOOT_return_to_start); + return; + } - data->direct_line_section.length = MAX(pOpponent_spec->player_to_oppo_d, 3.0f); - if (pOpponent_spec->player_to_oppo_d > 3.0f) { - data->time_last_away_from_pursuee = gTime_stamp_for_this_munging; - } - if (gOpponents[pOpponent_spec->index].psyche.grudge_against_player < 15u) { - dr_dprintf("%s: Completing pursuit objective because I'm happy now", pOpponent_spec->car_spec->driver_name); - ObjectiveComplete(pOpponent_spec); - return; - } - if (data->state != ePCS_backing_up) { - if (data->time_last_twatted_em + 1000 >= gTime_stamp_for_this_munging || data->time_last_twatted_em + 3000 <= gTime_stamp_for_this_munging || BrVector3Length(&data->pursuee->v) >= 0.3f) { - if (data->time_last_away_from_pursuee + 7000 >= gTime_stamp_for_this_munging || data->time_last_twatted_em + 7000 >= gTime_stamp_for_this_munging || data->start_backup_time + 10000 >= gTime_stamp_for_this_munging) { - if (pOpponent_spec->cheating) { - if (pOpponent_spec->player_to_oppo_d < 50.0f - && PointVisibleFromHere(&data->pursuee->car_master_actor->t.t.translate.t, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t)) { + data->direct_line_section.length = MAX(pOpponent_spec->player_to_oppo_d, 3.0f); + if (pOpponent_spec->player_to_oppo_d > 3.0f) { + data->time_last_away_from_pursuee = gTime_stamp_for_this_munging; + } + if (gOpponents[pOpponent_spec->index].psyche.grudge_against_player < 15) { + dr_dprintf("%s: Completing pursuit objective because I'm happy now", pOpponent_spec->car_spec->driver_name); + ObjectiveComplete(pOpponent_spec); + return; + } + if (data->state != ePCS_backing_up) { + if (data->time_last_twatted_em + 1000 < gTime_stamp_for_this_munging && data->time_last_twatted_em + 3000 > gTime_stamp_for_this_munging && BrVector3Length(&data->pursuee->v) < 0.3f) { + dr_dprintf("%s: Backing up because we're 'stationary' after colliding with pursuee", pOpponent_spec->car_spec->driver_name); + data->start_backup_time = gTime_stamp_for_this_munging; + data->state = ePCS_backing_up; + } else { + + if (data->time_last_away_from_pursuee + 7000 < gTime_stamp_for_this_munging && data->time_last_twatted_em + 7000 < gTime_stamp_for_this_munging && data->start_backup_time + 10000 < gTime_stamp_for_this_munging) { + dr_dprintf("%s: Backing up because we're too close to pursuee without having twatted him", pOpponent_spec->car_spec->driver_name); + data->start_backup_time = gTime_stamp_for_this_munging; + data->state = ePCS_backing_up; + } else { + if (pOpponent_spec->cheating) { + if (pOpponent_spec->player_to_oppo_d < 50.0f + && PointVisibleFromHere(&data->pursuee->car_master_actor->t.t.translate.t, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t)) { + data->time_pursuee_last_visible = gTime_stamp_for_this_munging; + } else { + data->time_pursuee_last_visible = 0; + } + } else if (pOpponent_spec->player_in_view_now || (data->time_of_next_visibility_check < gTime_stamp_for_this_munging && pOpponent_spec->player_to_oppo_d < 35.0f && PointVisibleFromHere(&data->pursuee->car_master_actor->t.t.translate.t, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t))) { data->time_pursuee_last_visible = gTime_stamp_for_this_munging; + data->time_of_next_visibility_check = gTime_stamp_for_this_munging + 600; + } + if (data->time_pursuee_last_visible + 3000 > gTime_stamp_for_this_munging) { + if (data->state != ePCS_following_line_of_sight) { + dr_dprintf("%s: Commencing ePCS_following_line_of_sight state", pOpponent_spec->car_spec->driver_name); + data->state = ePCS_following_line_of_sight; + sprintf(str, "%s: I've spotted you!", pOpponent_spec->car_spec->driver_name); + ProcessFollowPath(pOpponent_spec, ePOC_start, 1, 1, 0); + } } else { - data->time_pursuee_last_visible = 0; - } - } else if (pOpponent_spec->player_in_view_now || (data->time_of_next_visibility_check < gTime_stamp_for_this_munging && pOpponent_spec->player_to_oppo_d < 35.0f && PointVisibleFromHere(&data->pursuee->car_master_actor->t.t.translate.t, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t))) { - data->time_pursuee_last_visible = gTime_stamp_for_this_munging; - data->time_of_next_visibility_check = gTime_stamp_for_this_munging + 600; - } - if (data->time_pursuee_last_visible + 3000 <= gTime_stamp_for_this_munging) { - if (data->pursuee->my_trail.number_of_nodes < 2) { - dr_dprintf("%s: Giving up pursuit - not visible & no trail yet", pOpponent_spec->car_spec->driver_name); - NewObjective(pOpponent_spec, eOOT_get_near_player); - return; - } - if (data->state != ePCS_following_trail) { - section_no = FindNearestTrailSection(pOpponent_spec, data->pursuee, §ion_v, &intersect, &distance); - data->state = ePCS_following_trail; - if (distance > 20.0f || section_no == -1) { - dr_dprintf("%s: Giving up pursuit - not visible & trail ain't close enough (%f)", pOpponent_spec->car_spec->driver_name, distance); + if (data->pursuee->my_trail.number_of_nodes < 2) { + dr_dprintf("%s: Giving up pursuit - not visible & no trail yet", pOpponent_spec->car_spec->driver_name); NewObjective(pOpponent_spec, eOOT_get_near_player); return; } - dr_dprintf("%s: Commencing ePCS_following_trail state", pOpponent_spec->car_spec->driver_name); - pOpponent_spec->follow_path_data.section_no = section_no; - ProcessFollowPath(pOpponent_spec, ePOC_start, 1, 0, 0); + if (data->state != ePCS_following_trail) { + section_no = FindNearestTrailSection(pOpponent_spec, data->pursuee, §ion_v, &intersect, &distance); + data->state = ePCS_following_trail; + if (distance > 20.0f || section_no == -1) { + dr_dprintf("%s: Giving up pursuit - not visible & trail ain't close enough (%f)", pOpponent_spec->car_spec->driver_name, distance); + NewObjective(pOpponent_spec, eOOT_get_near_player); + return; + } + dr_dprintf("%s: Commencing ePCS_following_trail state", pOpponent_spec->car_spec->driver_name); + pOpponent_spec->follow_path_data.section_no = section_no; + ProcessFollowPath(pOpponent_spec, ePOC_start, 1, 0, 0); + } } - } else if (data->state != ePCS_following_line_of_sight) { - dr_dprintf("%s: Commencing ePCS_following_line_of_sight state", pOpponent_spec->car_spec->driver_name); - data->state = ePCS_following_line_of_sight; - sprintf(str, "%s: I've spotted you!", pOpponent_spec->car_spec->driver_name); - ProcessFollowPath(pOpponent_spec, ePOC_start, 1, 1, 0); } - } else { - dr_dprintf("%s: Backing up because we're too close to pursuee without having twatted him", pOpponent_spec->car_spec->driver_name); - data->start_backup_time = gTime_stamp_for_this_munging; - data->state = ePCS_backing_up; } - } else { - dr_dprintf("%s: Backing up because we're 'stationary' after colliding with pursuee", pOpponent_spec->car_spec->driver_name); - data->start_backup_time = gTime_stamp_for_this_munging; - data->state = ePCS_backing_up; } - } - switch (data->state) { - case ePCS_what_now: - PDEnterDebugger("ERROR: what_now state called in ProcessPursueAndTwat()"); - break; - case ePCS_following_trail: - if (data->pursuee->my_trail.nodes_shifted_this_frame) { - if (pOpponent_spec->follow_path_data.section_no <= 15000) { - data->state = ePCS_following_trail; - section_no = FindNearestTrailSection(pOpponent_spec, data->pursuee, §ion_v, &intersect, &distance); - dr_dprintf("%s: Trail got away; found new trail section %d", pOpponent_spec->car_spec->driver_name, section_no); - if (section_no == -1 || distance > 20.0f || !PointVisibleFromHere(&intersect, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t)) { - dr_dprintf("%s: ...which unfortunately is too far away (%fBRU) or not visible - end of pursuit", pOpponent_spec->car_spec->driver_name, distance); - NewObjective(pOpponent_spec, eOOT_get_near_player); - return; - } - pOpponent_spec->follow_path_data.section_no = section_no; - ProcessFollowPath(pOpponent_spec, ePOC_start, 1, 0, 0); - } else { - pOpponent_spec->follow_path_data.section_no--; - } - dr_dprintf("%s: Following re-jobbied section %d/%d", pOpponent_spec->car_spec->driver_name, pOpponent_spec->follow_path_data.section_no, data->pursuee->my_trail.number_of_nodes - 1); - } - sprintf(str, "%s: Trail section %d/%d", pOpponent_spec->car_spec->driver_name, pOpponent_spec->follow_path_data.section_no, data->pursuee->my_trail.number_of_nodes - 1); - res = ProcessFollowPath(pOpponent_spec, ePOC_run, 1, 0, 0); - if (res == eFPR_given_up || res == eFPR_end_of_path) { - NewObjective(pOpponent_spec, eOOT_get_near_player); - } - break; - case ePCS_following_line_of_sight: - BrVector3Copy(&data->direct_line_nodes[0].p, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t); - BrVector3Sub(&wank, &data->pursuee->car_master_actor->t.t.translate.t, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t); - s = BrVector3Length(&wank); - BrVector3Sub(&wank, &data->pursuee->v, &pOpponent_spec->car_spec->v); - t = BrVector3Length(&wank); - if (t >= 1.0f) { - d = s / t / 2.0; + switch (data->state) { - } else { - d = 0.0; - } - BrVector3Scale(&data->direct_line_nodes[1].p, &data->pursuee->v, d); - BrVector3Accumulate(&data->direct_line_nodes[1].p, &data->pursuee->car_master_actor->t.t.translate.t); - if (s >= 2.0f) { - ProcessFollowPath(pOpponent_spec, ePOC_run, 1, 1, 0); - } else { - ProcessFollowPath(pOpponent_spec, ePOC_run, 1, 1, 1); - } - break; - case ePCS_backing_up: - if (data->start_backup_time + 2200 >= gTime_stamp_for_this_munging) { - pOpponent_spec->car_spec->curvature = 0.0f; - pOpponent_spec->car_spec->brake_force = 0.0f; - pOpponent_spec->car_spec->acc_force = pOpponent_spec->car_spec->M * -8.0f; - } else { - pOpponent_spec->car_spec->acc_force = 0.0; - pOpponent_spec->car_spec->brake_force = pOpponent_spec->car_spec->M * 15.0f; - if (data->start_backup_time + 3000 < gTime_stamp_for_this_munging) { + case ePCS_backing_up: + if (data->start_backup_time + 2200 < gTime_stamp_for_this_munging) { + pOpponent_spec->car_spec->acc_force = 0.0; + pOpponent_spec->car_spec->brake_force = pOpponent_spec->car_spec->M * 15.0f; + if (data->start_backup_time + 3000 < gTime_stamp_for_this_munging) { + pOpponent_spec->car_spec->brake_force = 0.0f; + data->state = ePCS_what_now; + dr_dprintf("%s: Finished backing up.", pOpponent_spec->car_spec->driver_name); + } + } else { + pOpponent_spec->car_spec->curvature = 0.0f; pOpponent_spec->car_spec->brake_force = 0.0f; - data->state = ePCS_what_now; - dr_dprintf("%s: Finished backing up.", pOpponent_spec->car_spec->driver_name); + pOpponent_spec->car_spec->acc_force = pOpponent_spec->car_spec->M * -8.0f; } + break; + + case ePCS_following_line_of_sight: + BrVector3Copy(&data->direct_line_nodes[0].p, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t); + BrVector3Sub(&wank, &data->pursuee->car_master_actor->t.t.translate.t, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t); + d = BrVector3Length(&wank); + BrVector3Sub(&wank, &data->pursuee->v, &pOpponent_spec->car_spec->v); + s = BrVector3Length(&wank); + if (s < 1.0f) { + t = 0.0; + } else { + t = d / s / 2.0f; + } + BrVector3Scale(&data->direct_line_nodes[1].p, &data->pursuee->v, t); + BrVector3Accumulate(&data->direct_line_nodes[1].p, &data->pursuee->car_master_actor->t.t.translate.t); + if (d < 2.0f) { + ProcessFollowPath(pOpponent_spec, ePOC_run, 1, 1, 1); + } else { + ProcessFollowPath(pOpponent_spec, ePOC_run, 1, 1, 0); + } + break; + + case ePCS_following_trail: + if (data->pursuee->my_trail.nodes_shifted_this_frame) { + if (pOpponent_spec->follow_path_data.section_no > 15000) { + pOpponent_spec->follow_path_data.section_no--; + } else { + data->state = ePCS_following_trail; + section_no = FindNearestTrailSection(pOpponent_spec, data->pursuee, §ion_v, &intersect, &distance); + dr_dprintf("%s: Trail got away; found new trail section %d", pOpponent_spec->car_spec->driver_name, section_no); + if (section_no == -1 || distance > 20.0f || !PointVisibleFromHere(&intersect, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t)) { + dr_dprintf("%s: ...which unfortunately is too far away (%fBRU) or not visible - end of pursuit", pOpponent_spec->car_spec->driver_name, distance); + NewObjective(pOpponent_spec, eOOT_get_near_player); + break; + } + pOpponent_spec->follow_path_data.section_no = section_no; + ProcessFollowPath(pOpponent_spec, ePOC_start, 1, 0, 0); + } + dr_dprintf("%s: Following re-jobbied section %d/%d", pOpponent_spec->car_spec->driver_name, pOpponent_spec->follow_path_data.section_no, data->pursuee->my_trail.number_of_nodes - 1); + } + sprintf(str, "%s: Trail section %d/%d", pOpponent_spec->car_spec->driver_name, pOpponent_spec->follow_path_data.section_no, data->pursuee->my_trail.number_of_nodes - 1); + res = ProcessFollowPath(pOpponent_spec, ePOC_run, 1, 0, 0); + if (res == eFPR_given_up) { + NewObjective(pOpponent_spec, eOOT_get_near_player); + return; + } + if (res == eFPR_end_of_path) { + NewObjective(pOpponent_spec, eOOT_get_near_player); + return; + } + break; + + case ePCS_what_now: + PDEnterDebugger("ERROR: what_now state called in ProcessPursueAndTwat()"); + + default: + break; } + break; + default: return; } @@ -1224,48 +1252,50 @@ void ProcessRunAway(tOpponent_spec* pOpponent_spec, tProcess_objective_command p switch (pCommand) { - case ePOC_run: - if (pOpponent_spec->run_away_data.time_to_stop >= gTime_stamp_for_this_munging) { - if (pOpponent_spec->follow_path_data.section_no > 20000) { - ShiftOpponentsProjectedRoute(pOpponent_spec, pOpponent_spec->follow_path_data.section_no - 20000); - pOpponent_spec->follow_path_data.section_no = 20000; - } - if (pOpponent_spec->nnext_sections < 10) { - TopUpRandomRoute(pOpponent_spec, 10 - pOpponent_spec->nnext_sections); - } - if (ProcessFollowPath(pOpponent_spec, ePOC_run, 0, 0, 0) == eFPR_given_up) { - ClearOpponentsProjectedRoute(pOpponent_spec); - section_no = FindNearestPathSection(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &direction_v, &intersect, &distance); - if (BrVector3Dot(&pOpponent_spec->car_spec->direction, &direction_v) < 0.0f) { - AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 0); - } else { - AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 1); - } - TopUpRandomRoute(pOpponent_spec, -1); - ProcessFollowPath(pOpponent_spec, ePOC_start, 0, 0, 0); - } - } else { - ObjectiveComplete(pOpponent_spec); - } - break; - case ePOC_start: dr_dprintf("%s: ProcessRunAway() - new objective started", pOpponent_spec->car_spec->driver_name); pOpponent_spec->run_away_data.time_to_stop = gTime_stamp_for_this_munging + 1000 * IRandomBetween(30, 90); ClearOpponentsProjectedRoute(pOpponent_spec); section_no = FindNearestPathSection(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &direction_v, &intersect, &distance); - if (BrVector3Dot(&pOpponent_spec->car_spec->direction, &direction_v) < 0.0f) { - AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 0); - } else { + if (BrVector3Dot(&pOpponent_spec->car_spec->direction, &direction_v) >= 0.0f) { AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 1); + } else { + AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 0); } TopUpRandomRoute(pOpponent_spec, -1); ProcessFollowPath(pOpponent_spec, ePOC_start, 0, 0, 0); sprintf(str, "%s: Shit! I'm out of here...", pOpponent_spec->car_spec->driver_name); break; - case ePOC_die: + case ePOC_run: + if (pOpponent_spec->run_away_data.time_to_stop < gTime_stamp_for_this_munging) { + ObjectiveComplete(pOpponent_spec); + return; + } + if (pOpponent_spec->follow_path_data.section_no > 20000) { + ShiftOpponentsProjectedRoute(pOpponent_spec, pOpponent_spec->follow_path_data.section_no - 20000); + pOpponent_spec->follow_path_data.section_no = 20000; + } + if (pOpponent_spec->nnext_sections < 10) { + TopUpRandomRoute(pOpponent_spec, 10 - pOpponent_spec->nnext_sections); + } + res = ProcessFollowPath(pOpponent_spec, ePOC_run, 0, 0, 0); + if (res == eFPR_given_up) { + ClearOpponentsProjectedRoute(pOpponent_spec); + section_no = FindNearestPathSection(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &direction_v, &intersect, &distance); + if (BrVector3Dot(&pOpponent_spec->car_spec->direction, &direction_v) >= 0.0f) { + AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 1); + } else { + AddToOpponentsProjectedRoute(pOpponent_spec, section_no, 0); + } + TopUpRandomRoute(pOpponent_spec, -1); + ProcessFollowPath(pOpponent_spec, ePOC_start, 0, 0, 0); + } + break; + + case ePOC_die: + return; } } @@ -1275,11 +1305,14 @@ void ProcessWaitForSomeHaplessSod(tOpponent_spec* pOpponent_spec, tProcess_objec switch (pCommand) { case ePOC_start: + pOpponent_spec->car_spec->brake_force = 15.f * pOpponent_spec->car_spec->M; + return; case ePOC_run: pOpponent_spec->car_spec->brake_force = 15.f * pOpponent_spec->car_spec->M; - break; - default: - break; + return; + + case ePOC_die: + return; } } @@ -1293,17 +1326,26 @@ void ProcessReturnToStart(tOpponent_spec* pOpponent_spec, tProcess_objective_com int res; switch (pCommand) { + case ePOC_start: + dr_dprintf("%s: ProcessReturnToStart() - new objective started", pOpponent_spec->car_spec->driver_name); + pOpponent_spec->return_to_start_data.waiting_near_start = 0; + pOpponent_spec->return_to_start_data.section_no = FindNearestPathSection(&pOpponent_spec->start_pos, §ion_v, &pOpponent_spec->return_to_start_data.nearest_path_point, &distance); + pOpponent_spec->return_to_start_data.nearest_path_point.v[1] = 0.0; + CalcReturnToStartPointRoute(pOpponent_spec); + ProcessFollowPath(pOpponent_spec, ePOC_start, 0, 0, 0); + break; case ePOC_run: if (TeleportCopToStart(pOpponent_spec)) { break; } - if (pOpponent_spec->return_to_start_data.waiting_near_start) { - pOpponent_spec->car_spec->brake_force = pOpponent_spec->car_spec->M * 15.0f; - } else { - our_pos_xz = pOpponent_spec->car_spec->car_master_actor->t.t.translate.t; + if (!pOpponent_spec->return_to_start_data.waiting_near_start) { + BrVector3Copy(&our_pos_xz, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t); our_pos_xz.v[1] = 0.0f; BrVector3Sub(&cop_to_start, &pOpponent_spec->start_pos, &our_pos_xz); - if (BrVector3Length(&cop_to_start) >= 10.0) { + if (BrVector3Length(&cop_to_start) < 10.f) { + pOpponent_spec->return_to_start_data.waiting_near_start = 1; + pOpponent_spec->car_spec->brake_force = pOpponent_spec->car_spec->M * 15.0f; + } else { if (pOpponent_spec->follow_path_data.section_no > 20000) { ShiftOpponentsProjectedRoute(pOpponent_spec, pOpponent_spec->follow_path_data.section_no - 20000); pOpponent_spec->follow_path_data.section_no = 20000; @@ -1322,22 +1364,14 @@ void ProcessReturnToStart(tOpponent_spec* pOpponent_spec, tProcess_objective_com CalcReturnToStartPointRoute(pOpponent_spec); ProcessFollowPath(pOpponent_spec, ePOC_start, 0, 0, 0); } - } else { - pOpponent_spec->return_to_start_data.waiting_near_start = 1; - pOpponent_spec->car_spec->brake_force = pOpponent_spec->car_spec->M * 15.0f; } + } else { + pOpponent_spec->car_spec->brake_force = pOpponent_spec->car_spec->M * 15.0f; } break; - case ePOC_start: - dr_dprintf("%s: ProcessReturnToStart() - new objective started", pOpponent_spec->car_spec->driver_name); - pOpponent_spec->return_to_start_data.waiting_near_start = 0; - pOpponent_spec->return_to_start_data.section_no = FindNearestPathSection(&pOpponent_spec->start_pos, §ion_v, &pOpponent_spec->return_to_start_data.nearest_path_point, &distance); - pOpponent_spec->return_to_start_data.nearest_path_point.v[1] = 0.0; - CalcReturnToStartPointRoute(pOpponent_spec); - ProcessFollowPath(pOpponent_spec, ePOC_start, 0, 0, 0); - break; - default: - break; + + case ePOC_die: + return; } } @@ -1348,41 +1382,50 @@ void ProcessLevitate(tOpponent_spec* pOpponent_spec, tProcess_objective_command float terminal_time; float y; - if (pCommand == ePOC_start) { + switch (pCommand) { + case ePOC_start: dr_dprintf("%s: ProcessLevitate() - new objective started", pOpponent_spec->car_spec->driver_name); pOpponent_spec->levitate_data.waiting_to_levitate = 1; pOpponent_spec->car_spec->brake_force = 15.f * pOpponent_spec->car_spec->M; pOpponent_spec->car_spec->acc_force = 0.f; pOpponent_spec->levitate_data.time_started = gTime_stamp_for_this_munging; - } else if (pCommand == ePOC_run) { + break; + + case ePOC_run: if (pOpponent_spec->levitate_data.waiting_to_levitate) { if ((BrVector3Length(&pOpponent_spec->car_spec->v) < .01f && BrVector3Length(&pOpponent_spec->car_spec->omega) < 1.f) || gTime_stamp_for_this_munging - pOpponent_spec->levitate_data.time_started > 4000) { pOpponent_spec->levitate_data.waiting_to_levitate = 0; pOpponent_spec->levitate_data.time_started = gTime_stamp_for_this_munging; pOpponent_spec->levitate_data.initial_y = pOpponent_spec->car_spec->car_master_actor->t.t.translate.t.v[1]; if (pOpponent_spec->car_spec->has_been_stolen) { - NewTextHeadupSlot(eHeadupSlot_misc, 250, 2500, -4, GetMiscString(kMiscString_CarAddedToChangeCarList)); + NewTextHeadupSlot(eHeadupSlot_misc, 250, 5000, -4, GetMiscString(kMiscString_CarAddedToChangeCarList)); } } else { pOpponent_spec->car_spec->brake_force = 15.f * pOpponent_spec->car_spec->M; pOpponent_spec->car_spec->acc_force = 0.f; BrVector3InvScale(&pOpponent_spec->car_spec->omega, &pOpponent_spec->car_spec->omega, - pow(gFrame_period_for_this_munging / 1000.f, 2.f)); + pow(2.f, gFrame_period_for_this_munging / 1000.0)); } } if (!pOpponent_spec->levitate_data.waiting_to_levitate) { TurnOpponentPhysicsOff(pOpponent_spec); - t = (gTime_stamp_for_this_munging - pOpponent_spec->levitate_data.time_started) / 1000.f; - if (t < 20.f) { - y = .5f * t * t / 2.f; + t = (gTime_stamp_for_this_munging - pOpponent_spec->levitate_data.time_started) / 1000.0; + terminal_time = 20.f; + if (t < terminal_time) { + y = t * t * .5f / 2.f; } else { - y = 10.f * (t - 20.f) + 100.f; + y = terminal_time * terminal_time * 0.5 / 2.0 + (t - terminal_time) * 10.0; } pOpponent_spec->car_spec->car_master_actor->t.t.translate.t.v[1] = pOpponent_spec->levitate_data.initial_y + y; if (y > 200.f) { pOpponent_spec->finished_for_this_race = 1; } } + break; + case ePOC_die: + return; + default: + break; } } @@ -1394,21 +1437,25 @@ void ProcessGetNearPlayer(tOpponent_spec* pOpponent_spec, tProcess_objective_com int res; char str[256]; - if (pCommand == ePOC_start) { + initial_pos = &gProgram_state.initial_position; + car_actor = pOpponent_spec->car_spec->car_master_actor; + + switch (pCommand) { + case ePOC_start: dr_dprintf("%s: ProcessGetNearPlayer() - new objective started", pOpponent_spec->car_spec->driver_name); ClearOpponentsProjectedRoute(pOpponent_spec); CalcGetNearPlayerRoute(pOpponent_spec, &gProgram_state.current_car); ProcessFollowPath(pOpponent_spec, ePOC_start, 0, 0, 0); - return; - } - if (pCommand == ePOC_run) { - if ((pOpponent_spec->car_spec->car_ID & 0xff00) == 768 && pOpponent_spec->distance_from_home > 75.0) { + break; + + case ePOC_run: + if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec) && pOpponent_spec->distance_from_home > 75.0f) { dr_dprintf("%s: Completing get_near objective because I'm out of my precinct", pOpponent_spec->car_spec->driver_name); NewObjective(pOpponent_spec, eOOT_return_to_start); return; } if (pOpponent_spec->follow_path_data.section_no > 20000) { - if (pOpponent_spec->player_to_oppo_d < 10.0 || pOpponent_spec->follow_path_data.section_no == pOpponent_spec->players_section_when_last_calced_full_path) { + if (pOpponent_spec->player_to_oppo_d < 10.0f || pOpponent_spec->follow_path_data.section_no == pOpponent_spec->players_section_when_last_calced_full_path) { dr_dprintf("%s: ProcessGetNearPlayer() - giving up 'cos got to player's section", pOpponent_spec->car_spec->driver_name); ObjectiveComplete(pOpponent_spec); return; @@ -1422,14 +1469,20 @@ void ProcessGetNearPlayer(tOpponent_spec* pOpponent_spec, tProcess_objective_com res = ProcessFollowPath(pOpponent_spec, ePOC_run, 0, 0, 0); sprintf(str, "Get near: %d", GetOpponentsRealSection(pOpponent_spec, pOpponent_spec->follow_path_data.section_no)); - if (res == eFPR_given_up) { - NewObjective(pOpponent_spec, eOOT_pursue_and_twat, &gProgram_state.current_car); - } else if (res == eFPR_end_of_path) { - dr_dprintf("%s: Restarting get_near_player route because ran out of path!", pOpponent_spec->car_spec->driver_name); + if (res == eFPR_given_up || res == eFPR_end_of_path) { + if (res == eFPR_given_up) { + NewObjective(pOpponent_spec, eOOT_pursue_and_twat, &gProgram_state.current_car); + return; + } else { + dr_dprintf("%s: Restarting get_near_player route because ran out of path!", pOpponent_spec->car_spec->driver_name); + } ClearOpponentsProjectedRoute(pOpponent_spec); CalcGetNearPlayerRoute(pOpponent_spec, &gProgram_state.current_car); ProcessFollowPath(pOpponent_spec, ePOC_start, 0, 0, 0); } + + default: + break; } } @@ -1467,12 +1520,13 @@ int HeadOnWithPlayerPossible(tOpponent_spec* pOpponent_spec) { - pOpponent_spec->car_spec->car_master_actor->t.t.mat.m[3][2]; BrVector3Normalise(&oppo_to_player_norm, &oppo_to_player_norm); - if (gHead_on_cos_value >= BrVector3Dot(&pOpponent_spec->car_spec->direction, &pOpponent_spec->car_spec->direction) - || -gHead_on_cos_value <= BrVector3Dot(&pOpponent_spec->car_spec->direction, &pOpponent_spec->car_spec->direction)) { - return 0; + if (gHead_on_cos_value < BrVector3Dot(&pOpponent_spec->car_spec->direction, &oppo_to_player_norm) + && -gHead_on_cos_value > BrVector3Dot(&gProgram_state.current_car.direction, &oppo_to_player_norm)) { + + dr_dprintf("HOORAY! Head-on imminent"); + return 1; } - dr_dprintf("HOORAY! Head-on imminent"); - return 1; + return 0; } // IDA: int __usercall AlreadyPursuingCar@(tOpponent_spec *pOpponent_spec@, tCar_spec *pPursuee@) @@ -1506,12 +1560,12 @@ void ObjectiveComplete(tOpponent_spec* pOpponent_spec) { case eOOT_complete_race: gNum_of_opponents_completing_race--; break; - case eOOT_pursue_and_twat: - gNum_of_opponents_pursuing--; - break; case eOOT_get_near_player: gNum_of_opponents_getting_near--; break; + case eOOT_pursue_and_twat: + gNum_of_opponents_pursuing--; + break; default: break; } @@ -1580,16 +1634,17 @@ void ChooseNewObjective(tOpponent_spec* pOpponent_spec, int pMust_choose_one) { if (gTime_stamp_for_this_munging > pOpponent_spec->next_out_of_world_check) { pOpponent_spec->next_out_of_world_check = gTime_stamp_for_this_munging + 500; if (HasCarFallenOffWorld(pOpponent_spec->car_spec)) { - if (pOpponent_spec->car_spec->last_time_we_touched_a_player <= gTime_stamp_for_this_munging - 7000) { - TeleportOpponentToNearestSafeLocation(pOpponent_spec); - NewObjective(pOpponent_spec, eOOT_complete_race); - } else { + if (pOpponent_spec->car_spec->last_time_we_touched_a_player > gTime_stamp_for_this_munging - 7000) { TurnOpponentPhysicsOff(pOpponent_spec); pOpponent_spec->finished_for_this_race = 1; KnackerThisCar(pOpponent_spec->car_spec); pOpponent_spec->car_spec->car_master_actor->t.t.mat.m[3][1] -= 1000.0f; + return; + } else { + TeleportOpponentToNearestSafeLocation(pOpponent_spec); + NewObjective(pOpponent_spec, eOOT_complete_race); + return; } - return; } } if (pOpponent_spec->car_spec->knackered && !pOpponent_spec->knackeredness_detected) { @@ -1611,7 +1666,6 @@ void ChooseNewObjective(tOpponent_spec* pOpponent_spec, int pMust_choose_one) { NewObjective(pOpponent_spec, eOOT_get_near_player); } } - return; } else { if (CAR_SPEC_GET_SPEED_FACTOR(pOpponent_spec->car_spec) == 0.0f) { dr_dprintf("%s: Decided to freeze", pOpponent_spec->car_spec->driver_name); @@ -1627,17 +1681,15 @@ void ChooseNewObjective(tOpponent_spec* pOpponent_spec, int pMust_choose_one) { general_grudge_increase = (pOpponent_spec->nastiness * 40.0f + 10.0f); if (pOpponent_spec->car_spec->scary_bang && pOpponent_spec->player_to_oppo_d < 10.0f) { if (pOpponent_spec->current_objective == eOOT_pursue_and_twat) { - percentage = 40; + pursuit_percentage = 40; } else { - percentage = 0; + pursuit_percentage = 0; } - if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec)) { - if (PercentageChance(20)) { - dr_dprintf("%s: Decided to run away", pOpponent_spec->car_spec->driver_name); - NewObjective(pOpponent_spec, eOOT_run_away); - return; - } - } else if (PercentageChance((percentage + 60) - pOpponent_spec->nastiness * 50.0)) { + if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec) && PercentageChance(20)) { + dr_dprintf("%s: Decided to run away", pOpponent_spec->car_spec->driver_name); + NewObjective(pOpponent_spec, eOOT_run_away); + return; + } else if (PercentageChance((pursuit_percentage + 60) - pOpponent_spec->nastiness * 50.0f)) { dr_dprintf("%s: Decided to run away", pOpponent_spec->car_spec->driver_name); NewObjective(pOpponent_spec, eOOT_run_away); return; @@ -1652,14 +1704,6 @@ void ChooseNewObjective(tOpponent_spec* pOpponent_spec, int pMust_choose_one) { return; } if (pOpponent_spec->car_spec->big_bang && LastTwatterAPlayer(pOpponent_spec) && !AlreadyPursuingCar(pOpponent_spec, pOpponent_spec->car_spec->last_person_to_hit_us)) { - // v4 = gOpponents[pOpponent_spec->index].psyche.grudge_against_player; - // if (v4 <= 20) { - // v4 = 20; - // } - // v5 = general_grudge_increase + v4; - // if (v5 >= 100) { - // LOBYTE(v5) = 100; - // } gOpponents[pOpponent_spec->index].psyche.grudge_against_player = MIN(100, MAX(20, gOpponents[pOpponent_spec->index].psyche.grudge_against_player) + general_grudge_increase); sprintf(str, "%s: Christ! What was that?", pOpponent_spec->car_spec->driver_name); dr_dprintf("%s: Decided to pursue after big bang; last person to twat us was %s", pOpponent_spec->car_spec->driver_name, pOpponent_spec->car_spec->last_person_to_hit_us->driver_name); @@ -1667,14 +1711,6 @@ void ChooseNewObjective(tOpponent_spec* pOpponent_spec, int pMust_choose_one) { return; } if (LastTwatteeAPlayer(pOpponent_spec) && !AlreadyPursuingCar(pOpponent_spec, pOpponent_spec->car_spec->last_person_we_hit)) { - // v6 = gOpponents[pOpponent_spec->index].psyche.grudge_against_player; - // if (v6 <= 20) { - // v6 = 20; - // } - // v7 = general_grudge_increase + v6; - // if (v7 >= 100) { - // LOBYTE(v7) = 100; - // } gOpponents[pOpponent_spec->index].psyche.grudge_against_player = MIN(100, MAX(20, gOpponents[pOpponent_spec->index].psyche.grudge_against_player) + general_grudge_increase); sprintf(str, "%s: Ha! Bet you weren't expecting that!", pOpponent_spec->car_spec->driver_name); dr_dprintf("%s: Decided to pursue %s after accidentally hitting them", pOpponent_spec->car_spec->driver_name, pOpponent_spec->car_spec->last_person_we_hit->driver_name); @@ -1682,15 +1718,7 @@ void ChooseNewObjective(tOpponent_spec* pOpponent_spec, int pMust_choose_one) { return; } if (!AlreadyPursuingCar(pOpponent_spec, &gProgram_state.current_car)) { - if (pOpponent_spec->car_spec->grudge_raised_recently && (!CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec) || pOpponent_spec->player_to_oppo_d <= 20.0) && LastTwatterAPlayer(pOpponent_spec) && gOpponents[pOpponent_spec->index].psyche.grudge_against_player > 20) { - // v8 = gOpponents[pOpponent_spec->index].psyche.grudge_against_player; - // if (v8 <= 20) { - // v8 = 20; - // } - // v9 = general_grudge_increase + v8; - // if (v9 >= 100) { - // LOBYTE(v9) = 100; - // } + if (pOpponent_spec->car_spec->grudge_raised_recently && (!CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec) || pOpponent_spec->player_to_oppo_d <= 20.f) && LastTwatterAPlayer(pOpponent_spec) && gOpponents[pOpponent_spec->index].psyche.grudge_against_player > 20) { gOpponents[pOpponent_spec->index].psyche.grudge_against_player = MIN(100, MAX(20, gOpponents[pOpponent_spec->index].psyche.grudge_against_player) + general_grudge_increase); sprintf(str, "%s: Right! That's enough, %s!", pOpponent_spec->car_spec->driver_name, gProgram_state.current_car.driver_name); dr_dprintf("%s: Decided to pursue after grudginess raised; last person to twat us was %s", pOpponent_spec->car_spec->driver_name, pOpponent_spec->car_spec->last_person_to_hit_us->driver_name); @@ -1698,69 +1726,76 @@ void ChooseNewObjective(tOpponent_spec* pOpponent_spec, int pMust_choose_one) { return; } - if ((pOpponent_spec->player_in_view_now) != 0 && (pOpponent_spec->acknowledged_piv) == 0) { - pOpponent_spec->acknowledged_piv = 1; - if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec)) { - pursuit_percentage = (BrVector3Length(&gProgram_state.current_car.v) - gDefinite_no_cop_pursuit_speed) * gCop_pursuit_speed_percentage_multiplier; - } else if (gProgram_state.skill_level + 3 > gNum_of_opponents_pursuing) { - pursuit_percentage = gOpponents[pOpponent_spec->index].psyche.grudge_against_player - 20 + pOpponent_spec->nastiness * 30.f; - } else { - pursuit_percentage = 0; - } + if (pOpponent_spec->player_in_view_now) { + do_it = 0; + if (pOpponent_spec->acknowledged_piv == 0) { - pursuit_percentage += 50 * HeadOnWithPlayerPossible(pOpponent_spec); - do_it = PercentageChance(pursuit_percentage); - dr_dprintf("%s: Spotted player; chance of pursuing %d%%: %s", pOpponent_spec->car_spec->driver_name, pursuit_percentage, do_it ? "YES, Decided to pursue" : "NO, Decided NOT to pursue"); - if (do_it) { - gOpponents[pOpponent_spec->index].psyche.grudge_against_player = MIN(100, MAX(20, gOpponents[pOpponent_spec->index].psyche.grudge_against_player) + general_grudge_increase); - sprintf(str, "%s: I've decided to kill you for the fun of it", pOpponent_spec->car_spec->driver_name); - NewObjective(pOpponent_spec, eOOT_pursue_and_twat, &gProgram_state.current_car); - return; + pOpponent_spec->acknowledged_piv = 1; + if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec)) { + percentage = (BrVector3Length(&gProgram_state.current_car.v) - gDefinite_no_cop_pursuit_speed) * gCop_pursuit_speed_percentage_multiplier; + } else if (gProgram_state.skill_level + 3 > gNum_of_opponents_pursuing) { + percentage = gOpponents[pOpponent_spec->index].psyche.grudge_against_player - 20 + pOpponent_spec->nastiness * 30.f; + } else { + percentage = 0; + } + + percentage += 50 * HeadOnWithPlayerPossible(pOpponent_spec); + do_it = PercentageChance(percentage); + dr_dprintf("%s: Spotted player; chance of pursuing %d%%: %s", pOpponent_spec->car_spec->driver_name, percentage, do_it ? "YES, Decided to pursue" : "NO, Decided NOT to pursue"); + if (do_it) { + gOpponents[pOpponent_spec->index].psyche.grudge_against_player = MIN(100, MAX(20, gOpponents[pOpponent_spec->index].psyche.grudge_against_player) + general_grudge_increase); + sprintf(str, "%s: I've decided to kill you for the fun of it", pOpponent_spec->car_spec->driver_name); + NewObjective(pOpponent_spec, eOOT_pursue_and_twat, &gProgram_state.current_car); + return; + } } } } } } - if (!pMust_choose_one) { - return; - } - dr_dprintf("%s: Choosing new objective because we have to...", pOpponent_spec->car_spec->driver_name); - if (pOpponent_spec->has_moved_at_some_point) { - if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec)) { - NewObjective(pOpponent_spec, eOOT_return_to_start); - return; - } - if (gNum_of_opponents_pursuing + gNum_of_opponents_getting_near >= 3 || pOpponent_spec->player_to_oppo_d <= 10.0) { - if (gNum_of_opponents_completing_race >= 2) { - pursuit_percentage = pOpponent_spec->player_to_oppo_d - 15.0f; - if (PercentageChance(pursuit_percentage)) { - dr_dprintf("%s: Choosing to get_near because chance dictated it (%d%%)", pOpponent_spec->car_spec->driver_name, pursuit_percentage); + if (pMust_choose_one) { + dr_dprintf("%s: Choosing new objective because we have to...", pOpponent_spec->car_spec->driver_name, pOpponent_spec->car_spec->last_person_to_hit_us); + if (pOpponent_spec->has_moved_at_some_point) { + if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec)) { + NewObjective(pOpponent_spec, eOOT_return_to_start); + return; + } else { + if (gNum_of_opponents_getting_near + gNum_of_opponents_pursuing < 3 && pOpponent_spec->player_to_oppo_d > 10.0f) { + dr_dprintf("%s: Choosing to get_near because not enough oppos are yet (%d/%d)", pOpponent_spec->car_spec->driver_name, gNum_of_opponents_getting_near + gNum_of_opponents_pursuing, 3); + NewObjective(pOpponent_spec, eOOT_get_near_player); + return; + } + if (gNum_of_opponents_completing_race < 2) { + dr_dprintf("%s: Choosing to complete_race because not enough oppos are yet (%d/%d)", pOpponent_spec->car_spec->driver_name, gNum_of_opponents_completing_race, 2); + NewObjective(pOpponent_spec, eOOT_complete_race); + return; + } + + percentage = (int)pOpponent_spec->player_to_oppo_d - 15; + if (PercentageChance(percentage)) { + dr_dprintf("%s: Choosing to get_near because chance dictated it (%d%%)", pOpponent_spec->car_spec->driver_name, percentage); NewObjective(pOpponent_spec, eOOT_get_near_player); return; } else { - dr_dprintf("%s: Choosing to complete_race because chance dictated it (%d%%)", pOpponent_spec->car_spec->driver_name, pursuit_percentage); + dr_dprintf("%s: Choosing to complete_race because chance dictated it (%d%%)", pOpponent_spec->car_spec->driver_name, percentage); + NewObjective(pOpponent_spec, eOOT_complete_race); + return; } - } else { - dr_dprintf("%s: Choosing to complete_race because not enough oppos are yet (%d/%d)", pOpponent_spec->car_spec->driver_name, gNum_of_opponents_completing_race, 2); } + + } else if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec)) { + NewObjective(pOpponent_spec, eOOT_wait_for_some_hapless_sod); + return; + } else if (pOpponent_spec->pursue_from_start && !gMellow_opponents) { + gOpponents[pOpponent_spec->index].psyche.grudge_against_player = MIN(100.f, pOpponent_spec->nastiness * 40.f + (MAX(20, gOpponents[pOpponent_spec->index].psyche.grudge_against_player) + 20)); + NewObjective(pOpponent_spec, eOOT_pursue_and_twat, &gProgram_state.current_car); + return; + + } else { NewObjective(pOpponent_spec, eOOT_complete_race); return; } - dr_dprintf("%s: Choosing to get_near because not enough oppos are yet (%d/%d)", pOpponent_spec->car_spec->driver_name, gNum_of_opponents_pursuing + gNum_of_opponents_getting_near, 3); - NewObjective(pOpponent_spec, eOOT_get_near_player); - return; } - if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec)) { - NewObjective(pOpponent_spec, eOOT_wait_for_some_hapless_sod); - return; - } - if (!pOpponent_spec->pursue_from_start || gMellow_opponents) { - NewObjective(pOpponent_spec, eOOT_complete_race); - return; - } - - gOpponents[pOpponent_spec->index].psyche.grudge_against_player = MIN(100, pOpponent_spec->nastiness * 40.0 + (MAX(20, gOpponents[pOpponent_spec->index].psyche.grudge_against_player) + 20)); - NewObjective(pOpponent_spec, eOOT_pursue_and_twat, &gProgram_state.current_car); } } @@ -1769,13 +1804,16 @@ void ChooseNewObjective(tOpponent_spec* pOpponent_spec, int pMust_choose_one) { void ProcessThisOpponent(tOpponent_spec* pOpponent_spec) { int i; - if ((gMap_mode && gShow_opponents) || pOpponent_spec->last_in_view + 3000 >= gTime_stamp_for_this_munging) { + if ((!gMap_mode || !gShow_opponents) && (pOpponent_spec->last_in_view + 3000 < gTime_stamp_for_this_munging)) { + if (pOpponent_spec->cheating == 0) { + StartToCheat(pOpponent_spec); + } + } else { if (pOpponent_spec->cheating) { OiStopCheating(pOpponent_spec); } - } else if (pOpponent_spec->cheating == 0) { - StartToCheat(pOpponent_spec); } + ChooseNewObjective(pOpponent_spec, pOpponent_spec->new_objective_required); pOpponent_spec->new_objective_required = 0; if (gCountdown || gRace_finished) { @@ -1817,32 +1855,39 @@ void RebuildActiveCarList(void) { gActive_car_list_rebuild_required = 0; gNum_active_cars = 0; - if (!gProgram_state.current_car.disabled || gAction_replay_mode) { - gActive_car_list[gNum_active_cars] = &gProgram_state.current_car; - gNum_active_cars++; - gProgram_state.current_car.active = 1; + for (i = 0; i < 1; i++) { + if (i > 0) { + PDFatalError("mGet_car_count( eVehicle_self ) > 1 - I didn't know this could happen!"); + } + + car_spec = &gProgram_state.current_car; + if (!car_spec->disabled || gAction_replay_mode) { + gActive_car_list[gNum_active_cars] = car_spec; + gNum_active_cars++; + car_spec->active = 1; + } } if (gNet_mode == eNet_mode_host) { for (i = 0; i < GetCarCount(eVehicle_net_player); i++) { car_spec = GetCarSpec(eVehicle_net_player, i); - if (car_spec->disabled) { - car_spec->active = 0; - } else { + if (!car_spec->disabled) { gActive_car_list[gNum_active_cars] = car_spec; gNum_active_cars++; car_spec->active = 1; + } else { + car_spec->active = 0; } } } else if (gNet_mode == eNet_mode_client) { for (i = 0; i < GetCarCount(eVehicle_net_player); i++) { car_spec = GetCarSpec(eVehicle_net_player, i); - if (car_spec->disabled || !IsNetCarActive(&car_spec->car_master_actor->t.t.translate.t)) { - car_spec->active = 0; - } else { + if (!car_spec->disabled && IsNetCarActive(&car_spec->car_master_actor->t.t.translate.t)) { gActive_car_list[gNum_active_cars] = car_spec; gNum_active_cars++; car_spec->active = 1; + } else { + car_spec->active = 0; } } } @@ -1856,12 +1901,13 @@ void RebuildActiveCarList(void) { car_spec->active = 0; } } - for (i = 0; gNumber_of_cops_before_faffage > i; ++i) { + for (i = 0; i < gNumber_of_cops_before_faffage; i++) { car_spec = GetCarSpec(eVehicle_rozzer, i); if (gProgram_state.AI_vehicles.cops[i].physics_me || gAction_replay_mode) { gActive_car_list[gNum_active_cars] = car_spec; gNum_active_cars++; car_spec->active = 1; + } else { } } } @@ -1883,7 +1929,7 @@ void StartToCheat(tOpponent_spec* pOpponent_spec) { dr_dprintf("%s: StartToCheat() - Starting to cheat", pOpponent_spec->car_spec->driver_name); pOpponent_spec->cheating = 1; - if ((pOpponent_spec->car_spec->car_ID & 0xff00) == 0x300) { + if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec)) { dr_dprintf("%s: StartToCheat() - Turning physics OFF", pOpponent_spec->car_spec->driver_name); TurnOpponentPhysicsOff(pOpponent_spec); RebuildActiveCarList(); @@ -1896,7 +1942,7 @@ void OiStopCheating(tOpponent_spec* pOpponent_spec) { dr_dprintf("%s: OiStopCheating() - End of cheating sesh", pOpponent_spec->car_spec->driver_name); pOpponent_spec->cheating = 0; - if ((pOpponent_spec->car_spec->car_ID & 0xff00) == 0x300) { + if (CAR_SPEC_IS_ROZZER(pOpponent_spec->car_spec)) { dr_dprintf("%s: OiStopCheating() - Turning physics ON", pOpponent_spec->car_spec->driver_name); TurnOpponentPhysicsOn(pOpponent_spec); RebuildActiveCarList(); @@ -1912,17 +1958,18 @@ int TeleportCopToStart(tOpponent_spec* pOpponent_spec) { return 0; } BrVector3Sub(&wank, &gProgram_state.current_car.car_master_actor->t.t.translate.t, &pOpponent_spec->start_pos); - if (BrVector3Length(&wank) <= gIn_view_distance) { - return 0; + if (BrVector3Length(&wank) > gIn_view_distance) { + BrVector3Copy(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &pOpponent_spec->start_pos); + PointActorAlongThisBloodyVector(pOpponent_spec->car_spec->car_master_actor, &pOpponent_spec->start_direction); + pOpponent_spec->physics_me = 0; + RematerialiseOpponent(pOpponent_spec, 0.0); + TurnOpponentPhysicsOff(pOpponent_spec); + RebuildActiveCarList(); + NewObjective(pOpponent_spec, eOOT_wait_for_some_hapless_sod); + return 1; } - pOpponent_spec->car_spec->car_master_actor->t.t.euler.t = pOpponent_spec->start_pos; - PointActorAlongThisBloodyVector(pOpponent_spec->car_spec->car_master_actor, &pOpponent_spec->start_direction); - pOpponent_spec->physics_me = 0; - RematerialiseOpponent(pOpponent_spec, 0.0); - TurnOpponentPhysicsOff(pOpponent_spec); - RebuildActiveCarList(); - NewObjective(pOpponent_spec, eOOT_wait_for_some_hapless_sod); - return 1; + + return 0; } // IDA: void __usercall CalcDistanceFromHome(tOpponent_spec *pOpponent_spec@) @@ -1943,32 +1990,34 @@ int MassageOpponentPosition(tOpponent_spec* pOpponent_spec, int pMassage_count) br_vector3 positive_y_vector; br_vector3 direction_v; - BrVector3Set(&positive_y_vector, 0.f, 1.f, 0.f); mat = &pOpponent_spec->car_spec->car_master_actor->t.t.mat; car_trans = &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t; if (pMassage_count > 22) { return 0; - } else if (pMassage_count > 20) { + } + + if (pMassage_count > 20) { car_trans->v[1] += (pMassage_count - 20) * 2.0f; - return 1; } else { - direction_v.v[0] = -pOpponent_spec->car_spec->car_master_actor->t.t.mat.m[2][0]; - direction_v.v[1] = -pOpponent_spec->car_spec->car_master_actor->t.t.mat.m[2][1]; - direction_v.v[2] = -pOpponent_spec->car_spec->car_master_actor->t.t.mat.m[2][2]; - if (pMassage_count % 4 >= 2) { + direction_v.v[0] = -mat->m[2][0]; + direction_v.v[1] = -mat->m[2][1]; + direction_v.v[2] = -mat->m[2][2]; + if (pMassage_count % 4 < 2) { + BrVector3Normalise(&displacement, &direction_v); + BrVector3Scale(&displacement, &displacement, (pMassage_count / 4) * 0.5f); + } else { + BrVector3Set(&positive_y_vector, 0.f, 1.f, 0.f); BrVector3Cross(&displacement, &positive_y_vector, &direction_v); BrVector3Normalise(&displacement, &displacement); BrVector3Scale(&displacement, &displacement, (pMassage_count / 4) * 0.1f); - } else { - BrVector3Normalise(&displacement, &direction_v); - BrVector3Scale(&displacement, &displacement, (pMassage_count / 4) * 0.5f); } if (pMassage_count % 2) { BrVector3Negate(&displacement, &displacement); } BrVector3Accumulate(car_trans, &displacement); - return 1; } + + return 1; } // IDA: int __usercall RematerialiseOpponentOnThisSection@(tOpponent_spec *pOpponent_spec@, br_scalar pSpeed, tS16 pSection_no) @@ -1991,36 +2040,38 @@ int RematerialiseOpponentOnThisSection(tOpponent_spec* pOpponent_spec, br_scalar } start = GetOpponentsSectionStartNodePoint(pOpponent_spec, pSection_no); finish = GetOpponentsSectionFinishNodePoint(pOpponent_spec, pSection_no); - BrVector3Sub(§ion_v, finish, start); - if (BrVector3Length(§ion_v) != 0.f) { - BrVector3Sub(&a, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, start); - t = BrVector3Dot(§ion_v, &a) / BrVector3Dot(§ion_v, §ion_v); + BrVector3Sub(&a, finish, start); + length = BrVector3Length(&a); + if (length != 0.f) { + BrVector3Sub(&p, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, start); + t = BrVector3Dot(&a, &p) / BrVector3LengthSquared(&a); if (t < 0.f) { - BrVector3Copy(&p, start); + BrVector3Copy(&intersect, start); } else if (t > 1.f) { - BrVector3Copy(&p, finish); + BrVector3Copy(&intersect, finish); } else { - p.v[0] = start->v[0] + t * section_v.v[0]; - p.v[1] = start->v[1] + t * section_v.v[1]; - p.v[2] = start->v[2] + t * section_v.v[2]; + BrVector3Scale(&intersect, &a, t); + BrVector3Add(&intersect, &intersect, start); } - BrVector3Copy(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &p); - BrVector3Sub(&a, finish, start); - PointActorAlongThisBloodyVector(pOpponent_spec->car_spec->car_master_actor, &a); + BrVector3Copy(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &intersect); + BrVector3Sub(§ion_v, finish, start); + PointActorAlongThisBloodyVector(pOpponent_spec->car_spec->car_master_actor, §ion_v); } - if (!RematerialiseOpponent(pOpponent_spec, pSpeed)) { + if (RematerialiseOpponent(pOpponent_spec, pSpeed)) { + BrVector3Sub(&car_to_end, finish, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t); + distance_to_end = BrVector3Length(&car_to_end); + pOpponent_spec->car_spec->brake_force = 0.f; + pOpponent_spec->car_spec->acc_force = 0.f; + if (distance_to_end < 5.f) { + pOpponent_spec->car_spec->brake_force = 15.f * pOpponent_spec->car_spec->M; + } else { + pOpponent_spec->car_spec->acc_force = pOpponent_spec->car_spec->M / 2.f; + } + pOpponent_spec->last_in_view = gTime_stamp_for_this_munging; + return 1; + } else { return 0; } - BrVector3Sub(&car_to_end, finish, &pOpponent_spec->car_spec->car_master_actor->t.t.translate.t); - pOpponent_spec->car_spec->brake_force = 0.f; - pOpponent_spec->car_spec->acc_force = 0.f; - if (BrVector3Length(&car_to_end) >= 5.f) { - pOpponent_spec->car_spec->acc_force = pOpponent_spec->car_spec->M / 2.f; - } else { - pOpponent_spec->car_spec->acc_force = 15.f * pOpponent_spec->car_spec->M; - } - pOpponent_spec->last_in_view = gTime_stamp_for_this_munging; - return 1; } // IDA: int __usercall RematerialiseOpponentOnNearestSection@(tOpponent_spec *pOpponent_spec@, br_scalar pSpeed) @@ -2040,6 +2091,7 @@ int RematerialiseOpponentOnNearestSection(tOpponent_spec* pOpponent_spec, br_sca return 1; } section_no = FindNearestPathSection(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &direction_v, &intersect, &distance); + start = &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]].p; finish = &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]].p; BrVector3Copy(&pOpponent_spec->car_spec->car_master_actor->t.t.translate.t, &intersect); PointActorAlongThisBloodyVector(pOpponent_spec->car_spec->car_master_actor, &direction_v); @@ -2047,12 +2099,12 @@ int RematerialiseOpponentOnNearestSection(tOpponent_spec* pOpponent_spec, br_sca if (RematerialiseOpponent(pOpponent_spec, pSpeed)) { pOpponent_spec->car_spec->brake_force = 0.0f; pOpponent_spec->car_spec->acc_force = 0.0f; - distance_to_end = BrVector3Length(&car_to_end); - if (distance_to_end >= 5.0f) { - pOpponent_spec->car_spec->acc_force = pOpponent_spec->car_spec->M / 2.0f; - } else { + + if (distance_to_end < 5.0f) { pOpponent_spec->car_spec->brake_force = pOpponent_spec->car_spec->M * 15.0f; + } else { + pOpponent_spec->car_spec->acc_force = pOpponent_spec->car_spec->M / 2.0f; } } return 0; @@ -2087,104 +2139,106 @@ int RematerialiseOpponent(tOpponent_spec* pOpponent_spec, br_scalar pSpeed) { this_total = 0; mat = &pOpponent_spec->car_spec->car_master_actor->t.t.mat; massage_count = 0; - phi = BrDegreeToAngle(90) - BrRadianToAngle(atan2(mat->m[2][2], mat->m[2][0])); + theta = -BrRadianToAngle(atan2(mat->m[2][2], mat->m[2][0])) + BR_ANGLE_DEG(90); if (pOpponent_spec->physics_me) { dr_dprintf("%s: Actually, we're already materialised", pOpponent_spec->car_spec->driver_name); - } else { - total++; - BrMatrix34Copy(&original_mat, mat); - TurnOpponentPhysicsOn(pOpponent_spec); - RebuildActiveCarList(); - while (1) { - count++; - BrVector3Scale((br_vector3*)mat->m[3], (br_vector3*)mat->m[3], WORLD_SCALE); - BrVector3Copy(&b, (br_vector3*)mat->m[3]); - BrMatrix34RotateY(mat, phi); - BrVector3Copy((br_vector3*)mat->m[3], &b); - BrVector3SetFloat(&b, 0.f, -100.f, 0.f); - BrVector3Copy(&a, (br_vector3*)mat->m[3]); - a.v[1] += 1.f; - findfloor(&a, &b, &norm, &dist); - a.v[1] += 100.f; - findfloor(&a, &b, &norm2, &dist2); - if (dist2 <= 1.f) { - BrVector3SetFloat(&b, 0.f, -5.01f, 0.f); - a.v[1] -= 100.f; - for (i = 0; i < 20; i++) { - a.v[1] += 5.f; - findfloor(&a, &b, &norm2, &dist2); - if (dist2 <= 1.f) { - break; - } - } - dist2 = (i + 1) * 0.05f - dist2 / 20.f; - } - if (dist2 < dist) { - dist = -dist2; - BrVector3Copy(&norm, &norm2); - } - if (fabs(dist) <= 1.f) { - mat->m[3][1] -= dist * 100.f - 2.f; - BrMatrix34PreRotateX(mat, BrRadianToAngle(asin(BrVector3Dot((br_vector3*)mat->m[2], &norm)))); - BrMatrix34PreRotateZ(mat, BrRadianToAngle(asin(BrVector3Dot((br_vector3*)mat->m[2], &norm)))); - } - BrVector3Negate(&pOpponent_spec->car_spec->direction, (br_vector3*)mat->m[2]); - BrMatrix34ApplyP(&pOpponent_spec->car_spec->pos, &pOpponent_spec->car_spec->cmpos, mat); - BrVector3InvScale(&pOpponent_spec->car_spec->pos, &pOpponent_spec->car_spec->pos, WORLD_SCALE); - BrVector3InvScale((br_vector3*)mat->m[3], (br_vector3*)mat->m[3], WORLD_SCALE); - BrVector3Copy(&pOpponent_spec->car_spec->v, (br_vector3*)pOpponent_spec->car_spec->car_master_actor->t.t.mat.m[2]); - BrVector3Negate(&pOpponent_spec->car_spec->v, &pOpponent_spec->car_spec->v); - BrVector3Normalise(&pOpponent_spec->car_spec->v, &pOpponent_spec->car_spec->v); - BrVector3Scale(&pOpponent_spec->car_spec->v, &pOpponent_spec->car_spec->v, pSpeed * WORLD_SCALE); - BrVector3Set(&pOpponent_spec->car_spec->omega, 0.f, 0.f, 0.f); - BrMatrix34Copy(&pOpponent_spec->car_spec->oldmat, mat); - BrMatrix34Copy(&pOpponent_spec->car_spec->old_frame_mat, mat); - BrVector3Scale((br_vector3*)pOpponent_spec->car_spec->oldmat.m[3], (br_vector3*)pOpponent_spec->car_spec->oldmat.m[3], WORLD_SCALE); - for (i = 0; i < COUNT_OF(pOpponent_spec->car_spec->oldd); i++) { - pOpponent_spec->car_spec->oldd[i] = pOpponent_spec->car_spec->ride_height; - } - pOpponent_spec->car_spec->gear = 0; - pOpponent_spec->car_spec->revs = 0.f; - pOpponent_spec->car_spec->traction_control = 1; - BrMatrix34ApplyP(&pOpponent_spec->car_spec->pos, &pOpponent_spec->car_spec->cmpos, mat); - BrVector3InvScale(&pOpponent_spec->car_spec->pos, &pOpponent_spec->car_spec->pos, WORLD_SCALE); - BrVector3Negate(&pOpponent_spec->car_spec->direction, (br_vector3*)pOpponent_spec->car_spec->oldmat.m[3]); - pOpponent_spec->car_spec->box_face_ref = gFace_num__car - 2; - pOpponent_spec->car_spec->doing_nothing_flag = 0; - sensible_place = TestForCarInSensiblePlace(pOpponent_spec->car_spec); - if (sensible_place) { - break; - } else { - BrMatrix34Copy(mat, &original_mat); - } - if (!MassageOpponentPosition(pOpponent_spec, massage_count++)) { - break; - } - this_total++; - } - count--; - if (sensible_place) { - dr_dprintf("%s: Rematerialised (took %d attempts, orig. pos. (%7.3f,%7.3f,%7.3f), actual pos. (%7.3f,%7.3f,%7.3f))", - pOpponent_spec->car_spec->driver_name, - this_total + 1, - original_mat.m[3][0], original_mat.m[3][1], original_mat.m[3][2], - mat->m[3][0], mat->m[3][1], mat->m[3][2]); - } - if (this_total > highest) { - highest = this_total; - } - if (count != 0) { - dr_dprintf("MassageOpponentPosition() called an avg of %.1f times (max %d) per ReMaterialisation", - count / total, highest); - } - if (sensible_place) { - ResetCarSpecialVolume((tCollision_info*)pOpponent_spec->car_spec); - } else { - TurnOpponentPhysicsOff(pOpponent_spec); - RebuildActiveCarList(); - TeleportOpponentToNearestSafeLocation(pOpponent_spec); - } + return 1; } + total++; + BrMatrix34Copy(&original_mat, mat); + TurnOpponentPhysicsOn(pOpponent_spec); + RebuildActiveCarList(); + do { + count++; + this_total++; + BrVector3Scale((br_vector3*)mat->m[3], (br_vector3*)mat->m[3], WORLD_SCALE_D); + BrVector3Copy(&b, (br_vector3*)mat->m[3]); + BrMatrix34RotateY(mat, theta); + BrVector3Copy((br_vector3*)mat->m[3], &b); + BrVector3SetFloat(&b, 0.f, -100.f, 0.f); + BrVector3Copy(&a, (br_vector3*)mat->m[3]); + a.v[1] += 1.f; + findfloor(&a, &b, &norm, &dist); + a.v[1] += 100.f; + findfloor(&a, &b, &norm2, &dist2); + if (dist2 <= 1.f) { + BrVector3SetFloat(&b, 0.f, -5.01f, 0.f); + a.v[1] -= 100.f; + for (i = 0; i < 20; i++) { + a.v[1] += 5.f; + findfloor(&a, &b, &norm2, &dist2); + if (dist2 <= 1.f) { + break; + } + } + dist2 = (i + 1) * 0.05f + -dist2 / 20.f; + } + if (dist2 < dist) { + dist = -dist2; + BrVector3Copy(&norm, &norm2); + } + if (BR_ABS(dist) <= 1.f) { + mat->m[3][1] -= dist * 100.f - 2.f; + ts = BrVector3Dot((br_vector3*)mat->m[2], &norm); + phi = BrRadianToAngle(asin(ts)); + BrMatrix34PreRotateX(mat, phi); + ts = BrVector3Dot((br_vector3*)mat->m[0], &norm); + phi = -BrRadianToAngle(asin(ts)); + BrMatrix34PreRotateZ(mat, phi); + } + BrVector3Negate(&pOpponent_spec->car_spec->direction, (br_vector3*)mat->m[2]); + BrMatrix34ApplyP(&pOpponent_spec->car_spec->pos, &pOpponent_spec->car_spec->cmpos, mat); + BrVector3InvScale(&pOpponent_spec->car_spec->pos, &pOpponent_spec->car_spec->pos, WORLD_SCALE); + BrVector3InvScale((br_vector3*)mat->m[3], (br_vector3*)mat->m[3], WORLD_SCALE_D); + BrVector3Copy(&pOpponent_spec->car_spec->v, (br_vector3*)pOpponent_spec->car_spec->car_master_actor->t.t.mat.m[2]); + BrVector3Negate(&pOpponent_spec->car_spec->v, &pOpponent_spec->car_spec->v); + BrVector3Normalise(&pOpponent_spec->car_spec->v, &pOpponent_spec->car_spec->v); + BrVector3Scale(&pOpponent_spec->car_spec->v, &pOpponent_spec->car_spec->v, pSpeed * WORLD_SCALE_D); + BrVector3Set(&pOpponent_spec->car_spec->omega, 0.f, 0.f, 0.f); + pOpponent_spec->car_spec->curvature = 0.0; + BrMatrix34Copy(&pOpponent_spec->car_spec->oldmat, mat); + BrMatrix34Copy(&pOpponent_spec->car_spec->old_frame_mat, mat); + BrVector3Scale((br_vector3*)pOpponent_spec->car_spec->oldmat.m[3], (br_vector3*)pOpponent_spec->car_spec->oldmat.m[3], WORLD_SCALE); + for (j = 0; j < COUNT_OF(pOpponent_spec->car_spec->oldd); j++) { + pOpponent_spec->car_spec->oldd[j] = pOpponent_spec->car_spec->ride_height; + } + pOpponent_spec->car_spec->gear = 0; + pOpponent_spec->car_spec->revs = 0.f; + pOpponent_spec->car_spec->traction_control = 1; + BrMatrix34ApplyP(&pOpponent_spec->car_spec->pos, &pOpponent_spec->car_spec->cmpos, mat); + BrVector3InvScale(&pOpponent_spec->car_spec->pos, &pOpponent_spec->car_spec->pos, WORLD_SCALE); + BrVector3Negate(&pOpponent_spec->car_spec->direction, (br_vector3*)pOpponent_spec->car_spec->oldmat.m[3]); + pOpponent_spec->car_spec->box_face_ref = gFace_num__car - 2; + pOpponent_spec->car_spec->doing_nothing_flag = 0; + sensible_place = TestForCarInSensiblePlace(pOpponent_spec->car_spec); + if (!sensible_place) { + BrMatrix34Copy(mat, &original_mat); + } + } while (!sensible_place && MassageOpponentPosition(pOpponent_spec, massage_count++)); + + count--; + this_total--; + if (sensible_place) { + dr_dprintf("%s: Rematerialised (took %d attempts, orig. pos. (%7.3f,%7.3f,%7.3f), actual pos. (%7.3f,%7.3f,%7.3f))", + pOpponent_spec->car_spec->driver_name, + this_total + 1, + original_mat.m[3][0], original_mat.m[3][1], original_mat.m[3][2], + mat->m[3][0], mat->m[3][1], mat->m[3][2]); + } + if (this_total > highest) { + highest = this_total; + } + if (count != 0) { + dr_dprintf("MassageOpponentPosition() called an avg of %.1f times (max %d) per ReMaterialisation", + count / (float)total, highest); + } + if (!sensible_place) { + TurnOpponentPhysicsOff(pOpponent_spec); + RebuildActiveCarList(); + TeleportOpponentToNearestSafeLocation(pOpponent_spec); + return 1; + } + ResetCarSpecialVolume((tCollision_info*)pOpponent_spec->car_spec); return 1; } @@ -2242,16 +2296,18 @@ void ChallengeOccurred(int pChallenger_index, int pAccepted) { void LoadCopCars(void) { int i; - for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { - PossibleService(); - gProgram_state.AI_vehicles.cops[i].car_spec = BrMemAllocate(sizeof(tCar_spec), kMem_cop_car_spec); - LoadCar( - gBIG_APC_index == i ? "BIGAPC.TXT" : "APC.TXT", - eDriver_oppo, - gProgram_state.AI_vehicles.cops[i].car_spec, - (gBIG_APC_index == i) ? 4 : 3, - "The Cops", - &gTheir_cars_storage_space); + if (gProgram_state.AI_vehicles.number_of_cops != 0) { + for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { + PossibleService(); + gProgram_state.AI_vehicles.cops[i].car_spec = BrMemAllocate(sizeof(tCar_spec), kMem_cop_car_spec); + LoadCar( + gBIG_APC_index == i ? "BIGAPC.TXT" : "APC.TXT", + eDriver_oppo, + gProgram_state.AI_vehicles.cops[i].car_spec, + (gBIG_APC_index == i) ? 4 : 3, + "The Cops", + &gTheir_cars_storage_space); + } } } @@ -2278,10 +2334,6 @@ void LoadInOppoPaths(FILE* pF) { int sections_to_delete; int delete_these[1024]; - float x_0; - float x_1; - float x_2; - data_errors = 0; sections_to_delete = 0; dr_dprintf("Start of LoadInOppoPaths()..."); @@ -2294,66 +2346,73 @@ void LoadInOppoPaths(FILE* pF) { do { res = GetALineAndDontArgue(pF, s); } while (res && strcmp("START OF OPPONENT PATHS", s) != 0); - if (res) { + if (res == 0) { + // return; + + } else { + if (gNet_mode != eNet_mode_none) { + } ReallocExtraPathNodes(GetAnInt(pF)); - for (i = 0; i < gProgram_state.AI_vehicles.number_of_path_nodes; i++) { - GetThreeFloats(pF, &gProgram_state.AI_vehicles.path_nodes[i].p.v[0], &gProgram_state.AI_vehicles.path_nodes[i].p.v[1], &gProgram_state.AI_vehicles.path_nodes[i].p.v[2]); - gProgram_state.AI_vehicles.path_nodes[i].number_of_sections = 0; + if (gProgram_state.AI_vehicles.number_of_path_nodes != 0) { + for (node_no = 0; node_no < gProgram_state.AI_vehicles.number_of_path_nodes; node_no++) { + ReadThreeFloats(pF, x, y, z); + gProgram_state.AI_vehicles.path_nodes[node_no].p.v[0] = x; + gProgram_state.AI_vehicles.path_nodes[node_no].p.v[1] = y; + gProgram_state.AI_vehicles.path_nodes[node_no].p.v[2] = z; + gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections = 0; + } } ReallocExtraPathSections(GetAnInt(pF)); - for (i = 0; i < gProgram_state.AI_vehicles.number_of_path_sections; i++) { - PossibleService(); - GetNScalars(pF, 8, scalars); - gProgram_state.AI_vehicles.path_sections[i].node_indices[0] = scalars[0]; - gProgram_state.AI_vehicles.path_sections[i].node_indices[1] = scalars[1]; - gProgram_state.AI_vehicles.path_sections[i].min_speed[0] = scalars[2]; - gProgram_state.AI_vehicles.path_sections[i].max_speed[0] = scalars[3]; - gProgram_state.AI_vehicles.path_sections[i].min_speed[1] = scalars[4]; - gProgram_state.AI_vehicles.path_sections[i].max_speed[1] = scalars[5]; - gProgram_state.AI_vehicles.path_sections[i].width = scalars[6]; - x = gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[1]].p.v[0] - - gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[0]].p.v[0]; - y = gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[1]].p.v[1] - - gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[0]].p.v[1]; - z = gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[1]].p.v[2] - - gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[0]].p.v[2]; + if (gProgram_state.AI_vehicles.number_of_path_sections != 0) { + for (section_no = 0; section_no < gProgram_state.AI_vehicles.number_of_path_sections; section_no++) { + PossibleService(); + GetNScalars(pF, 8, scalars); + gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0] = scalars[0]; + gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1] = scalars[1]; + gProgram_state.AI_vehicles.path_sections[section_no].min_speed[0] = scalars[2]; + gProgram_state.AI_vehicles.path_sections[section_no].max_speed[0] = scalars[3]; + gProgram_state.AI_vehicles.path_sections[section_no].min_speed[1] = scalars[4]; + gProgram_state.AI_vehicles.path_sections[section_no].max_speed[1] = scalars[5]; + gProgram_state.AI_vehicles.path_sections[section_no].width = scalars[6]; - gProgram_state.AI_vehicles.path_sections[i].length = sqrt(x * x + y * y + z * z); - if (scalars[7] < 1000.0f) { - gProgram_state.AI_vehicles.path_sections[i].type = (tU8)scalars[7]; - gProgram_state.AI_vehicles.path_sections[i].one_way = 0; - } else { - gProgram_state.AI_vehicles.path_sections[i].type = (tU8)(scalars[7] - 1000.0f); - gProgram_state.AI_vehicles.path_sections[i].one_way = 1; - } - for (j = 0; j < 2; j++) { - node_ptr = &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[j]]; - if (node_ptr->number_of_sections >= 8u) { - dr_dprintf( - "ERROR: Too many sections (including section #%d) attached to node #%d", - i, - gProgram_state.AI_vehicles.path_sections[i].node_indices[j]); - data_errors = 1; + BrVector3Sub(§ion_v, + &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]].p, + &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]].p); + + gProgram_state.AI_vehicles.path_sections[section_no].length = BrVector3Length(§ion_v); + if (scalars[7] >= 1000.0f) { + gProgram_state.AI_vehicles.path_sections[section_no].type = (tU8)(scalars[7] - 1000.0f); + gProgram_state.AI_vehicles.path_sections[section_no].one_way = 1; } else { - node_ptr->sections[node_ptr->number_of_sections] = (tS16)i; - node_ptr->number_of_sections++; + gProgram_state.AI_vehicles.path_sections[section_no].type = (tU8)scalars[7]; + gProgram_state.AI_vehicles.path_sections[section_no].one_way = 0; + } + for (node_no = 0; node_no < 2; node_no++) { + node_ptr = &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[node_no]]; + if (node_ptr->number_of_sections < 8) { + node_ptr->sections[node_ptr->number_of_sections] = (tS16)section_no; + node_ptr->number_of_sections++; + } else { + dr_dprintf("ERROR: Too many sections (including section #%d) attached to node #%d", + section_no, + gProgram_state.AI_vehicles.path_sections[section_no].node_indices[node_no]); + data_errors = 1; + } + } + BrVector3Sub(§ion_v, + &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]].p, + &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]].p); + + if (BrVector3LengthSquared(§ion_v) == 0.0f) { + dr_dprintf( + "ERROR: Opponent path section #%d has zero length (nodes #%d and #%d are in same position). Secti" + "on and one node will be deleted.", + section_no, + gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0], + gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]); + delete_these[sections_to_delete] = section_no; + sections_to_delete++; } - } - x = gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[1]].p.v[0] - - gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[0]].p.v[0]; - y = gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[1]].p.v[1] - - gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[0]].p.v[1]; - z = gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[1]].p.v[2] - - gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[i].node_indices[0]].p.v[2]; - if (z * z + x * x + y * y == 0.0f) { - dr_dprintf( - "ERROR: Opponent path section #%d has zero length (nodes #%d and #%d are in same position). Secti" - "on and one node will be deleted.", - j, - gProgram_state.AI_vehicles.path_sections[i].node_indices[0], - gProgram_state.AI_vehicles.path_sections[i].node_indices[1]); - delete_these[sections_to_delete] = j; - sections_to_delete++; } } @@ -2361,12 +2420,12 @@ void LoadInOppoPaths(FILE* pF) { PDFatalError("Opponent path data inconsistencies. Unable to rectumify them."); } if (sections_to_delete != 0) { - for (j = 0; j < sections_to_delete; j++) { - dr_dprintf("Deleting section #%d (was #%d)", delete_these[j], j + delete_these[j]); - DeleteSection(delete_these[j]); + for (i = 0; i < sections_to_delete; i++) { + dr_dprintf("Deleting section #%d (was #%d)", delete_these[i], i + delete_these[i]); + DeleteSection(delete_these[i]); DeleteOrphanNodes(); - for (section_no = j; section_no < sections_to_delete; section_no++) { - delete_these[j]--; + for (j = i; j < sections_to_delete; j++) { + delete_these[i]--; } } WriteOutOppoPaths(); @@ -2379,29 +2438,29 @@ void LoadInOppoPaths(FILE* pF) { } if (gAusterity_mode || gNet_mode != eNet_mode_none) { gProgram_state.AI_vehicles.number_of_cops = GetAnInt(pF); - for (j = 0; j < gProgram_state.AI_vehicles.number_of_cops; j++) { + for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { GetALineAndDontArgue(pF, s); } gProgram_state.AI_vehicles.number_of_cops = 0; } else { gProgram_state.AI_vehicles.number_of_cops = GetAnInt(pF); - for (j = 0; j < gProgram_state.AI_vehicles.number_of_cops; j++) { - PossibleService(); - GetNScalars(pF, 6, scalars); - BrVector3Set(&gProgram_state.AI_vehicles.cop_start_points[j], scalars[0], scalars[1], scalars[2]); + if (gProgram_state.AI_vehicles.number_of_cops != 0) { + for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { + PossibleService(); + GetNScalars(pF, 6, scalars); + BrVector3Set(&gProgram_state.AI_vehicles.cop_start_points[i], scalars[0], scalars[1], scalars[2]); - if (scalars[3] == 9.0f && scalars[4] == 9.0f && scalars[5] == 9.0f) { - gBIG_APC_index = j; - } + if (scalars[3] == 9.0f && scalars[4] == 9.0f && scalars[5] == 9.0f) { + gBIG_APC_index = i; + } - FindNearestPathSection(&gProgram_state.AI_vehicles.cop_start_points[j], &cop_to_section, &intersect, &distance); - BrVector3Set(&gProgram_state.AI_vehicles.cop_start_vectors[j], - cop_to_section.v[2] * 1.0f - cop_to_section.v[1] * 0.0f, - cop_to_section.v[0] * 0.0f - cop_to_section.v[2] * 0.0f, - cop_to_section.v[1] * 0.0f - cop_to_section.v[0] * 1.0f); - BrVector3Sub(§ion_v, &intersect, &gProgram_state.AI_vehicles.cop_start_points[j]); - if (BrVector3Dot(&gProgram_state.AI_vehicles.cop_start_vectors[j], §ion_v) < 0.0f) { - BrVector3Negate(&gProgram_state.AI_vehicles.cop_start_vectors[j], &gProgram_state.AI_vehicles.cop_start_vectors[j]); + section_no = FindNearestPathSection(&gProgram_state.AI_vehicles.cop_start_points[i], §ion_v, &intersect, &distance); + BrVector3Set(&positive_y_vector, 0.0, 1.0, 0.0); + BrVector3Cross(&gProgram_state.AI_vehicles.cop_start_vectors[i], &positive_y_vector, §ion_v); + BrVector3Sub(&cop_to_section, &intersect, &gProgram_state.AI_vehicles.cop_start_points[i]); + if (BrVector3Dot(&gProgram_state.AI_vehicles.cop_start_vectors[i], &cop_to_section) < 0.0f) { + BrVector3Negate(&gProgram_state.AI_vehicles.cop_start_vectors[i], &gProgram_state.AI_vehicles.cop_start_vectors[i]); + } } } } @@ -2433,11 +2492,12 @@ void DisposeOpponentPaths(void) { if (gBit_per_node != NULL) { BrMemFree(gBit_per_node); } - gBit_per_node = NULL; + gProgram_state.AI_vehicles.number_of_path_nodes = 0; gProgram_state.AI_vehicles.number_of_path_sections = 0; gProgram_state.AI_vehicles.path_nodes = NULL; gProgram_state.AI_vehicles.path_sections = NULL; + gBit_per_node = NULL; } // IDA: void __usercall MungeOpponents(tU32 pFrame_period@) @@ -2454,79 +2514,72 @@ void MungeOpponents(tU32 pFrame_period) { gAcme_frame_count++; gTime_stamp_for_this_munging = GetTotalTime(); gFrame_period_for_this_munging = pFrame_period; - gFrame_period_for_this_munging_in_secs = pFrame_period / 1000.f; + gFrame_period_for_this_munging_in_secs = gFrame_period_for_this_munging / 1000.f; if (!gAcknowledged_start && !gCountdown) { gAcknowledged_start = 1; if (!gStart_jumped) { un_stun_flag = 1; } } - if (gProgram_state.current_car.no_of_processes_recording_my_trail == 0) { - StartRecordingTrail(&gProgram_state.current_car); - } else { + if (gProgram_state.current_car.no_of_processes_recording_my_trail != 0) { RecordNextTrailNode(&gProgram_state.current_car); + } else { + StartRecordingTrail(&gProgram_state.current_car); } TrackElasticateyPath(); - if (gProcessing_opponents) { - gNum_of_opponents_pursuing = 0; - gNum_of_opponents_getting_near = 0; - gNum_of_opponents_completing_race = 0; - for (i = 0; i < gProgram_state.AI_vehicles.number_of_opponents; i++) { - if (!gProgram_state.AI_vehicles.opponents[i].finished_for_this_race) { - switch (gProgram_state.AI_vehicles.opponents[i].current_objective) { - case eOOT_pursue_and_twat: - gNum_of_opponents_pursuing++; - break; - case eOOT_get_near_player: - gNum_of_opponents_getting_near++; - break; - case eOOT_complete_race: - gNum_of_opponents_completing_race++; - break; - default: - break; - } - } - } - for (i = 0; i < gProgram_state.AI_vehicles.number_of_opponents; i++) { - if (!gProgram_state.AI_vehicles.opponents[i].finished_for_this_race) { - if (un_stun_flag) { - UnStunTheBugger(&gProgram_state.AI_vehicles.opponents[i]); - } - CalcOpponentConspicuousnessWithAViewToCheatingLikeFuck(&gProgram_state.AI_vehicles.opponents[i]); - CalcPlayerConspicuousness(&gProgram_state.AI_vehicles.opponents[i]); - ProcessThisOpponent(&gProgram_state.AI_vehicles.opponents[i]); - ClearTwattageOccurrenceVariables(&gProgram_state.AI_vehicles.opponents[i]); - } - } - for (i = 0; i < gNumber_of_cops_before_faffage; i++) { - if (!gProgram_state.AI_vehicles.cops[i].finished_for_this_race) { - if (un_stun_flag) { - UnStunTheBugger(&gProgram_state.AI_vehicles.cops[i]); - } - CalcDistanceFromHome(&gProgram_state.AI_vehicles.cops[i]); - CalcOpponentConspicuousnessWithAViewToCheatingLikeFuck(&gProgram_state.AI_vehicles.cops[i]); - CalcPlayerConspicuousness(&gProgram_state.AI_vehicles.cops[i]); - ProcessThisOpponent(&gProgram_state.AI_vehicles.cops[i]); - ClearTwattageOccurrenceVariables(&gProgram_state.AI_vehicles.cops[i]); - gProgram_state.AI_vehicles.cops[i].murder_reported = 0; - } - } - if (gNext_grudge_reduction < gTime_stamp_for_this_munging) { - gNext_grudge_reduction = gTime_stamp_for_this_munging + 3000; - for (i = 0; i < gProgram_state.AI_vehicles.number_of_opponents; i++) { - if (!gProgram_state.AI_vehicles.opponents[i].finished_for_this_race) { - if (gOpponents[gProgram_state.AI_vehicles.opponents[i].index].psyche.grudge_against_player >= gGrudge_reduction_per_period) { - gOpponents[gProgram_state.AI_vehicles.opponents[i].index].psyche.grudge_against_player -= gGrudge_reduction_per_period; - } else { - gOpponents[gProgram_state.AI_vehicles.opponents[i].index].psyche.grudge_against_player = 0; - } - } - } - } - RebuildActiveCarList(); - gFirst_frame = 0; + if (!gProcessing_opponents) { + return; } + gNum_of_opponents_pursuing = 0; + gNum_of_opponents_getting_near = 0; + gNum_of_opponents_completing_race = 0; + for (i = 0; i < gProgram_state.AI_vehicles.number_of_opponents; i++) { + if (!gProgram_state.AI_vehicles.opponents[i].finished_for_this_race) { + if (gProgram_state.AI_vehicles.opponents[i].current_objective == eOOT_pursue_and_twat) { + gNum_of_opponents_pursuing++; + } else if (gProgram_state.AI_vehicles.opponents[i].current_objective == eOOT_get_near_player) { + + gNum_of_opponents_getting_near++; + + } else if (gProgram_state.AI_vehicles.opponents[i].current_objective == eOOT_complete_race) { + gNum_of_opponents_completing_race++; + } + } + } + for (i = 0; i < gProgram_state.AI_vehicles.number_of_opponents; i++) { + if (!gProgram_state.AI_vehicles.opponents[i].finished_for_this_race) { + if (un_stun_flag) { + UnStunTheBugger(&gProgram_state.AI_vehicles.opponents[i]); + } + CalcOpponentConspicuousnessWithAViewToCheatingLikeFuck(&gProgram_state.AI_vehicles.opponents[i]); + CalcPlayerConspicuousness(&gProgram_state.AI_vehicles.opponents[i]); + ProcessThisOpponent(&gProgram_state.AI_vehicles.opponents[i]); + ClearTwattageOccurrenceVariables(&gProgram_state.AI_vehicles.opponents[i]); + } + } + for (i = 0; i < gNumber_of_cops_before_faffage; i++) { + if (!gProgram_state.AI_vehicles.cops[i].finished_for_this_race) { + if (un_stun_flag) { + UnStunTheBugger(&gProgram_state.AI_vehicles.cops[i]); + } + CalcDistanceFromHome(&gProgram_state.AI_vehicles.cops[i]); + CalcOpponentConspicuousnessWithAViewToCheatingLikeFuck(&gProgram_state.AI_vehicles.cops[i]); + CalcPlayerConspicuousness(&gProgram_state.AI_vehicles.cops[i]); + ProcessThisOpponent(&gProgram_state.AI_vehicles.cops[i]); + ClearTwattageOccurrenceVariables(&gProgram_state.AI_vehicles.cops[i]); + gProgram_state.AI_vehicles.cops[i].murder_reported = 0; + } + } + if (gNext_grudge_reduction < gTime_stamp_for_this_munging) { + gNext_grudge_reduction = gTime_stamp_for_this_munging + 3000; + for (i = 0; i < gProgram_state.AI_vehicles.number_of_opponents; i++) { + if (!gProgram_state.AI_vehicles.opponents[i].finished_for_this_race) { + gOpponents[gProgram_state.AI_vehicles.opponents[i].index].psyche.grudge_against_player -= MIN(gOpponents[gProgram_state.AI_vehicles.opponents[i].index].psyche.grudge_against_player, gGrudge_reduction_per_period); + } + } + } + RebuildActiveCarList(); + gFirst_frame = 0; } // IDA: void __cdecl SetInitialCopPositions() @@ -2552,8 +2605,6 @@ void InitOpponents(tRace_info* pRace_info) { int rank_dependent_difficulty; int skill_dependent_difficulty; br_bounds bounds; - tCar_spec* car_spec; - tOpponent_spec* opponent_spec; gNext_grudge_reduction = gTime_stamp_for_this_munging + 8000; gGrudge_reduction_per_period = 3 - gProgram_state.skill_level; @@ -2561,29 +2612,28 @@ void InitOpponents(tRace_info* pRace_info) { gFirst_frame = 1; gAcknowledged_start = 0; gStart_jumped = 0; - gViewable_car_list[0] = &gProgram_state.current_car; - gNum_viewable_cars = 1; + gNum_viewable_cars = 0; + gViewable_car_list[gNum_viewable_cars] = &gProgram_state.current_car; + gNum_viewable_cars++; BrActorToBounds(&bounds, gProgram_state.track_spec.the_actor); gMinimum_yness_before_knackerisation = bounds.min.v[1] - 2.f; gDefinite_no_cop_pursuit_speed = 17.8788f; gDefinite_cop_pursuit_speed = 44.697f; gCop_pursuit_speed_percentage_multiplier = 100.f / (gDefinite_cop_pursuit_speed - gDefinite_no_cop_pursuit_speed); - gHead_on_cos_value = cos(.5235668f); + gHead_on_cos_value = cos(0.5235668420791626f); gAcme_frame_count = 0; gProgram_state.current_car.no_of_processes_recording_my_trail = 0; - rank_dependent_difficulty = (101.f - (gCurrent_race.suggested_rank < 10 ? .5f : gCurrent_race.suggested_rank)) / 10.0f; - gBig_bang = 70.f - (3 * rank_dependent_difficulty + 10 * gProgram_state.skill_level) * gOpponent_nastyness_frigger; - gIn_view_distance = gCamera_yon + 10.f; - if (gCamera_yon + 10.f <= 45.f) { - gIn_view_distance = 45.f; - } + rank_dependent_difficulty = (101.0 - (gCurrent_race.suggested_rank < 10 ? 0.5 : gCurrent_race.suggested_rank)) / 10.0; + skill_dependent_difficulty = gProgram_state.skill_level * 5; + gBig_bang = 70.f - (2 * skill_dependent_difficulty + 3 * rank_dependent_difficulty) * gOpponent_nastyness_frigger; + gIn_view_distance = MAX(gCamera_yon + 10.f, 45.f); gTime_stamp_for_this_munging = GetTotalTime(); gFrame_period_for_this_munging = 1; gFrame_period_for_this_munging_in_secs = gFrame_period_for_this_munging / 1000.f; - if (gNet_mode == eNet_mode_none) { - gProgram_state.AI_vehicles.number_of_opponents = pRace_info->number_of_racers - 1; - } else { + if (gNet_mode != eNet_mode_none) { gProgram_state.AI_vehicles.number_of_opponents = 0; + } else { + gProgram_state.AI_vehicles.number_of_opponents = pRace_info->number_of_racers - 1; } gNumber_of_cops_before_faffage = gProgram_state.AI_vehicles.number_of_cops; for (i = 0, opponent_number = 0; i < gProgram_state.AI_vehicles.number_of_opponents; i++, opponent_number++) { @@ -2592,7 +2642,7 @@ void InitOpponents(tRace_info* pRace_info) { opponent_number++; } gProgram_state.AI_vehicles.opponents[i].car_spec = pRace_info->opponent_list[opponent_number].car_spec; - gProgram_state.AI_vehicles.opponents[i].car_spec->car_ID = i | 0x200; + gProgram_state.AI_vehicles.opponents[i].car_spec->car_ID = i + 0x200; dr_dprintf("Car '%s', car_ID %x", gProgram_state.AI_vehicles.opponents[i].car_spec->driver_name, gProgram_state.AI_vehicles.opponents[i].car_spec->car_ID); @@ -2623,10 +2673,11 @@ void InitOpponents(tRace_info* pRace_info) { gProgram_state.AI_vehicles.opponents[i].has_moved_at_some_point = 0; gProgram_state.AI_vehicles.opponents[i].player_in_view_now = 0; gProgram_state.AI_vehicles.opponents[i].acknowledged_piv = 0; - gProgram_state.AI_vehicles.opponents[i].nastiness = (gProgram_state.skill_level / 2.f - + ((float)(gOpponents[gProgram_state.AI_vehicles.opponents[i].index].strength_rating - 1)) / 4.f - + (99.f - (gCurrent_race.suggested_rank < 10 ? .5f : (float)gCurrent_race.suggested_rank)) / 98.f) - / 3.f * gOpponent_nastyness_frigger; + + gProgram_state.AI_vehicles.opponents[i].nastiness = ((99.0 - (gCurrent_race.suggested_rank < 10 ? 0.5 : gCurrent_race.suggested_rank)) / 98.0 + + (gOpponents[gProgram_state.AI_vehicles.opponents[i].index].strength_rating - 1) / 4.0 + + gProgram_state.skill_level / 2.0) + / 3.0 * gOpponent_nastyness_frigger; BrVector3Set(&gProgram_state.AI_vehicles.opponents[i].pos_last_frame, 0.f, 0.f, 0.f); gOpponents[gProgram_state.AI_vehicles.opponents[i].index].psyche.grudge_against_player = 10; gViewable_car_list[gNum_viewable_cars] = gProgram_state.AI_vehicles.opponents[i].car_spec; @@ -2634,18 +2685,20 @@ void InitOpponents(tRace_info* pRace_info) { StunTheBugger(&gProgram_state.AI_vehicles.opponents[i], 10000); } if (gChallenger_index__opponent >= 0) { + tCar_spec* car_spec; + tOpponent_spec* opponent_spec; car_spec = GetCarSpecFromGlobalOppoIndex(gChallenger_index__opponent); opponent_spec = GetOpponentSpecFromCarSpec(car_spec); - if (opponent_spec == NULL) { - dr_dprintf("ERROR - can't record dare - no opponent_spec for car_spec"); - } else { + if (opponent_spec != NULL) { opponent_spec->pursue_from_start = 1; + } else { + dr_dprintf("ERROR - can't record dare - no opponent_spec for car_spec"); } gChallenger_index__opponent = -1; } for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { PossibleService(); - gProgram_state.AI_vehicles.cops[i].car_spec->car_ID = i | 0x300; + gProgram_state.AI_vehicles.cops[i].car_spec->car_ID = i + 0x300; gProgram_state.AI_vehicles.cops[i].index = 3; gProgram_state.AI_vehicles.cops[i].time_last_processed = gTime_stamp_for_this_munging; gProgram_state.AI_vehicles.cops[i].time_this_objective_started = gTime_stamp_for_this_munging; @@ -2668,10 +2721,15 @@ void InitOpponents(tRace_info* pRace_info) { gProgram_state.AI_vehicles.cops[i].has_moved_at_some_point = 0; gProgram_state.AI_vehicles.cops[i].player_in_view_now = 0; gProgram_state.AI_vehicles.cops[i].acknowledged_piv = 0; - gProgram_state.AI_vehicles.cops[i].nastiness = (gProgram_state.skill_level / 2.f - + (99.f - (gCurrent_race.suggested_rank < 10 ? .5f : (float)gCurrent_race.suggested_rank)) / 98.f - + 2.25f) +#ifdef DETHRACE_FIX_BUGS + gProgram_state.AI_vehicles.cops[i].nastiness = +#else + gProgram_state.AI_vehicles.opponents[i].nastiness = +#endif + ((99.0 - (gCurrent_race.suggested_rank < 10 ? 0.5 : gCurrent_race.suggested_rank)) / 98.0 + + gProgram_state.skill_level / 2.0 + 2.25) / 3.f * gOpponent_nastyness_frigger; + BrVector3Copy(&gProgram_state.AI_vehicles.cops[i].start_pos, &gProgram_state.AI_vehicles.cop_start_points[i]); BrVector3Copy(&gProgram_state.AI_vehicles.cops[i].start_direction, &gProgram_state.AI_vehicles.cop_start_vectors[i]); BrVector3Set(&gProgram_state.AI_vehicles.cops[i].pos_last_frame, 0.f, 0.f, 0.f); @@ -2681,6 +2739,7 @@ void InitOpponents(tRace_info* pRace_info) { gProgram_state.AI_vehicles.cops[i].car_spec->last_person_we_hit = NULL; gProgram_state.AI_vehicles.cops[i].car_spec->last_collision_time = 0; gProgram_state.AI_vehicles.cops[i].car_spec->last_time_we_touched_a_player = 0; + gProgram_state.AI_vehicles.cops[i].car_spec->no_of_processes_recording_my_trail = 0; gProgram_state.AI_vehicles.cops[i].car_spec->grudge_raised_recently = 1; gOpponents[gProgram_state.AI_vehicles.cops[i].index].psyche.grudge_against_player = 10; StunTheBugger(&gProgram_state.AI_vehicles.cops[i], 10000); @@ -2693,10 +2752,11 @@ void InitOpponents(tRace_info* pRace_info) { // FUNCTION: CARM95 0x0040b186 void DisposeOpponents(void) { int i; - - for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { - DisposeCar(gProgram_state.AI_vehicles.cops[i].car_spec, (i == gBIG_APC_index) ? 4 : 3); - BrMemFree(gProgram_state.AI_vehicles.cops[i].car_spec); + if (gProgram_state.AI_vehicles.number_of_cops != 0) { + for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { + DisposeCar(gProgram_state.AI_vehicles.cops[i].car_spec, (i == gBIG_APC_index) ? 4 : 3); + BrMemFree(gProgram_state.AI_vehicles.cops[i].car_spec); + } } } @@ -2707,22 +2767,14 @@ void WakeUpOpponentsToTheFactThatTheStartHasBeenJumped(int pWhat_the_countdown_w for (i = 0; i < gProgram_state.AI_vehicles.number_of_opponents; i++) { UnStunTheBugger(&gProgram_state.AI_vehicles.opponents[i]); - if (IRandomBetween(1000, 2500) < 1000 * pWhat_the_countdown_was) { - StunTheBugger(&gProgram_state.AI_vehicles.opponents[i], IRandomBetween(1000, 2500)); - } else { - StunTheBugger(&gProgram_state.AI_vehicles.opponents[i], 1000 * pWhat_the_countdown_was); - } + StunTheBugger(&gProgram_state.AI_vehicles.opponents[i], MIN(IRandomBetween(1000, 2500), 1000 * pWhat_the_countdown_was)); } for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { UnStunTheBugger(&gProgram_state.AI_vehicles.cops[i]); - if (IRandomBetween(1000, 2500) < 1000 * pWhat_the_countdown_was) { - StunTheBugger(&gProgram_state.AI_vehicles.cops[i], IRandomBetween(1000, 2500)); - } else { - StunTheBugger(&gProgram_state.AI_vehicles.cops[i], 1000 * pWhat_the_countdown_was); - } + StunTheBugger(&gProgram_state.AI_vehicles.cops[i], MIN(IRandomBetween(1000, 2500), 1000 * pWhat_the_countdown_was)); } - gStart_jumped = 1; gAcknowledged_start = 1; + gStart_jumped = 1; } // IDA: void __usercall ReportMurderToPoliceDepartment(tCar_spec *pCar_spec@) @@ -2745,16 +2797,12 @@ int GetCarCount(tVehicle_type pCategory) { case eVehicle_self: return 1; - case eVehicle_net_player: - if (gNet_mode) { - return gNumber_of_net_players - 1; - } else { - return 0; - } - break; case eVehicle_opponent: return gProgram_state.AI_vehicles.number_of_opponents; + case eVehicle_net_player: + return gNet_mode ? gNumber_of_net_players - 1 : 0; + case eVehicle_rozzer: return gNumber_of_cops_before_faffage; @@ -2763,10 +2811,9 @@ int GetCarCount(tVehicle_type pCategory) { case eVehicle_not_really: return gNum_active_non_cars; - - default: - return 0; } + + return 0; } // IDA: tCar_spec* __usercall GetCarSpec@(tVehicle_type pCategory@, int pIndex@) @@ -2779,11 +2826,7 @@ tCar_spec* GetCarSpec(tVehicle_type pCategory, int pIndex) { return &gProgram_state.current_car; case eVehicle_net_player: - if (gThis_net_player_index > pIndex) { - return gNet_players[pIndex].car; - } else { - return gNet_players[pIndex + 1].car; - } + return pIndex >= gThis_net_player_index ? gNet_players[pIndex + 1].car : gNet_players[pIndex].car; case eVehicle_opponent: return gProgram_state.AI_vehicles.opponents[pIndex].car_spec; @@ -2797,10 +2840,8 @@ tCar_spec* GetCarSpec(tVehicle_type pCategory, int pIndex) { case eVehicle_not_really: return (tCar_spec*)gActive_non_car_list[pIndex]; - - default: - return 0; } + return 0; } // IDA: char* __usercall GetDriverName@(tVehicle_type pCategory@, int pIndex@) @@ -2813,13 +2854,18 @@ char* GetDriverName(tVehicle_type pCategory, int pIndex) { case eVehicle_opponent: return gOpponents[gProgram_state.AI_vehicles.opponents[pIndex].index].name; case eVehicle_rozzer: - return "Faceless Cop"; + return gCop_name; case eVehicle_drone: - return "Innocent Civilian"; + return gDrone_name; case eVehicle_not_really: - default: return NULL; + +#ifdef DETHRACE_FIX_BUGS + default: + break; +#endif } + return NULL; } // IDA: tOpponent_spec* __usercall GetOpponentSpecFromCarSpec@(tCar_spec *pCar_spec@) @@ -2827,13 +2873,13 @@ char* GetDriverName(tVehicle_type pCategory, int pIndex) { tOpponent_spec* GetOpponentSpecFromCarSpec(tCar_spec* pCar_spec) { int i; - if ((pCar_spec->car_ID & 0xff00) == 0x200) { + if (CAR_SPEC_IS_OPPONENT(pCar_spec)) { for (i = 0; i < GetCarCount(eVehicle_opponent); i++) { if (gProgram_state.AI_vehicles.opponents[i].car_spec == pCar_spec) { return &gProgram_state.AI_vehicles.opponents[i]; } } - } else if ((pCar_spec->car_ID & 0xff00) == 0x300) { + } else if (CAR_SPEC_IS_ROZZER(pCar_spec)) { for (i = 0; i < GetCarCount(eVehicle_rozzer); i++) { if (gProgram_state.AI_vehicles.cops[i].car_spec == pCar_spec) { return &gProgram_state.AI_vehicles.cops[i]; @@ -2862,25 +2908,22 @@ int GetOpponentsRealSection(tOpponent_spec* pOpponent_spec, int pSection_no) { if (pSection_no >= 20000) { return pOpponent_spec->next_sections[pSection_no - 20000].section_no; - } else if (pSection_no >= 10000) { - return -1; - } else { + } else if (pSection_no < 10000) { return pSection_no; } + return -1; } // IDA: int __usercall GetOpponentsFirstSection@(tOpponent_spec *pOpponent_spec@) // FUNCTION: CARM95 0x0040b806 int GetOpponentsFirstSection(tOpponent_spec* pOpponent_spec) { - if (pOpponent_spec->current_objective != eOOT_pursue_and_twat) { - return 20000; - } - if (pOpponent_spec->pursue_car_data.state == ePCS_following_trail) { - return pOpponent_spec->follow_path_data.section_no; - } - if (pOpponent_spec->pursue_car_data.state == ePCS_following_line_of_sight) { - return 10000; + if (pOpponent_spec->current_objective == eOOT_pursue_and_twat) { + if (pOpponent_spec->pursue_car_data.state == ePCS_following_trail) { + return pOpponent_spec->follow_path_data.section_no; + } else if (pOpponent_spec->pursue_car_data.state == ePCS_following_line_of_sight) { + return 10000; + } } return 20000; } @@ -2888,18 +2931,15 @@ int GetOpponentsFirstSection(tOpponent_spec* pOpponent_spec) { // IDA: int __usercall GetOpponentsNextSection@(tOpponent_spec *pOpponent_spec@, tS16 pCurrent_section@) // FUNCTION: CARM95 0x0040b86e int GetOpponentsNextSection(tOpponent_spec* pOpponent_spec, tS16 pCurrent_section) { - - if (pCurrent_section < 20000) { - if (pCurrent_section < 15000) { - return -1; - } else { - return CalcNextTrailSection(pOpponent_spec, pCurrent_section); + if (pCurrent_section >= 20000) { + if (pCurrent_section - 19999 < pOpponent_spec->nnext_sections && (pOpponent_spec->cheating || gProgram_state.AI_vehicles.path_sections[pCurrent_section - 19999].type != ePST_cheat_only)) { + return pCurrent_section + 1; } - } else if (pCurrent_section - 19999 >= pOpponent_spec->nnext_sections || (!pOpponent_spec->cheating && gProgram_state.AI_vehicles.path_sections[pCurrent_section - 19999].type == ePST_cheat_only)) { return -1; - } else { - return pCurrent_section + 1; + } else if (pCurrent_section >= 15000) { + return CalcNextTrailSection(pOpponent_spec, pCurrent_section); } + return -1; } // IDA: tS16 __usercall GetOpponentsSectionStartNode@(tOpponent_spec *pOpponent_spec@, tS16 pSection@) @@ -2909,16 +2949,11 @@ tS16 GetOpponentsSectionStartNode(tOpponent_spec* pOpponent_spec, tS16 pSection) int node_index_index; if (pSection >= 20000 && pSection - 20000 < pOpponent_spec->nnext_sections) { + section_no = pOpponent_spec->next_sections[pSection - 20000].section_no; node_index_index = pOpponent_spec->next_sections[pSection - 20000].direction == 0; - if (pSection - 20000 > pOpponent_spec->nnext_sections) { - section_no = -1; - } else { - section_no = gProgram_state.AI_vehicles.path_sections[pOpponent_spec->next_sections[pSection - 20000].section_no].node_indices[node_index_index]; - return section_no; - } + return pOpponent_spec->nnext_sections >= pSection - 20000 ? gProgram_state.AI_vehicles.path_sections[section_no].node_indices[node_index_index] : -1; } - dr_dprintf("BIG ERROR - GetOpponentsSectionStartNode() - section not found in next_section array for opponent %s", - pOpponent_spec->car_spec->driver_name); + dr_dprintf("BIG ERROR - GetOpponentsSectionStartNode() - section not found in next_section array for opponent %s", pOpponent_spec->car_spec->driver_name); PDEnterDebugger("BIG ERROR - GetOpponentsSectionStartNode()"); return -1; } @@ -2930,12 +2965,13 @@ tS16 GetOpponentsSectionFinishNode(tOpponent_spec* pOpponent_spec, tS16 pSection int node_index_index; if (pSection >= 20000 && pSection - 20000 < pOpponent_spec->nnext_sections) { - return gProgram_state.AI_vehicles.path_sections[pOpponent_spec->next_sections[pSection - 20000].section_no].node_indices[pOpponent_spec->next_sections[pSection - 20000].direction]; + section_no = pOpponent_spec->next_sections[pSection - 20000].section_no; + node_index_index = pOpponent_spec->next_sections[pSection - 20000].direction; + return gProgram_state.AI_vehicles.path_sections[section_no].node_indices[node_index_index]; } - dr_dprintf("BIG ERROR - GetOpponentsSectionFinishNode() - section not found in next_section array for opponent %s", - pOpponent_spec->car_spec->driver_name); + dr_dprintf("BIG ERROR - GetOpponentsSectionFinishNode() - section not found in next_section array for opponent %s", pOpponent_spec->car_spec->driver_name); PDEnterDebugger("BIG ERROR - GetOpponentsSectionFinishNode()"); - return 0; + return -1; } // IDA: br_vector3* __usercall GetOpponentsSectionStartNodePoint@(tOpponent_spec *pOpponent_spec@, tS16 pSection@) @@ -2947,20 +2983,17 @@ br_vector3* GetOpponentsSectionStartNodePoint(tOpponent_spec* pOpponent_spec, tS if (pSection >= 20000 && pOpponent_spec->nnext_sections > pSection - 20000) { section_no = pOpponent_spec->next_sections[pSection - 20000].section_no; - node_index_index = pOpponent_spec->next_sections[pSection - 20000].direction; - node_no = gProgram_state.AI_vehicles.path_sections[section_no].node_indices[node_index_index == 0]; + node_index_index = pOpponent_spec->next_sections[pSection - 20000].direction == 0; + node_no = gProgram_state.AI_vehicles.path_sections[section_no].node_indices[node_index_index]; return &gProgram_state.AI_vehicles.path_nodes[node_no].p; - } - - if (pSection >= 15000) { + } else if (pSection >= 15000) { return &pOpponent_spec->pursue_car_data.pursuee->my_trail.trail_nodes[pSection - 15000]; - } - if (pSection == 10000) { + } else if (pSection == 10000) { return &pOpponent_spec->pursue_car_data.direct_line_nodes[0].p; } dr_dprintf("BIG ERROR - GetOpponentsSectionStartNodePoint() - section not found in next_section array for opponent %s", pOpponent_spec->car_spec->driver_name); PDEnterDebugger("BIG ERROR - GetOpponentsSectionStartNodePoint()"); - return 0; + return NULL; } // IDA: br_vector3* __usercall GetOpponentsSectionFinishNodePoint@(tOpponent_spec *pOpponent_spec@, tS16 pSection@) @@ -2979,12 +3012,11 @@ br_vector3* GetOpponentsSectionFinishNodePoint(tOpponent_spec* pOpponent_spec, t return &pOpponent_spec->pursue_car_data.pursuee->my_trail.trail_nodes[(pSection + 1) - 15000]; } else if (pSection == 10000) { return &pOpponent_spec->pursue_car_data.direct_line_nodes[1].p; - } else { - dr_dprintf("BIG ERROR - GetOpponentsSectionFinishNodePoint() - section not found in next_section array for opponent %s", - pOpponent_spec->car_spec->driver_name); - PDEnterDebugger("BIG ERROR - GetOpponentsSectionFinishNodePoint()"); - return NULL; } + dr_dprintf("BIG ERROR - GetOpponentsSectionFinishNodePoint() - section not found in next_section array for opponent %s", + pOpponent_spec->car_spec->driver_name); + PDEnterDebugger("BIG ERROR - GetOpponentsSectionFinishNodePoint()"); + return NULL; } // IDA: br_scalar __usercall GetOpponentsSectionWidth@(tOpponent_spec *pOpponent_spec@, tS16 pSection@) @@ -2993,11 +3025,9 @@ br_scalar GetOpponentsSectionWidth(tOpponent_spec* pOpponent_spec, tS16 pSection if (pSection >= 20000 && pSection - 20000 < pOpponent_spec->nnext_sections) { return gProgram_state.AI_vehicles.path_sections[pOpponent_spec->next_sections[pSection - 20000].section_no].width; - } - if (pSection >= 15000) { + } else if (pSection >= 15000) { return 0.5f; - } - if (pSection == 10000) { + } else if (pSection == 10000) { return pOpponent_spec->pursue_car_data.direct_line_section.width; } return gProgram_state.AI_vehicles.path_sections[pSection].width; @@ -3012,12 +3042,10 @@ int GetOpponentsSectionMinSpeed(tOpponent_spec* pOpponent_spec, tS16 pSection, i if (pSection >= 20000 && pSection - 20000 < pOpponent_spec->nnext_sections) { section_no = pOpponent_spec->next_sections[pSection - 20000].section_no; direction = pOpponent_spec->next_sections[pSection - 20000].direction; - return gProgram_state.AI_vehicles.path_sections[section_no].min_speed[pTowards_finish == direction]; - } - if (pSection >= 15000) { + return gProgram_state.AI_vehicles.path_sections[section_no].min_speed[(direction ^ pTowards_finish) == 0]; + } else if (pSection >= 15000) { return 0; - } - if (pSection == 10000) { + } else if (pSection == 10000) { return pOpponent_spec->pursue_car_data.direct_line_section.min_speed[pTowards_finish]; } dr_dprintf("WARNING - GetOpponentsSectionMinSpeed() - section not found in next_section array for opponent %s", pOpponent_spec->car_spec->driver_name); @@ -3034,12 +3062,10 @@ int GetOpponentsSectionMaxSpeed(tOpponent_spec* pOpponent_spec, tS16 pSection, i if (pSection >= 20000 && pSection - 20000 < pOpponent_spec->nnext_sections) { section_no = pOpponent_spec->next_sections[pSection - 20000].section_no; direction = pOpponent_spec->next_sections[pSection - 20000].direction; - return gProgram_state.AI_vehicles.path_sections[section_no].max_speed[pTowards_finish == direction]; - } - if (pSection >= 15000) { + return gProgram_state.AI_vehicles.path_sections[section_no].max_speed[(direction ^ pTowards_finish) == 0]; + } else if (pSection >= 15000) { return 255; - } - if (pSection == 10000) { + } else if (pSection == 10000) { return pOpponent_spec->pursue_car_data.direct_line_section.max_speed[pTowards_finish]; } dr_dprintf("WARNING - GetOpponentsSectionMaxSpeed() - section not found in next_section array for opponent %s", pOpponent_spec->car_spec->driver_name); @@ -3050,6 +3076,8 @@ int GetOpponentsSectionMaxSpeed(tOpponent_spec* pOpponent_spec, tS16 pSection, i // IDA: void __usercall InitOpponentPsyche(int pOpponent_index@) // FUNCTION: CARM95 0x0040bf68 void InitOpponentPsyche(int pOpponent_index) { + int i; + gOpponents[pOpponent_index].psyche.grudge_against_player = 0; } @@ -3093,7 +3121,7 @@ void RecordOpponentTwattageOccurrence(tCar_spec* pTwatter, tCar_spec* pTwattee) return; } damage = pTwattee->damage_magnitude_accumulator; - bangness = MIN(sqrt(damage * 300000.0f), 100); + bangness = MIN(sqrt(damage * 300000.0), 100); grudginess_caused_by_damage = bangness / 10 + 50 * CAR_SPEC_IS_ROZZER(pTwattee); dr_dprintf("Frame %0.6d: %s hit %s, damage %f, bangness %d, gBig_bang %d, grudginess %d", gAcme_frame_count, @@ -3103,65 +3131,68 @@ void RecordOpponentTwattageOccurrence(tCar_spec* pTwatter, tCar_spec* pTwattee) bangness, gBig_bang, grudginess_caused_by_damage); - if (gMin_bangness <= bangness) { + if (gMin_bangness > bangness) { + gMin_bangness = bangness; + dr_dprintf("(New gMin_bangness - %d)", gMin_bangness); + } else { if (gMax_bangness < bangness) { gMax_bangness = bangness; - dr_dprintf("(New gMax_bangness - %d)", bangness); + dr_dprintf("(New gMax_bangness - %d)", gMax_bangness); } - } else { - gMin_bangness = bangness; - dr_dprintf("(New gMin_bangness - %d)", bangness); } - if (bangness >= 5) { - pTwatter->last_collision_time = gTime_stamp_for_this_munging; - pTwatter->last_person_we_hit = pTwattee; - pTwattee->last_collision_time = gTime_stamp_for_this_munging; - pTwattee->last_person_to_hit_us = pTwatter; - pTwattee->grudge_raised_recently = 1; - if (bangness >= gBig_bang || CAR_SPEC_IS_ROZZER(pTwattee)) { - pTwattee->big_bang = 1; + if (bangness < 5) { + return; + } + pTwatter->last_collision_time = gTime_stamp_for_this_munging; + pTwatter->last_person_we_hit = pTwattee; + pTwattee->last_collision_time = gTime_stamp_for_this_munging; + pTwattee->last_person_to_hit_us = pTwatter; + pTwattee->grudge_raised_recently = 1; + if (bangness >= gBig_bang || CAR_SPEC_IS_ROZZER(pTwattee)) { + pTwattee->big_bang = 1; + } + if (bangness >= 80) { + pTwattee->scary_bang = 1; + } + if (pTwatter->driver == eDriver_local_human) { + twattee_opponent_spec = GetOpponentSpecFromCarSpec(pTwattee); + if (pTwattee->scary_bang) { + StunTheBugger(twattee_opponent_spec, 30 * MIN(bangness, 100) + 1000); } - if (bangness >= 80) { - pTwattee->scary_bang = 1; + twattee_index = twattee_opponent_spec->index; + new_grudge_value = grudginess_caused_by_damage + gOpponents[twattee_index].psyche.grudge_against_player; + if (new_grudge_value > 100) { + new_grudge_value = 100; } - if (pTwatter->driver == eDriver_local_human) { - twattee_opponent_spec = GetOpponentSpecFromCarSpec(pTwattee); - if (pTwattee->scary_bang) { - StunTheBugger(twattee_opponent_spec, 30 * bangness + 1000); - } - new_grudge_value = grudginess_caused_by_damage + gOpponents[twattee_opponent_spec->index].psyche.grudge_against_player; + gOpponents[twattee_index].psyche.grudge_against_player = new_grudge_value; + } else if (pTwattee->driver == eDriver_local_human) { + twatter_opponent_spec = GetOpponentSpecFromCarSpec(pTwatter); + if (twatter_opponent_spec->current_objective == eOOT_pursue_and_twat && twatter_opponent_spec->pursue_car_data.pursuee == pTwattee) { + twatter_opponent_spec->pursue_car_data.time_last_twatted_em = gTime_stamp_for_this_munging; + } + twatter_index = twatter_opponent_spec->index; + new_grudge_value = gOpponents[twatter_index].psyche.grudge_against_player - (twatter_opponent_spec->current_objective == eOOT_pursue_and_twat ? 0 : 2 * grudginess_caused_by_damage); + if (new_grudge_value < 0) { + new_grudge_value = 0; + } + gOpponents[twatter_index].psyche.grudge_against_player = new_grudge_value; + } else { + twatter_opponent_spec = GetOpponentSpecFromCarSpec(pTwatter); + twattee_opponent_spec = GetOpponentSpecFromCarSpec(pTwattee); + if (pTwattee->scary_bang) { + StunTheBugger(twattee_opponent_spec, 30 * bangness + 1000); + } + twatter_index = twatter_opponent_spec->index; + twattee_index = twattee_opponent_spec->index; + if (twatter_opponent_spec->current_objective == eOOT_pursue_and_twat && twatter_opponent_spec->pursue_car_data.pursuee == pTwattee) { + twatter_opponent_spec->pursue_car_data.time_last_twatted_em = gTime_stamp_for_this_munging; + } + if (CAR_SPEC_IS_OPPONENT(pTwatter) && CAR_SPEC_IS_ROZZER(pTwattee)) { + new_grudge_value = grudginess_caused_by_damage + gOpponents[twattee_index].psyche.grudge_against_player; if (new_grudge_value > 100) { new_grudge_value = 100; } - gOpponents[twattee_opponent_spec->index].psyche.grudge_against_player = new_grudge_value; - } else if (pTwattee->driver == eDriver_local_human) { - twatter_opponent_spec = GetOpponentSpecFromCarSpec(pTwatter); - if (twatter_opponent_spec->current_objective == eOOT_pursue_and_twat && twatter_opponent_spec->pursue_car_data.pursuee == pTwattee) { - twatter_opponent_spec->pursue_car_data.time_last_twatted_em = gTime_stamp_for_this_munging; - } - twatter_index = twatter_opponent_spec->index; - new_grudge_value = gOpponents[twatter_index].psyche.grudge_against_player - (twatter_opponent_spec->current_objective == eOOT_pursue_and_twat ? 0 : 2 * grudginess_caused_by_damage); - if (new_grudge_value < 0) { - new_grudge_value = 0; - } - gOpponents[twatter_index].psyche.grudge_against_player = new_grudge_value; - } else { - twatter_opponent_spec = GetOpponentSpecFromCarSpec(pTwatter); - twattee_opponent_spec = GetOpponentSpecFromCarSpec(pTwattee); - if (pTwattee->scary_bang) { - StunTheBugger(twattee_opponent_spec, 30 * bangness + 1000); - } - twattee_index = twattee_opponent_spec->index; - if (twatter_opponent_spec->current_objective == eOOT_pursue_and_twat && twatter_opponent_spec->pursue_car_data.pursuee == pTwattee) { - twatter_opponent_spec->pursue_car_data.time_last_twatted_em = gTime_stamp_for_this_munging; - } - if (CAR_SPEC_IS_OPPONENT(pTwatter) && CAR_SPEC_IS_ROZZER(pTwattee)) { - new_grudge_value = grudginess_caused_by_damage + gOpponents[twattee_index].psyche.grudge_against_player; - if (new_grudge_value > 100) { - new_grudge_value = 100; - } - gOpponents[twattee_index].psyche.grudge_against_player = new_grudge_value; - } + gOpponents[twattee_index].psyche.grudge_against_player = new_grudge_value; } } } @@ -3169,7 +3200,6 @@ void RecordOpponentTwattageOccurrence(tCar_spec* pTwatter, tCar_spec* pTwattee) // IDA: void __cdecl ToggleOpponentTest() // FUNCTION: CARM95 0x0040c537 void ToggleOpponentTest(void) { - gTest_toggle = !gTest_toggle; } @@ -3222,9 +3252,10 @@ void RepairOpponentsSystems(void) { int i; for (i = 0; i < gProgram_state.AI_vehicles.number_of_opponents; i++) { - if (!gProgram_state.AI_vehicles.opponents[i].pursue_from_start) { + if (!gProgram_state.AI_vehicles.opponents[i].finished_for_this_race) { TotallyRepairACar(gProgram_state.AI_vehicles.opponents[i].car_spec); - TurnOpponentPhysicsOff(&gProgram_state.AI_vehicles.opponents[i]); + TurnOpponentPhysicsOn(&gProgram_state.AI_vehicles.opponents[i]); + NewObjective(&gProgram_state.AI_vehicles.opponents[i], eOOT_complete_race); gProgram_state.AI_vehicles.opponents[i].knackeredness_detected = 0; } } @@ -3267,20 +3298,20 @@ void DeleteSection(tS16 pSection_to_delete) { tS16 node_no_index; tS16 found_it; - for (node_no = 0; node_no < 2; node_no++) { - node_no_index = gProgram_state.AI_vehicles.path_sections[pSection_to_delete].node_indices[node_no]; - if (node_no_index >= 0) { + for (node_no_index = 0; node_no_index < 2; node_no_index++) { + node_no = gProgram_state.AI_vehicles.path_sections[pSection_to_delete].node_indices[node_no_index]; + if (node_no >= 0) { found_it = 0; - for (section_no = 0; section_no < (gProgram_state.AI_vehicles.path_nodes[node_no_index].number_of_sections - 1); section_no++) { - if (gProgram_state.AI_vehicles.path_nodes[node_no_index].sections[section_no] == pSection_to_delete) { + for (section_no_index = 0; section_no_index < (gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections - 1); section_no_index++) { + if (gProgram_state.AI_vehicles.path_nodes[node_no].sections[section_no_index] == pSection_to_delete) { found_it = 1; } if (found_it) { - gProgram_state.AI_vehicles.path_nodes[node_no_index].sections[section_no] = gProgram_state.AI_vehicles.path_nodes[node_no_index].sections[section_no + 1]; + gProgram_state.AI_vehicles.path_nodes[node_no].sections[section_no_index] = gProgram_state.AI_vehicles.path_nodes[node_no].sections[section_no_index + 1]; } } - if (gProgram_state.AI_vehicles.path_nodes[node_no_index].number_of_sections != 0) { - gProgram_state.AI_vehicles.path_nodes[node_no_index].number_of_sections--; + if (gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections != 0) { + gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections--; } } } @@ -3374,10 +3405,12 @@ void InsertThisNodeInThisSectionHere(tS16 pInserted_node, tS16 pSection_no, br_v tS16 node2; tS16 node3; - section_no_index = gProgram_state.AI_vehicles.path_sections[pSection_no].node_indices[1]; + node1 = gProgram_state.AI_vehicles.path_sections[pSection_no].node_indices[0]; + node2 = pInserted_node; + node3 = gProgram_state.AI_vehicles.path_sections[pSection_no].node_indices[1]; new_section = ReallocExtraPathSections(1); - gProgram_state.AI_vehicles.path_sections[new_section].node_indices[0] = pInserted_node; - gProgram_state.AI_vehicles.path_sections[new_section].node_indices[1] = section_no_index; + gProgram_state.AI_vehicles.path_sections[new_section].node_indices[0] = node2; + gProgram_state.AI_vehicles.path_sections[new_section].node_indices[1] = node3; gProgram_state.AI_vehicles.path_sections[new_section].min_speed[0] = 0; gProgram_state.AI_vehicles.path_sections[new_section].max_speed[0] = 255; gProgram_state.AI_vehicles.path_sections[new_section].min_speed[1] = gProgram_state.AI_vehicles.path_sections[pSection_no].min_speed[1]; @@ -3385,21 +3418,21 @@ void InsertThisNodeInThisSectionHere(tS16 pInserted_node, tS16 pSection_no, br_v gProgram_state.AI_vehicles.path_sections[new_section].width = gProgram_state.AI_vehicles.path_sections[pSection_no].width; gProgram_state.AI_vehicles.path_sections[new_section].type = gProgram_state.AI_vehicles.path_sections[pSection_no].type; gProgram_state.AI_vehicles.path_sections[new_section].one_way = gProgram_state.AI_vehicles.path_sections[pSection_no].one_way; - gProgram_state.AI_vehicles.path_sections[pSection_no].node_indices[1] = pInserted_node; + gProgram_state.AI_vehicles.path_sections[pSection_no].node_indices[1] = node2; gProgram_state.AI_vehicles.path_sections[pSection_no].min_speed[1] = 0; gProgram_state.AI_vehicles.path_sections[pSection_no].max_speed[1] = 255; - BrVector3Copy(&gProgram_state.AI_vehicles.path_nodes[pInserted_node].p, pWhere); - gProgram_state.AI_vehicles.path_nodes[pInserted_node].sections - [gProgram_state.AI_vehicles.path_nodes[pInserted_node].number_of_sections] + BrVector3Copy(&gProgram_state.AI_vehicles.path_nodes[node2].p, pWhere); + gProgram_state.AI_vehicles.path_nodes[node2].sections + [gProgram_state.AI_vehicles.path_nodes[node2].number_of_sections] = pSection_no; - gProgram_state.AI_vehicles.path_nodes[pInserted_node].number_of_sections = gProgram_state.AI_vehicles.path_nodes[pInserted_node].number_of_sections + 1; - gProgram_state.AI_vehicles.path_nodes[pInserted_node].sections - [gProgram_state.AI_vehicles.path_nodes[pInserted_node].number_of_sections] + gProgram_state.AI_vehicles.path_nodes[node2].number_of_sections++; // = gProgram_state.AI_vehicles.path_nodes[node2].number_of_sections + 1; + gProgram_state.AI_vehicles.path_nodes[node2].sections + [gProgram_state.AI_vehicles.path_nodes[node2].number_of_sections] = new_section; - gProgram_state.AI_vehicles.path_nodes[pInserted_node].number_of_sections = gProgram_state.AI_vehicles.path_nodes[pInserted_node].number_of_sections + 1; - for (node1 = 0; node1 < gProgram_state.AI_vehicles.path_nodes[section_no_index].number_of_sections; node1++) { - if (gProgram_state.AI_vehicles.path_nodes[section_no_index].sections[node1] == pSection_no) { - gProgram_state.AI_vehicles.path_nodes[section_no_index].sections[node1] = new_section; + gProgram_state.AI_vehicles.path_nodes[node2].number_of_sections++; + for (section_no_index = 0; section_no_index < gProgram_state.AI_vehicles.path_nodes[node3].number_of_sections; section_no_index++) { + if (gProgram_state.AI_vehicles.path_nodes[node3].sections[section_no_index] == pSection_no) { + gProgram_state.AI_vehicles.path_nodes[node3].sections[section_no_index] = new_section; } } } @@ -3433,50 +3466,64 @@ void RecalcNearestPathSectionSpeed(int pMax_not_min, int pAdjustment) { int new_speed; int nearest_end; - if (gOppo_paths_shown) { + if (!gOppo_paths_shown) { + return; + } + if (gAlready_elasticating) { +#ifdef DETHRACE_FIX_BUGS + // section_no is used uninitialized otherwise. Perhaps this should `return` here instead? + section_no = 0; +#endif + } else { section_no = FindNearestPathSection(&gSelf->t.t.translate.t, &direction_v, &intersect, &distance); - if (!gAlready_elasticating && distance > 10.f) { + if (distance > 10.f) { NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any paths close enough"); - } else { - BrVector3Sub(&wank, &gSelf->t.t.translate.t, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]].p); - dist_to_start = BrVector3Length(&wank); - BrVector3Sub(&wank, &gSelf->t.t.translate.t, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]].p); - dist_to_finish = BrVector3Length(&wank); - nearest_end = dist_to_finish < dist_to_start ? 1 : 0; - if (pMax_not_min) { - new_speed = gProgram_state.AI_vehicles.path_sections[section_no].max_speed[nearest_end]; - } else { - new_speed = gProgram_state.AI_vehicles.path_sections[section_no].min_speed[nearest_end]; - } - new_speed += 5 * pAdjustment; - if (5 * pAdjustment < 0 && new_speed > 100) { - new_speed = 100; - } else if (5 * pAdjustment > 0 && new_speed > 100) { - new_speed = 255; - } - if (new_speed < 0) { - new_speed = 0; - } else if (new_speed > 255) { - new_speed = 255; - } - if (pMax_not_min) { - gProgram_state.AI_vehicles.path_sections[section_no].max_speed[nearest_end] = new_speed; - } else { - gProgram_state.AI_vehicles.path_sections[section_no].min_speed[nearest_end] = new_speed; - } - if (nearest_end != 0) { - sprintf(str, "Towards section finish - Min Speed %d mph - Max speed %d mph", - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[section_no].min_speed[nearest_end]), - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[section_no].max_speed[nearest_end])); - } else { - sprintf(str, "Towards section start - Min Speed %d mph - Max speed %d mph", - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[section_no].min_speed[0]), - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[section_no].max_speed[0])); - } - ShowOppoPaths(); - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); + return; } } + BrVector3Sub(&wank, &gSelf->t.t.translate.t, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]].p); + dist_to_start = BrVector3Length(&wank); + BrVector3Sub(&wank, &gSelf->t.t.translate.t, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]].p); + dist_to_finish = BrVector3Length(&wank); + if (dist_to_finish < dist_to_start) { + nearest_end = 1; + } else { + nearest_end = 0; + } + pAdjustment *= 5; + + if (pMax_not_min) { + new_speed = gProgram_state.AI_vehicles.path_sections[section_no].max_speed[nearest_end] + pAdjustment; + } else { + new_speed = gProgram_state.AI_vehicles.path_sections[section_no].min_speed[nearest_end] + pAdjustment; + } + + if (pAdjustment < 0 && new_speed > 100) { + new_speed = 100; + } else if (pAdjustment > 0 && new_speed > 100) { + new_speed = 255; + } + if (new_speed < 0) { + new_speed = 0; + } else if (new_speed > 255) { + new_speed = 255; + } + if (pMax_not_min) { + gProgram_state.AI_vehicles.path_sections[section_no].max_speed[nearest_end] = new_speed; + } else { + gProgram_state.AI_vehicles.path_sections[section_no].min_speed[nearest_end] = new_speed; + } + if (nearest_end != 0) { + sprintf(str, "Towards section finish - Min Speed %d mph - Max speed %d mph", + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[section_no].min_speed[nearest_end]), + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[section_no].max_speed[nearest_end])); + } else { + sprintf(str, "Towards section start - Min Speed %d mph - Max speed %d mph", + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[section_no].min_speed[nearest_end]), + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[section_no].max_speed[nearest_end])); + } + ShowOppoPaths(); + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); } // IDA: void __cdecl RecalcNearestPathSectionWidth(br_scalar pAdjustment) @@ -3488,24 +3535,26 @@ void RecalcNearestPathSectionWidth(br_scalar pAdjustment) { br_scalar distance; char str[128]; - if (gOppo_paths_shown) { - if (!gAlready_elasticating) { - section_no = FindNearestPathSection(&gSelf->t.t.translate.t, &direction_v, &intersect, &distance); - if (distance > 10.f) { - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any paths close enough"); - return; - } - } else { - section_no = gMobile_section; - } - gProgram_state.AI_vehicles.path_sections[section_no].width += (int)pAdjustment * pAdjustment + pAdjustment; - if (gProgram_state.AI_vehicles.path_sections[section_no].width < .05f) { - gProgram_state.AI_vehicles.path_sections[section_no].width = .05f; - } - ShowOppoPaths(); - sprintf(str, "Width %2.1f BRU", 2.f * gProgram_state.AI_vehicles.path_sections[section_no].width); - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); + if (!gOppo_paths_shown) { + return; } + if (gAlready_elasticating) { + section_no = gMobile_section; + } else { + section_no = FindNearestPathSection(&gSelf->t.t.translate.t, &direction_v, &intersect, &distance); + if (distance > 10.f) { + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any paths close enough"); + return; + } + } + pAdjustment = (int)pAdjustment * pAdjustment + pAdjustment; + gProgram_state.AI_vehicles.path_sections[section_no].width += pAdjustment; + if (gProgram_state.AI_vehicles.path_sections[section_no].width < .05f) { + gProgram_state.AI_vehicles.path_sections[section_no].width = .05f; + } + ShowOppoPaths(); + sprintf(str, "Width %2.1f BRU", 2.0 * gProgram_state.AI_vehicles.path_sections[section_no].width); + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); } // IDA: void __usercall CalcNegativeXVector(br_vector3 *pNegative_x_vector@, br_vector3 *pStart@, br_vector3 *pFinish@, br_scalar pLength) @@ -3514,13 +3563,9 @@ void CalcNegativeXVector(br_vector3* pNegative_x_vector, br_vector3* pStart, br_ br_vector3 positive_y_vector; br_vector3 path_vector; - positive_y_vector.v[0] = pFinish->v[0] - pStart->v[0]; - positive_y_vector.v[1] = pFinish->v[1] - pStart->v[1]; - positive_y_vector.v[2] = pFinish->v[2] - pStart->v[2]; - pNegative_x_vector->v[0] = 1.0 * positive_y_vector.v[2] - positive_y_vector.v[1] * 0.0; - pNegative_x_vector->v[1] = 0.0 * positive_y_vector.v[0] - positive_y_vector.v[2] * 0.0; - pNegative_x_vector->v[2] = positive_y_vector.v[1] * 0.0 - 1.0 * positive_y_vector.v[0]; - + BrVector3Set(&positive_y_vector, 0, 1.0, 0.0); + BrVector3Sub(&path_vector, pFinish, pStart); + BrVector3Cross(pNegative_x_vector, &positive_y_vector, &path_vector); BrVector3Normalise(pNegative_x_vector, pNegative_x_vector); BrVector3Scale(pNegative_x_vector, pNegative_x_vector, pLength); } @@ -3569,13 +3614,13 @@ void MakeSection(br_uint_16 pFirst_vertex, br_uint_16 pFirst_face, br_vector3* p height = .3f; BrVector3Set(&offset_v, 0.f, 0.f, 0.f); the_material_finish_lt = pMaterial_centre_lt; - the_material_start_lt = pMaterial_centre_lt; + the_material_start_lt = the_material_finish_lt; the_material_finish_dk = pMaterial_centre_dk; - the_material_start_dk = pMaterial_centre_dk; + the_material_start_dk = the_material_finish_dk; } - centre_length_v.v[0] = pStart->v[0] + (pFinish->v[0] - pStart->v[0]) / 2.f; - centre_length_v.v[1] = pStart->v[1] + (pFinish->v[1] - pStart->v[1]) / 2.f; - centre_length_v.v[2] = pStart->v[2] + (pFinish->v[2] - pStart->v[2]) / 2.f; + BrVector3Sub(¢re_length_v, pFinish, pStart); + BrVector3InvScale(¢re_length_v, ¢re_length_v, 2); + BrVector3Accumulate(¢re_length_v, pStart); MakeVertexAndOffsetIt(gOppo_path_model, pFirst_vertex + 6 * i + 0, pStart->v[0], pStart->v[1], pStart->v[2], &offset_v); MakeVertexAndOffsetIt(gOppo_path_model, pFirst_vertex + 6 * i + 1, pStart->v[0], pStart->v[1] + height, pStart->v[2], &offset_v); @@ -3597,10 +3642,8 @@ void MakeCube(br_uint_16 pFirst_vertex, br_uint_16 pFirst_face, br_vector3* pPoi br_vector3 offset_v; br_vector3 point; - point.v[0] = pPoint->v[0]; - point.v[1] = pPoint->v[1]; + BrVector3Copy(&point, pPoint); point.v[1] += .15f; - point.v[2] = pPoint->v[2]; BrVector3Set(&offset_v, .1f, .1f, .1f); MakeVertexAndOffsetIt(gOppo_path_model, pFirst_vertex + 0, point.v[0], point.v[1], point.v[2], &offset_v); @@ -3649,6 +3692,7 @@ void ReallocModelFacesAndVertices(br_model* pModel, int pNum_faces, int pNum_ver int i; new_vertices = BrResAllocate(pModel, pNum_vertices * sizeof(br_vertex), BR_MEMORY_VERTICES); + // this is something like BrMemSet32 in the dissassembly, although no such function exists in open-source BRender memset(new_vertices, 0, pNum_vertices * sizeof(br_vertex)); if (pModel->nvertices != 0) { for (i = 0; i < ((pNum_vertices <= pModel->nvertices) ? pNum_vertices : pModel->nvertices); i++) { @@ -3661,6 +3705,7 @@ void ReallocModelFacesAndVertices(br_model* pModel, int pNum_faces, int pNum_ver pModel->nvertices = pNum_vertices; new_faces = BrResAllocate(pModel, pNum_faces * sizeof(br_face), BR_MEMORY_FACES); + // this is something like BrMemSet32 in the dissassembly, although no such function exists in open-source BRender memset(new_faces, 0, pNum_faces * sizeof(br_face)); if (pModel->nfaces != 0) { for (i = 0; i < ((pNum_faces <= pModel->nfaces) ? pNum_faces : pModel->nfaces); i++) { @@ -3731,6 +3776,7 @@ void RebuildOppoPathModel(void) { br_material* edge_mat_finish_lt; br_material* edge_mat_finish_dk; + at_least_one = 0; if (gProgram_state.AI_vehicles.number_of_path_nodes < 2) { if (gOppo_path_model != NULL) { BrModelRemove(gOppo_path_model); @@ -3803,14 +3849,20 @@ void RebuildOppoPathModel(void) { centre_mat_lt, centre_mat_dk, edge_mat_start_lt, edge_mat_start_dk, edge_mat_finish_lt, edge_mat_finish_dk); + at_least_one = 1; } + + first_face = 12 * gProgram_state.AI_vehicles.number_of_path_sections; + first_vertex = 18 * gProgram_state.AI_vehicles.number_of_path_sections; + for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { - MakeCube(18 * gProgram_state.AI_vehicles.number_of_path_sections + 8 * i, - 12 * gProgram_state.AI_vehicles.number_of_path_sections + 12 * i, + MakeCube(first_vertex + 8 * i, + first_face + 12 * i, gProgram_state.AI_vehicles.cop_start_points + i, gMat_lt_turq, gMat_lt_turq, gMat_dk_turq); + at_least_one = 1; } BrModelUpdate(gOppo_path_model, BR_MODU_ALL); } @@ -3827,8 +3879,8 @@ int ConsistencyCheck(void) { tS16 section_no_index1; int found_how_many; int failed; - tU8* nodes_referenced_by_sections_array = NULL; - tU8* sections_referenced_by_nodes_array = NULL; + tU8* nodes_referenced_by_sections_array; + tU8* sections_referenced_by_nodes_array; failed = 0; if (gProgram_state.AI_vehicles.number_of_path_nodes != 0) { @@ -3839,64 +3891,70 @@ int ConsistencyCheck(void) { sections_referenced_by_nodes_array = BrMemAllocate(gProgram_state.AI_vehicles.number_of_path_sections, kMem_sections_array); memset(sections_referenced_by_nodes_array, 0, gProgram_state.AI_vehicles.number_of_path_sections); } - for (section_no_index = 0; section_no_index < gProgram_state.AI_vehicles.number_of_path_sections; section_no_index++) { - start_node = gProgram_state.AI_vehicles.path_sections[section_no_index].node_indices[0]; - finish_node = gProgram_state.AI_vehicles.path_sections[section_no_index].node_indices[1]; + for (section_no = 0; section_no < gProgram_state.AI_vehicles.number_of_path_sections; section_no++) { + start_node = gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]; + finish_node = gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]; if (finish_node == start_node) { - dr_dprintf("CONSISTENCY FAILURE: Section #%d has both ends attached to same node!", section_no_index); + dr_dprintf("CONSISTENCY FAILURE: Section #%d has both ends attached to same node!", section_no); failed = 1; } - if (start_node >= 0 && gProgram_state.AI_vehicles.number_of_path_nodes - 1 >= start_node) { + if (start_node < 0 || gProgram_state.AI_vehicles.number_of_path_nodes - 1 < start_node) { + dr_dprintf( + "CONSISTENCY FAILURE: Section #%d references invalid node (#%d) - should be in range 0..%d", + section_no, start_node, gProgram_state.AI_vehicles.number_of_path_nodes - 1); + failed = 1; + } else { nodes_referenced_by_sections_array[start_node] = 1; nodes_referenced_by_sections_array[finish_node] = 1; found_how_many = 0; - for (section_no_index1 = 0; section_no_index1 < gProgram_state.AI_vehicles.path_nodes[start_node].number_of_sections; section_no_index1++) { - if (gProgram_state.AI_vehicles.path_nodes[start_node].sections[section_no_index1] == section_no_index) { + for (section_no_index = 0; section_no_index < gProgram_state.AI_vehicles.path_nodes[start_node].number_of_sections; section_no_index++) { + if (gProgram_state.AI_vehicles.path_nodes[start_node].sections[section_no_index] == section_no) { found_how_many++; } } if (found_how_many == 0) { dr_dprintf( "CONSISTENCY FAILURE: Section #%d references node #%d but not vice-versa", - section_no_index, + section_no, start_node); failed = 1; } - } else { + } + if (finish_node < 0 || gProgram_state.AI_vehicles.number_of_path_nodes - 1 < finish_node) { dr_dprintf( "CONSISTENCY FAILURE: Section #%d references invalid node (#%d) - should be in range 0..%d", - section_no_index, - start_node, + section_no, + finish_node, gProgram_state.AI_vehicles.number_of_path_nodes - 1); failed = 1; - } - if (finish_node >= 0 && gProgram_state.AI_vehicles.number_of_path_nodes - 1 >= finish_node) { + + } else { found_how_many = 0; - for (section_no_index1 = 0; section_no_index1 < gProgram_state.AI_vehicles.path_nodes[finish_node].number_of_sections; section_no_index1++) { - if (gProgram_state.AI_vehicles.path_nodes[finish_node].sections[section_no_index1] == section_no_index) { + for (section_no_index = 0; section_no_index < gProgram_state.AI_vehicles.path_nodes[finish_node].number_of_sections; section_no_index++) { + if (gProgram_state.AI_vehicles.path_nodes[finish_node].sections[section_no_index] == section_no) { found_how_many++; } } if (found_how_many == 0) { dr_dprintf( "CONSISTENCY FAILURE: Section #%d references node #%d but not vice-versa", - section_no_index, + section_no, finish_node); failed = 1; } - } else { - dr_dprintf( - "CONSISTENCY FAILURE: Section #%d references invalid node (#%d) - should be in range 0..%d", - section_no_index, - finish_node, - gProgram_state.AI_vehicles.number_of_path_nodes - 1); - failed = 1; } } for (node_no = 0; node_no < gProgram_state.AI_vehicles.number_of_path_nodes; node_no++) { for (section_no_index = 0; section_no_index < gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections; section_no_index++) { section_no = gProgram_state.AI_vehicles.path_nodes[node_no].sections[section_no_index]; - if (section_no >= 0 && gProgram_state.AI_vehicles.number_of_path_sections - 1 >= section_no) { + if (section_no < 0 || gProgram_state.AI_vehicles.number_of_path_sections - 1 < section_no) { + dr_dprintf( + "CONSISTENCY FAILURE: Node #%d references invalid section (#%d) - should be in range 0..%d", + node_no, + section_no, + gProgram_state.AI_vehicles.number_of_path_sections - 1); + failed = 1; + } else { sections_referenced_by_nodes_array[section_no] = 1; if (gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0] != node_no && gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1] != node_no) { @@ -3906,18 +3964,12 @@ int ConsistencyCheck(void) { section_no); failed = 1; } - } else { - dr_dprintf( - "CONSISTENCY FAILURE: Node #%d references invalid section (#%d) - should be in range 0..%d", - node_no, - section_no, - gProgram_state.AI_vehicles.number_of_path_sections - 1); - failed = 1; } found_how_many = 0; - for (section_no_index1 = section_no; section_no_index1 < gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections; section_no_index1++) { + for (section_no_index1 = section_no_index; section_no_index1 < gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections; section_no_index1++) { if (gProgram_state.AI_vehicles.path_nodes[node_no].sections[section_no_index1] == section_no) { found_how_many++; + } else { } } if (found_how_many > 1) { @@ -3954,8 +4006,9 @@ int ConsistencyCheck(void) { gProgram_state.AI_vehicles.number_of_path_nodes); dr_dprintf("^^^ CONSISTENCY FAILURE ^^^"); PDEnterDebugger("OPPONENT PATH CONSISTENCY FAILURE - refer to DIAGNOST.TXT"); + return 0; } - return !failed; + return 1; } // IDA: void __cdecl ShowOppoPaths() @@ -3963,17 +4016,17 @@ int ConsistencyCheck(void) { void ShowOppoPaths(void) { char str[256]; - if (!gOppo_paths_shown) { - if (gOppo_path_actor != NULL) { - gOppo_path_actor->render_style = BR_RSTYLE_NONE; - } - NewTextHeadupSlot(eHeadupSlot_misc, 0, 1000, -1, "Not displaying any paths"); - } else { + if (gOppo_paths_shown) { RebuildOppoPathModel(); sprintf(str, "Total %d nodes, %d sections", gProgram_state.AI_vehicles.number_of_path_nodes, gProgram_state.AI_vehicles.number_of_path_sections); - NewTextHeadupSlot(eHeadupSlot_misc, 0, 1000, -1, str); + NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -1, str); + } else { + if (gOppo_path_actor != NULL) { + gOppo_path_actor->render_style = BR_RSTYLE_NONE; + } + NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -1, "Not displaying any paths"); } if (ConsistencyCheck()) { WriteOutOppoPaths(); @@ -3994,32 +4047,31 @@ void WriteOutOppoPaths(void) { for (i = 0; 1; i++) { #ifdef DETHRACE_FIX_BUGS sprintf(str, "OPATH%03d.TXT", i); -#else - sprintf(str, "OPATH%0.3d.TXT", i); -#endif PathCat(the_path, gApplication_path, str); -#ifdef DETHRACE_FIX_BUGS // OldDRfopen refuses to open unknown .TXT files f = fopen(the_path, "r"); #else + sprintf(str, "OPATH%0.3d.TXT", i); + PathCat(the_path, gApplication_path, str); f = DRfopen(the_path, "r+"); #endif - if (f == NULL) { + if (!f) { + strcpy(gOppo_path_filename, the_path); + gMade_path_filename = 1; break; } fclose(f); } - strcpy(gOppo_path_filename, the_path); - gMade_path_filename = 1; } #ifdef DETHRACE_FIX_BUGS f = fopen(gOppo_path_filename, "w"); -#else - f = DRfopen(gOppo_path_filename, "wt"); -#endif if (f == NULL) { printf("f is NULL, errno=%d, msg=\"%s\"\n", errno, strerror(errno)); } +#else + f = DRfopen(gOppo_path_filename, "wt"); +#endif + fprintf(f, "%s\n", "START OF OPPONENT PATHS"); fprintf(f, "\n%-3d // Number of path nodes\n", gProgram_state.AI_vehicles.number_of_path_nodes); @@ -4053,7 +4105,7 @@ void WriteOutOppoPaths(void) { gProgram_state.AI_vehicles.cop_start_points[i].v[2], 0.f, 0.f, 0.f, i); } - fprintf(f, "END OF OPPONENT PATHS"); + fprintf(f, "\n%s\n", "END OF OPPONENT PATHS"); fclose(f); } @@ -4066,7 +4118,10 @@ int NewNodeOKHere(void) { BrVector3Sub(&last_node_to_this, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]].p, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[0]].p); - return BrVector3Length(&last_node_to_this) != 0.f; + + if (BrVector3Length(&last_node_to_this) == 0.f) { + return 0; + } } return 1; } @@ -4095,6 +4150,8 @@ void DropElasticateyNode(void) { tPath_section_type_enum original_type; all_the_same_type = 1; + section_type = ePST_normal; + if (!NewNodeOKHere()) { return; } @@ -4102,7 +4159,7 @@ void DropElasticateyNode(void) { old_node = gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]; BrVector3Copy(&gProgram_state.AI_vehicles.path_nodes[old_node].p, &gProgram_state.current_car.car_master_actor->t.t.translate.t); - original_type = gProgram_state.AI_vehicles.path_sections[gMobile_section].type; + section_type = gProgram_state.AI_vehicles.path_sections[gMobile_section].type; one_wayness = gProgram_state.AI_vehicles.path_sections[gMobile_section].one_way; new_node = ReallocExtraPathNodes(1); gMobile_section = ReallocExtraPathSections(1); @@ -4114,27 +4171,29 @@ void DropElasticateyNode(void) { if (gProgram_state.AI_vehicles.number_of_path_nodes == 0) { NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Not implemented yet. Go away."); return; - } - old_node = FindNearestPathNode(&gSelf->t.t.translate.t, &distance); - if (distance > 10.f) { - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any nodes close enough"); - return; - } - original_type = 0; - if (gProgram_state.AI_vehicles.path_nodes[old_node].number_of_sections != 0) { - for (section_no_index = 1; section_no_index < gProgram_state.AI_vehicles.path_nodes[old_node].number_of_sections; section_no_index++) { - if (gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[old_node].sections[section_no_index]].type != gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[old_node].sections[0]].type) { - all_the_same_type = 0; + } else { + old_node = FindNearestPathNode(&gSelf->t.t.translate.t, &distance); + if (distance > 10.f) { + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any nodes close enough"); + return; + } + + if (gProgram_state.AI_vehicles.path_nodes[old_node].number_of_sections >= 1) { + original_type = gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[old_node].sections[0]].type; + for (section_no_index = 1; section_no_index < gProgram_state.AI_vehicles.path_nodes[old_node].number_of_sections; section_no_index++) { + if (gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[old_node].sections[section_no_index]].type != original_type) { + all_the_same_type = 0; + } + } + if (all_the_same_type) { + section_type = original_type; } } - if (all_the_same_type) { - original_type = gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[old_node].sections[0]].type; - } + gAlready_elasticating = 1; + new_node = ReallocExtraPathNodes(1); + gMobile_section = ReallocExtraPathSections(1); + one_wayness = 0; } - gAlready_elasticating = 1; - new_node = ReallocExtraPathNodes(1); - gMobile_section = ReallocExtraPathSections(1); - one_wayness = 0; } gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[0] = old_node; gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1] = new_node; @@ -4142,18 +4201,18 @@ void DropElasticateyNode(void) { gProgram_state.AI_vehicles.path_sections[gMobile_section].min_speed[1] = 0; gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[0] = 255; gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[1] = 255; - gProgram_state.AI_vehicles.path_sections[gMobile_section].type = original_type; + gProgram_state.AI_vehicles.path_sections[gMobile_section].type = section_type; gProgram_state.AI_vehicles.path_sections[gMobile_section].one_way = one_wayness; - if (gProgram_state.AI_vehicles.path_nodes[old_node].number_of_sections == 0) { - gProgram_state.AI_vehicles.path_sections[gMobile_section].width = 1.f; - } else { + if (gProgram_state.AI_vehicles.path_nodes[old_node].number_of_sections != 0) { gProgram_state.AI_vehicles.path_sections[gMobile_section].width = gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[old_node].sections[0]].width; + } else { + gProgram_state.AI_vehicles.path_sections[gMobile_section].width = 1.f; } gProgram_state.AI_vehicles.path_nodes[new_node].number_of_sections = 0; gProgram_state.AI_vehicles.path_nodes[new_node].sections[gProgram_state.AI_vehicles.path_nodes[new_node].number_of_sections] = gMobile_section; - gProgram_state.AI_vehicles.path_nodes[new_node].number_of_sections += 1; + gProgram_state.AI_vehicles.path_nodes[new_node].number_of_sections++; gProgram_state.AI_vehicles.path_nodes[old_node].sections[gProgram_state.AI_vehicles.path_nodes[old_node].number_of_sections] = gMobile_section; - gProgram_state.AI_vehicles.path_nodes[old_node].number_of_sections += 1; + gProgram_state.AI_vehicles.path_nodes[old_node].number_of_sections++; ShowOppoPaths(); sprintf(str, "New section #%d, new node #%d", gMobile_section, new_node); NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); @@ -4176,60 +4235,63 @@ void InsertAndElasticate(void) { tPath_section_type_enum section_type; not_perp = 0; - if (NewNodeOKHere()) { - section_no = FindNearestPathSection(&gSelf->t.t.translate.t, &direction_v, &intersect, &distance); - BrVector3Sub(&wank, - &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]].p, - &intersect); - if (BrVector3Length(&wank) == 0.f) { - not_perp = 1; - } - BrVector3Sub(&wank, - &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]].p, - &intersect); - if (BrVector3Length(&wank) == 0.f) { - not_perp = 1; - } - if (not_perp || distance > 10.f) { - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Get nearer to the section"); + section_type = ePST_normal; + + if (!NewNodeOKHere()) { + return; + } + section_no = FindNearestPathSection(&gSelf->t.t.translate.t, &direction_v, &intersect, &distance); + BrVector3Sub(&wank, + &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]].p, + &intersect); + if (BrVector3Length(&wank) == 0.f) { + not_perp = 1; + } + BrVector3Sub(&wank, + &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]].p, + &intersect); + if (BrVector3Length(&wank) == 0.f) { + not_perp = 1; + } + if (not_perp || distance > 10.f) { + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Get nearer to the section"); + } else { + new_section = ReallocExtraPathSections(1); + if (gAlready_elasticating) { + inserted_node = gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]; + section_type = gProgram_state.AI_vehicles.path_sections[gMobile_section].type; + one_wayness = gProgram_state.AI_vehicles.path_sections[gMobile_section].one_way; + elasticatey_node = ReallocExtraPathNodes(1); + gProgram_state.AI_vehicles.path_nodes[elasticatey_node].number_of_sections = 0; + gProgram_state.AI_vehicles.path_sections[new_section].width = gProgram_state.AI_vehicles.path_sections[gMobile_section].width; } else { - new_section = ReallocExtraPathSections(1); - if (gAlready_elasticating) { - inserted_node = gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]; - section_type = gProgram_state.AI_vehicles.path_sections[gMobile_section].type; - one_wayness = gProgram_state.AI_vehicles.path_sections[gMobile_section].one_way; - elasticatey_node = ReallocExtraPathNodes(1); - gProgram_state.AI_vehicles.path_nodes[elasticatey_node].number_of_sections = 0; - gProgram_state.AI_vehicles.path_sections[new_section].width = gProgram_state.AI_vehicles.path_sections[gMobile_section].width; - } else { - inserted_node = ReallocExtraPathNodes(2); - gProgram_state.AI_vehicles.path_nodes[inserted_node].number_of_sections = 0; - elasticatey_node = inserted_node + 1; - gProgram_state.AI_vehicles.path_nodes[elasticatey_node].number_of_sections = 0; - gProgram_state.AI_vehicles.path_sections[new_section].width = gProgram_state.AI_vehicles.path_sections[section_no].width; - section_type = gProgram_state.AI_vehicles.path_sections[section_no].type; - one_wayness = gProgram_state.AI_vehicles.path_sections[section_no].one_way; - } - InsertThisNodeInThisSectionHere(inserted_node, section_no, &gSelf->t.t.translate.t); - gMobile_section = new_section; - gProgram_state.AI_vehicles.path_sections[new_section].node_indices[0] = inserted_node; - gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1] = elasticatey_node; - gProgram_state.AI_vehicles.path_sections[gMobile_section].min_speed[0] = 0; - gProgram_state.AI_vehicles.path_sections[gMobile_section].min_speed[1] = 0; - gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[0] = 255; - gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[1] = 255; - gProgram_state.AI_vehicles.path_sections[gMobile_section].type = section_type; - gProgram_state.AI_vehicles.path_sections[gMobile_section].one_way = one_wayness; - gProgram_state.AI_vehicles.path_nodes[inserted_node].sections[gProgram_state.AI_vehicles.path_nodes[inserted_node].number_of_sections] = gMobile_section; - gProgram_state.AI_vehicles.path_nodes[inserted_node].number_of_sections += 1; - gProgram_state.AI_vehicles.path_nodes[elasticatey_node].sections[gProgram_state.AI_vehicles.path_nodes[elasticatey_node].number_of_sections] = gMobile_section; - gProgram_state.AI_vehicles.path_nodes[elasticatey_node].number_of_sections += 1; - gAlready_elasticating = 1; - ShowOppoPaths(); - sprintf(str, "New section %d, new node #%d inserted into section #%d", - gMobile_section, inserted_node, section_no); - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); + inserted_node = ReallocExtraPathNodes(2); + gProgram_state.AI_vehicles.path_nodes[inserted_node].number_of_sections = 0; + elasticatey_node = inserted_node + 1; + gProgram_state.AI_vehicles.path_nodes[elasticatey_node].number_of_sections = 0; + gProgram_state.AI_vehicles.path_sections[new_section].width = gProgram_state.AI_vehicles.path_sections[section_no].width; + section_type = gProgram_state.AI_vehicles.path_sections[section_no].type; + one_wayness = gProgram_state.AI_vehicles.path_sections[section_no].one_way; } + InsertThisNodeInThisSectionHere(inserted_node, section_no, &gSelf->t.t.translate.t); + gMobile_section = new_section; + gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[0] = inserted_node; + gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1] = elasticatey_node; + gProgram_state.AI_vehicles.path_sections[gMobile_section].min_speed[0] = 0; + gProgram_state.AI_vehicles.path_sections[gMobile_section].min_speed[1] = 0; + gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[0] = 255; + gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[1] = 255; + gProgram_state.AI_vehicles.path_sections[gMobile_section].type = section_type; + gProgram_state.AI_vehicles.path_sections[gMobile_section].one_way = one_wayness; + gProgram_state.AI_vehicles.path_nodes[inserted_node].sections[gProgram_state.AI_vehicles.path_nodes[inserted_node].number_of_sections] = gMobile_section; + gProgram_state.AI_vehicles.path_nodes[inserted_node].number_of_sections++; + gProgram_state.AI_vehicles.path_nodes[elasticatey_node].sections[gProgram_state.AI_vehicles.path_nodes[elasticatey_node].number_of_sections] = gMobile_section; + gProgram_state.AI_vehicles.path_nodes[elasticatey_node].number_of_sections++; + gAlready_elasticating = 1; + ShowOppoPaths(); + sprintf(str, "New section %d, new node #%d inserted into section #%d", + gMobile_section, inserted_node, section_no); + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); } } @@ -4246,31 +4308,32 @@ void InsertAndDontElasticate(void) { char str[256]; not_perp = 0; - if (NewNodeOKHere()) { - section_no = FindNearestPathSection(&gSelf->t.t.translate.t, &direction_v, &intersect, &distance); - BrVector3Sub(&wank, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]].p, &intersect); - if (BrVector3Length(&wank) == 0.f) { - not_perp = 1; - } - BrVector3Sub(&wank, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]].p, &intersect); - if (BrVector3Length(&wank) == 0.f) { - not_perp = 1; - } - if (not_perp || distance > 10.f) { - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Get nearer to the section"); + if (!NewNodeOKHere()) { + return; + } + section_no = FindNearestPathSection(&gSelf->t.t.translate.t, &direction_v, &intersect, &distance); + BrVector3Sub(&wank, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[0]].p, &intersect); + if (BrVector3Length(&wank) == 0.f) { + not_perp = 1; + } + BrVector3Sub(&wank, &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[section_no].node_indices[1]].p, &intersect); + if (BrVector3Length(&wank) == 0.f) { + not_perp = 1; + } + if (not_perp || distance > 10.f) { + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Get nearer to the section"); + } else { + if (gAlready_elasticating) { + gAlready_elasticating = 0; + inserted_node = gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]; } else { - if (gAlready_elasticating) { - gAlready_elasticating = 0; - inserted_node = gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]; - } else { - inserted_node = ReallocExtraPathNodes(1); - gProgram_state.AI_vehicles.path_nodes[inserted_node].number_of_sections = 0; - } - InsertThisNodeInThisSectionHere(inserted_node, section_no, &gSelf->t.t.translate.t); - ShowOppoPaths(); - sprintf(str, "New node #%d inserted into section #%d", inserted_node, section_no); - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); + inserted_node = ReallocExtraPathNodes(1); + gProgram_state.AI_vehicles.path_nodes[inserted_node].number_of_sections = 0; } + InsertThisNodeInThisSectionHere(inserted_node, section_no, &gSelf->t.t.translate.t); + ShowOppoPaths(); + sprintf(str, "New node #%d inserted into section #%d", inserted_node, section_no); + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); } } @@ -4279,17 +4342,21 @@ void InsertAndDontElasticate(void) { void DropDeadEndNode(void) { char str[256]; - if (NewNodeOKHere() && gAlready_elasticating) { - gAlready_elasticating = 0; - BrVector3Copy( - &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]].p, - &gSelf->t.t.translate.t); - ShowOppoPaths(); - sprintf(str, "New section #%d, finish node #%d", - gMobile_section, - gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]); - NewTextHeadupSlot(eHeadupSlot_misc, 0, 4000, -1, str); + if (!NewNodeOKHere()) { + return; } + if (!gAlready_elasticating) { + return; + } + gAlready_elasticating = 0; + BrVector3Copy( + &gProgram_state.AI_vehicles.path_nodes[gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]].p, + &gSelf->t.t.translate.t); + ShowOppoPaths(); + sprintf(str, "New section #%d, finish node #%d", + gMobile_section, + gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]); + NewTextHeadupSlot(eHeadupSlot_misc, 0, 4000, -1, str); } // IDA: void __cdecl DropNodeOnNodeAndStopElasticating() @@ -4299,25 +4366,26 @@ void DropNodeOnNodeAndStopElasticating(void) { char str[256]; br_scalar distance; - if (gAlready_elasticating) { - node_no = FindNearestPathNode(&gSelf->t.t.translate.t, &distance); - if (gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[0] == node_no || distance > 10.f) { - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any nodes close enough"); - } else if (gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections >= COUNT_OF(gProgram_state.AI_vehicles.path_nodes[node_no].sections)) { - sprintf(str, "Sorry, node #%d already has %d sections attached", node_no, (int)COUNT_OF(gProgram_state.AI_vehicles.path_nodes[node_no].sections)); - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); - } else { - gAlready_elasticating = 0; - gProgram_state.AI_vehicles.number_of_path_nodes -= 1; - gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1] = node_no; - gProgram_state.AI_vehicles.path_nodes[node_no].sections[gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections] = gMobile_section; - gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections += 1; - ShowOppoPaths(); - sprintf(str, "New section #%d, attached to existing node #%d", - gMobile_section, - gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]); - NewTextHeadupSlot(eHeadupSlot_misc, 0, 4000, -1, str); - } + if (!gAlready_elasticating) { + return; + } + node_no = FindNearestPathNode(&gSelf->t.t.translate.t, &distance); + if (gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[0] == node_no || distance > 10.f) { + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any nodes close enough"); + } else if (gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections >= COUNT_OF(gProgram_state.AI_vehicles.path_nodes[node_no].sections)) { + sprintf(str, "Sorry, node #%d already has %d sections attached", node_no, (int)COUNT_OF(gProgram_state.AI_vehicles.path_nodes[node_no].sections)); + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); + } else { + gAlready_elasticating = 0; + gProgram_state.AI_vehicles.number_of_path_nodes--; + gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1] = node_no; + gProgram_state.AI_vehicles.path_nodes[node_no].sections[gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections] = gMobile_section; + gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections++; + ShowOppoPaths(); + sprintf(str, "New section #%d, attached to existing node #%d", + gMobile_section, + gProgram_state.AI_vehicles.path_sections[gMobile_section].node_indices[1]); + NewTextHeadupSlot(eHeadupSlot_misc, 0, 4000, -1, str); } } @@ -4325,54 +4393,60 @@ void DropNodeOnNodeAndStopElasticating(void) { // FUNCTION: CARM95 0x004103c5 void WidenOppoPathSection(void) { - if (gOppo_paths_shown) { - RecalcNearestPathSectionWidth(.05f); + if (!gOppo_paths_shown) { + return; } + RecalcNearestPathSectionWidth(.05f); } // IDA: void __cdecl NarrowOppoPathSection() // FUNCTION: CARM95 0x00410573 void NarrowOppoPathSection(void) { - if (gOppo_paths_shown) { - RecalcNearestPathSectionWidth(-.05f); + if (!gOppo_paths_shown) { + return; } + RecalcNearestPathSectionWidth(-.05f); } // IDA: void __cdecl IncreaseSectionMinSpeed() // FUNCTION: CARM95 0x0041059d void IncreaseSectionMinSpeed(void) { - if (gOppo_paths_shown) { - RecalcNearestPathSectionSpeed(0, 1); + if (!gOppo_paths_shown) { + return; } + RecalcNearestPathSectionSpeed(0, 1); } // IDA: void __cdecl DecreaseSectionMinSpeed() // FUNCTION: CARM95 0x00410a7f void DecreaseSectionMinSpeed(void) { - if (gOppo_paths_shown) { - RecalcNearestPathSectionSpeed(0, -1); + if (!gOppo_paths_shown) { + return; } + RecalcNearestPathSectionSpeed(0, -1); } // IDA: void __cdecl IncreaseSectionMaxSpeed() // FUNCTION: CARM95 0x00410aa8 void IncreaseSectionMaxSpeed(void) { - if (gOppo_paths_shown) { - RecalcNearestPathSectionSpeed(1, 1); + if (!gOppo_paths_shown) { + return; } + RecalcNearestPathSectionSpeed(1, 1); } // IDA: void __cdecl DecreaseSectionMaxSpeed() // FUNCTION: CARM95 0x00410ad1 void DecreaseSectionMaxSpeed(void) { - if (gOppo_paths_shown) { - RecalcNearestPathSectionSpeed(1, -1); + if (!gOppo_paths_shown) { + return; } + RecalcNearestPathSectionSpeed(1, -1); } // IDA: void __cdecl PullOppoPoint() @@ -4381,20 +4455,22 @@ void PullOppoPoint(void) { tS16 node_no; br_scalar distance; - if (gOppo_paths_shown) { - if (gAlready_elasticating) { - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Not while you're elasticating"); - } else { - node_no = FindNearestPathNode(&gSelf->t.t.translate.t, &distance); - if (distance > 10.f) { - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any paths close enough"); - } else { - BrVector3Copy(&gProgram_state.AI_vehicles.path_nodes[node_no].p, &gSelf->t.t.translate.t); - ShowOppoPaths(); - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Bing!"); - } - } + if (!gOppo_paths_shown) { + return; } + if (gAlready_elasticating) { + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Not while you're elasticating"); + return; + } else { + node_no = FindNearestPathNode(&gSelf->t.t.translate.t, &distance); + if (distance > 10.f) { + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any paths close enough"); + return; + } + BrVector3Copy(&gProgram_state.AI_vehicles.path_nodes[node_no].p, &gSelf->t.t.translate.t); + } + ShowOppoPaths(); + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Bing!"); } // IDA: void __cdecl ShowNodeInfo() @@ -4467,10 +4543,10 @@ void ShowSectionInfo2(void) { NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Show paths first (F5)"); } else if (gAlready_elasticating) { sprintf(str, "Towards start - min %d max %d, finish - min %d, max %d mph", - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[gMobile_section].min_speed[0]), - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[0]), - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[gMobile_section].min_speed[1]), - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[1])); + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[gMobile_section].min_speed[0]), + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[0]), + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[gMobile_section].min_speed[1]), + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[gMobile_section].max_speed[1])); NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); } else { section_no = FindNearestPathSection(&gSelf->t.t.translate.t, &direction_v, &intersect, &distance); @@ -4478,10 +4554,10 @@ void ShowSectionInfo2(void) { NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any sections close enough"); } else { sprintf(str, "Towards start - min %d max %d, finish - min %d, max %d mph", - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[section_no].min_speed[0]), - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[section_no].max_speed[0]), - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[section_no].min_speed[1]), - (int)(2.2f * gProgram_state.AI_vehicles.path_sections[section_no].max_speed[1])); + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[section_no].min_speed[0]), + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[section_no].max_speed[0]), + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[section_no].min_speed[1]), + (int)(2.2 * gProgram_state.AI_vehicles.path_sections[section_no].max_speed[1])); NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, str); } } @@ -4551,10 +4627,13 @@ void DeleteOppoPathNodeAndJoin(void) { NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any nodes close enough"); } else if (gProgram_state.AI_vehicles.path_nodes[node_no].number_of_sections != 2) { NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Node must have exactly 2 sections attached"); - } else if ((gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[node_no].sections[0]].node_indices[0] == node_no - && gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[node_no].sections[1]].node_indices[1] == node_no) - || (gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[node_no].sections[1]].node_indices[0] == node_no - && gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[node_no].sections[0]].node_indices[1] == node_no)) { + } else if ((gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[node_no].sections[0]].node_indices[0] != node_no + || gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[node_no].sections[1]].node_indices[1] != node_no) + && (gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[node_no].sections[1]].node_indices[0] != node_no + || gProgram_state.AI_vehicles.path_sections[gProgram_state.AI_vehicles.path_nodes[node_no].sections[0]].node_indices[1] != node_no)) { + + NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Sections must point in same direction"); + } else { ConsistencyCheck(); DeleteNode(node_no, 0); ConsistencyCheck(); @@ -4562,8 +4641,6 @@ void DeleteOppoPathNodeAndJoin(void) { ConsistencyCheck(); ShowOppoPaths(); NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Blam!"); - } else { - NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Sections must point in same direction"); } } } @@ -4647,10 +4724,10 @@ void ToggleOneWayNess(void) { if (distance > 10.f) { NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -1, "Can't find any sections close enough"); } else { - if (gProgram_state.AI_vehicles.path_sections[section_no].one_way) { - gProgram_state.AI_vehicles.path_sections[section_no].one_way = 0; - } else { + if (!gProgram_state.AI_vehicles.path_sections[section_no].one_way) { gProgram_state.AI_vehicles.path_sections[section_no].one_way = 1; + } else { + gProgram_state.AI_vehicles.path_sections[section_no].one_way = 0; } ShowOppoPaths(); if (gProgram_state.AI_vehicles.path_sections[section_no].one_way) { @@ -4679,10 +4756,10 @@ void CopStartPointInfo(void) { } else { for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { BrVector3Sub(&car_to_point, &gSelf->t.t.translate.t, &gProgram_state.AI_vehicles.cop_start_points[i]); - distance = BrVector3LengthSquared(&car_to_point); + distance = BrVector3Length(&car_to_point); if (distance < closest_distance) { - closest = i; closest_distance = distance; + closest = i; } } if (closest < 0 || closest_distance > 10.f) { diff --git a/src/DETHRACE/common/skidmark.c b/src/DETHRACE/common/skidmark.c index 30196c0a..0fd2d6bc 100644 --- a/src/DETHRACE/common/skidmark.c +++ b/src/DETHRACE/common/skidmark.c @@ -33,10 +33,10 @@ void AdjustSkid(int pSkid_num, br_matrix34* pMatrix, int pMaterial_index) { // IDA: br_material* __usercall MaterialFromIndex@(int pIndex@) // FUNCTION: CARM95 0x00401088 br_material* MaterialFromIndex(int pIndex) { - if (pIndex > -2) { - return gCurrent_race.material_modifiers[pIndex].skid_mark_material; - } else { + if (pIndex <= -2) { return gMaterial[-2 - pIndex]; + } else { + return gCurrent_race.material_modifiers[pIndex].skid_mark_material; } } @@ -306,7 +306,7 @@ int FarFromLine2D(br_vector3* pPt, br_vector3* pL1, br_vector3* pL2) { to_pt.v[0] = BR_SUB(pPt->v[0], pL2->v[0]); to_pt.v[1] = BR_SUB(pPt->v[2], pL2->v[2]); - cross = -(line.v[0]) * to_pt.v[1] + to_pt.v[0] * line.v[1]; + cross = (-line.v[0]) * to_pt.v[1] + to_pt.v[0] * line.v[1]; line_len = BrVector2Length(&line); if (fabs(cross) > line_len * 0.05f) { return 1; diff --git a/src/DETHRACE/dr_types.h b/src/DETHRACE/dr_types.h index fe70ed24..9a7ad3fb 100644 --- a/src/DETHRACE/dr_types.h +++ b/src/DETHRACE/dr_types.h @@ -589,14 +589,14 @@ typedef struct tJoystick { tS32 dec; } tJoystick; -typedef struct tPursuee_trail { - br_vector3 trail_nodes[25]; - br_vector3 base_heading; - tU32 time_of_next_recording; - tU32 end_of_deviation; - tU8 number_of_nodes; - tU8 has_deviated_recently; - tU8 nodes_shifted_this_frame; +typedef struct tPursuee_trail { // size: 0x144 + br_vector3 trail_nodes[25]; // @0x0 + br_vector3 base_heading; // @0x12c + tU32 time_of_next_recording; // @0x138 + tU32 end_of_deviation; // @0x13c + tU8 number_of_nodes; // @0x140 + tU8 has_deviated_recently; // @0x141 + tU8 nodes_shifted_this_frame; // @0x142 } tPursuee_trail; typedef struct tCar_spec_struct { // size: 0x1a9c @@ -1659,71 +1659,71 @@ typedef struct tOpponent { tText_chunk* text_chunks; } tOpponent; -typedef struct tProgram_state { - tS32 credits; - tS32 credits_earned; - tS32 credits_lost; - tU32 view_change_start; - tU32 pratcam_move_start; - int peds_killed; - int sausage_eater_mode; - int rank; - int loaded; - int last_slot; - int skill_level; - int parts_shop_visited; - int racing; - int cut_scene; - int saving; - int loading; - int dont_save_or_load; - int dont_load; - int mirror_on; - int prat_cam_on; - int cockpit_on; - int cockpit_image_index; - int current_render_left; - int current_render_top; - int current_render_right; - int current_render_bottom; - int frame_rate_headup; - int revs; - int music_volume; - int effects_volume; - int current_race_index; - int redo_race_index; - int credits_per_rank; - int game_completed; - int number_of_cars; - int current_car_index; - tWhich_view which_view; - tWhich_view new_view; - tWhich_view pending_view; - tWhich_view old_view; - tRace_sel_view_type view_type; - tProg_status prog_status; - tFrank_anne frank_or_anniness; - tAuto_parts_reply auto_parts_reply; - tCar_spec current_car; - char player_name[2][14]; - char track_file_name[14]; - char car_name[14]; - int cars_available[60]; - br_vector3 initial_position; - br_scalar initial_yaw; - tTrack_spec track_spec; - tDepth_effect default_depth_effect; - tDepth_effect current_depth_effect; - int special_volume_count; - tSpecial_volume* special_volumes; - br_material* standard_screen; - br_material* standard_screen_dark; - br_material* standard_screen_fog; - int special_screens_count; - tSpecial_screen* special_screens; - tIntelligent_vehicles AI_vehicles; - tNon_car_spec* non_cars; - int num_non_car_spaces; +typedef struct tProgram_state { // size: 0x356c + tS32 credits; // @0x0 + tS32 credits_earned; // @0x4 + tS32 credits_lost; // @0x8 + tU32 view_change_start; // @0xc + tU32 pratcam_move_start; // @0x10 + int peds_killed; // @0x14 + int sausage_eater_mode; // @0x18 + int rank; // @0x1c + int loaded; // @0x20 + int last_slot; // @0x24 + int skill_level; // @0x28 + int parts_shop_visited; // @0x2c + int racing; // @0x30 + int cut_scene; // @0x34 + int saving; // @0x38 + int loading; // @0x3c + int dont_save_or_load; // @0x40 + int dont_load; // @0x44 + int mirror_on; // @0x48 + int prat_cam_on; // @0x4c + int cockpit_on; // @0x50 + int cockpit_image_index; // @0x54 + int current_render_left; // @0x58 + int current_render_top; // @0x5c + int current_render_right; // @0x60 + int current_render_bottom; // @0x64 + int frame_rate_headup; // @0x68 + int revs; // @0x6c + int music_volume; // @0x70 + int effects_volume; // @0x74 + int current_race_index; // @0x78 + int redo_race_index; // @0x7c + int credits_per_rank; // @0x80 + int game_completed; // @0x84 + int number_of_cars; // @0x88 + int current_car_index; // @0x8c + tWhich_view which_view; // @0x90 + tWhich_view new_view; // @0x94 + tWhich_view pending_view; // @0x98 + tWhich_view old_view; // @0x9c + tRace_sel_view_type view_type; // @0xa0 + tProg_status prog_status; // @0xa4 + tFrank_anne frank_or_anniness; // @0xa8 + tAuto_parts_reply auto_parts_reply; // @0xac + tCar_spec current_car; // @0xb0 + char player_name[2][14]; // @0x1b4c + char track_file_name[14]; // @0x1b68 + char car_name[14]; // @0x1b76 + int cars_available[60]; // @0x1b84 + br_vector3 initial_position; // @0x1c74 + br_scalar initial_yaw; // @0x1c80 + tTrack_spec track_spec; // @0x1c84 + tDepth_effect default_depth_effect; // @0x1cb0 + tDepth_effect current_depth_effect; // @0x1cc0 + int special_volume_count; // @0x1cd0 + tSpecial_volume* special_volumes; // @0x1cd4 + br_material* standard_screen; // @0x1cd8 + br_material* standard_screen_dark; // @0x1cdc + br_material* standard_screen_fog; // @0x1ce0 + int special_screens_count; // @0x1ce4 + tSpecial_screen* special_screens; // @0x1ce8 + tIntelligent_vehicles AI_vehicles; // @0x1cec + tNon_car_spec* non_cars; // @0x3564 + int num_non_car_spaces; // @0x3568 } tProgram_state; typedef struct tDR_font { diff --git a/src/DETHRACE/macros.h b/src/DETHRACE/macros.h index 2ff70345..03726d01 100644 --- a/src/DETHRACE/macros.h +++ b/src/DETHRACE/macros.h @@ -55,23 +55,14 @@ (V2) = (T); \ } while (0) -#define ReadVector3(pF, a, b, c) \ - do { \ - float x[3]; \ - GetThreeFloats(pF, &x[2], &x[1], &x[0]); \ - a = x[2]; \ - b = x[1]; \ - c = x[0]; \ - \ - } while (0) - -#define ReadVector32(pF, a, b, c) \ - do { \ - float x[3]; \ - GetThreeFloats(pF, &x[2], &x[1], &x[0]); \ - b = x[2]; \ - c = x[1]; \ - a = x[0]; \ +#define ReadThreeFloats(pF, a, b, c) \ + do { \ + float x_0, x_1, x_2; \ + GetThreeFloats(pF, &x_0, &x_1, &x_2); \ + a = x_0; \ + b = x_1; \ + c = x_2; \ + \ } while (0) #define ReadPairOfFloats(pF, a, b) \ @@ -82,11 +73,4 @@ b = x[0]; \ } while (0) -#define DRVector3Scale(v1, v2, s) \ - do { \ - (v1)->v[0] = BR_MUL((v2)->v[0], s); \ - (v1)->v[1] = BR_MUL((v2)->v[1], s); \ - (v1)->v[2] = BR_MUL((v2)->v[2], s); \ - } while (0) - #endif diff --git a/src/library_msvc.h b/src/library_msvc.h index da42fecd..590d1ec0 100644 --- a/src/library_msvc.h +++ b/src/library_msvc.h @@ -214,7 +214,7 @@ // __loctotime_t // LIBRARY: CARM95 0x004EA9E0 -// __chkstk +// $$$00001(1) // GLOBAL: CARM95 0x0052D39C // __mb_cur_max @@ -224,3 +224,12 @@ // GLOBAL: CARM95 0x0052D190 // _pctype + +// GLOBAL: CARM95 0x004EAB82 +// __CIpow + +// GLOBAL: CARM95 0x004EA8DA +// __CIatan2 + +// GLOBAL: CARM95 0x004EA8C2 +// __CIasin