View Issue Details

IDProjectCategoryView StatusLast Update
0001777FSSCPgameplaypublic2008-09-28 00:24
ReporterKeldorKatarn Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version3.6.9 
Summary0001777: attack_set_accel () & evade_ship() bugs prevent AI from disengaging afterburners
DescriptionThere is a strange setting in above aicode.cpp functions that causes the AI to virtually never disengage the afterburners after they have been engaged by one of these functions. The reason for that is in a wrong setting of the afterburner_stop_time:

aip->afterburner_stop_time = Missiontime + F1_0 + static_rand(Pl_objp-Objects)/4;

since static_rand returns a 32bit integer this causes the AI in the worst case to keep the afterburners engaged for 2^32 / (F1_0 * 4) = 16,384 seconds.
I am pretty sure this is a retail behavior and I am also pretty sure it was not intended this way or at least it was fully intended to nearly always exhaust a ship's afterburner fuel.
Additional InformationSince this makes usage of AI ships with limited afterburner fuel impossible it needs to be fixed but without breaking retail behavior. I have attached a proposed fix that introduces a new flag to the ai_profiles which handles the new behavior.

The new behavior in short would be to make a ship evade another ship for 1.0 - 1.25 seconds and to accelerate to get to an enemy the minimum of the time to fly 75% of the distance to the enemy and the time to burn 25% of the remaining fuel.
TagsNo tags attached.

Activities

2008-09-26 05:32

 

ai_afterburner_fix.patch (3,277 bytes)   
Index: code/ai/ai_profiles.cpp
===================================================================
--- code/ai/ai_profiles.cpp	(revision 4831)
+++ code/ai/ai_profiles.cpp	(working copy)
@@ -363,6 +363,8 @@
 
 			set_flag(profile, "$allow event and goal scoring in multiplayer:", AIPF_ALLOW_MULTI_EVENT_SCORING);
 
+			set_flag(profile, "$new ai afterburner behavior:", AIPF_SMART_AFTERBURNER_USAGE);
+
 			// if we've been through once already and are at the same place, force a move
 			if ( saved_Mp && (saved_Mp == Mp) )
 				Mp++;
Index: code/ai/ai_profiles.h
===================================================================
--- code/ai/ai_profiles.h	(revision 4831)
+++ code/ai/ai_profiles.h	(working copy)
@@ -77,6 +77,7 @@
 #define AIPF_KILL_SCORING_SCALES_WITH_DAMAGE						(1 << 16)
 #define AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE						(1 << 17)
 #define AIPF_ALLOW_MULTI_EVENT_SCORING								(1 << 18)
+#define AIPF_SMART_AFTERBURNER_USAGE								(1 << 19)
 
 
 #define MAX_AI_PROFILES	5
Index: code/ai/aicode.cpp
===================================================================
--- code/ai/aicode.cpp	(revision 4831)
+++ code/ai/aicode.cpp	(working copy)
@@ -6033,7 +6033,12 @@
 		float percent_left = 100.0f * shipp->afterburner_fuel / sip->afterburner_fuel_capacity;
 		if (percent_left > 30.0f + ((Pl_objp-Objects) & 0x0f)) {
 			afterburners_start(Pl_objp);
-			aip->afterburner_stop_time = Missiontime + F1_0 + static_rand(Pl_objp-Objects)/4;
+			
+			if (The_mission.ai_profile->flags & AIPF_SMART_AFTERBURNER_USAGE) {
+				aip->afterburner_stop_time = Missiontime + F1_0 + static_randf(Pl_objp-Objects) * F1_0 / 4;
+			} else {				
+				aip->afterburner_stop_time = Missiontime + F1_0 + static_rand(Pl_objp-Objects)/4;
+			}
 		}
 	}
 
@@ -7584,8 +7589,30 @@
 					if (sip->afterburner_fuel_capacity > 0.0f) {
 						percent_left = 100.0f * shipp->afterburner_fuel / sip->afterburner_fuel_capacity;
 						if (percent_left > 30.0f + ((Pl_objp-Objects) & 0x0f)) {
-							afterburners_start(Pl_objp);
-							aip->afterburner_stop_time = Missiontime + F1_0 + static_rand(Pl_objp-Objects)/4;
+							afterburners_start(Pl_objp);							
+							if (The_mission.ai_profile->flags & AIPF_SMART_AFTERBURNER_USAGE) {
+								float max_ab_vel;
+								float time_to_exhaust_25pct_fuel;
+								float time_to_fly_75pct_of_distance;
+								float ab_time;
+
+								// Max afterburner speed - make sure we don't devide by 0 later
+								max_ab_vel = sip->afterburner_max_vel.xyz.z > 0.0f ? sip->afterburner_max_vel.xyz.z : sip->max_vel.xyz.z;
+								max_ab_vel = max_ab_vel > 0.0f ? max_ab_vel : 0.0001f;
+
+								// Time to exhaust 25% of the remaining fuel
+								time_to_exhaust_25pct_fuel = shipp->afterburner_fuel * 0.25f / sip->afterburner_burn_rate;
+
+								// Time to fly 75% of the distance to the target
+								time_to_fly_75pct_of_distance = dist_to_enemy * 0.75f / max_ab_vel;
+
+								// Get minimum
+								ab_time = min(time_to_exhaust_25pct_fuel, time_to_fly_75pct_of_distance);								
+								
+								aip->afterburner_stop_time = Missiontime + F1_0 * ab_time;
+							} else {				
+								aip->afterburner_stop_time = Missiontime + F1_0 + static_rand(Pl_objp-Objects)/4;
+							}
 						}
 					}
 				}
ai_afterburner_fix.patch (3,277 bytes)   

Goober5000

2008-09-27 05:52

administrator   ~0009710

Confirmed. And I approve of the patch. Change two things, and I'll commit it:

1) Make the line in ai_profiles.tbl more descriptive
2) Add the appropriate default in the ai_profiles.tbl default table in globalincs.

2008-09-27 12:04

 

ai_afterburner_fix_new.patch (4,002 bytes)   
Index: code/ai/ai_profiles.cpp
===================================================================
--- code/ai/ai_profiles.cpp	(revision 4831)
+++ code/ai/ai_profiles.cpp	(working copy)
@@ -363,6 +369,8 @@
 
 			set_flag(profile, "$allow event and goal scoring in multiplayer:", AIPF_ALLOW_MULTI_EVENT_SCORING);
 
+			set_flag(profile, "$AI supports limited afterburner fuel:", AIPF_AI_SUPPORTS_LIMITED_AFTERBURNER_FUEL);
+
 			// if we've been through once already and are at the same place, force a move
 			if ( saved_Mp && (saved_Mp == Mp) )
 				Mp++;
Index: code/ai/ai_profiles.h
===================================================================
--- code/ai/ai_profiles.h	(revision 4831)
+++ code/ai/ai_profiles.h	(working copy)
@@ -77,6 +77,7 @@
 #define AIPF_KILL_SCORING_SCALES_WITH_DAMAGE						(1 << 16)
 #define AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE						(1 << 17)
 #define AIPF_ALLOW_MULTI_EVENT_SCORING								(1 << 18)
+#define AIPF_AI_SUPPORTS_LIMITED_AFTERBURNER_FUEL					(1 << 19)
 
 
 #define MAX_AI_PROFILES	5
Index: code/ai/aicode.cpp
===================================================================
--- code/ai/aicode.cpp	(revision 4831)
+++ code/ai/aicode.cpp	(working copy)
@@ -6033,7 +6033,12 @@
 		float percent_left = 100.0f * shipp->afterburner_fuel / sip->afterburner_fuel_capacity;
 		if (percent_left > 30.0f + ((Pl_objp-Objects) & 0x0f)) {
 			afterburners_start(Pl_objp);
-			aip->afterburner_stop_time = Missiontime + F1_0 + static_rand(Pl_objp-Objects)/4;
+			
+			if (The_mission.ai_profile->flags & AIPF_AI_SUPPORTS_LIMITED_AFTERBURNER_FUEL) {
+				aip->afterburner_stop_time = Missiontime + F1_0 + static_randf(Pl_objp-Objects) * F1_0 / 4;
+			} else {				
+				aip->afterburner_stop_time = Missiontime + F1_0 + static_rand(Pl_objp-Objects)/4;
+			}
 		}
 	}
 
@@ -7584,8 +7589,30 @@
 					if (sip->afterburner_fuel_capacity > 0.0f) {
 						percent_left = 100.0f * shipp->afterburner_fuel / sip->afterburner_fuel_capacity;
 						if (percent_left > 30.0f + ((Pl_objp-Objects) & 0x0f)) {
-							afterburners_start(Pl_objp);
-							aip->afterburner_stop_time = Missiontime + F1_0 + static_rand(Pl_objp-Objects)/4;
+							afterburners_start(Pl_objp);							
+							if (The_mission.ai_profile->flags & AIPF_AI_SUPPORTS_LIMITED_AFTERBURNER_FUEL) {
+								float max_ab_vel;
+								float time_to_exhaust_25pct_fuel;
+								float time_to_fly_75pct_of_distance;
+								float ab_time;
+
+								// Max afterburner speed - make sure we don't devide by 0 later
+								max_ab_vel = sip->afterburner_max_vel.xyz.z > 0.0f ? sip->afterburner_max_vel.xyz.z : sip->max_vel.xyz.z;
+								max_ab_vel = max_ab_vel > 0.0f ? max_ab_vel : 0.0001f;
+
+								// Time to exhaust 25% of the remaining fuel
+								time_to_exhaust_25pct_fuel = shipp->afterburner_fuel * 0.25f / sip->afterburner_burn_rate;
+
+								// Time to fly 75% of the distance to the target
+								time_to_fly_75pct_of_distance = dist_to_enemy * 0.75f / max_ab_vel;
+
+								// Get minimum
+								ab_time = min(time_to_exhaust_25pct_fuel, time_to_fly_75pct_of_distance);								
+								
+								aip->afterburner_stop_time = Missiontime + F1_0 * ab_time;
+							} else {				
+								aip->afterburner_stop_time = Missiontime + F1_0 + static_rand(Pl_objp-Objects)/4;
+							}
 						}
 					}
 				}
Index: code/globalincs/def_files.cpp
===================================================================
--- code/globalincs/def_files.cpp	(revision 4831)
+++ code/globalincs/def_files.cpp	(working copy)
@@ -864,6 +870,10 @@
 ;; events in multiplayer												\n\
 $allow event and goal scoring in multiplayer: NO						\n\
 																		\n\
+;; if set, the AI can handle limited afterburner fuel					\n\
+;; and will be smarter in spending it									\n\
+$AI supports limited afterburner fuel: NO								\n\
 																		\n\
+																		\n\
 #End																	\n\
 ";
ai_afterburner_fix_new.patch (4,002 bytes)   

KeldorKatarn

2008-09-27 12:05

reporter   ~0009719

Line should be more descriptive now and is set to NO in FS2 RETAIL

Goober5000

2008-09-28 00:24

administrator   ~0009723

That's not quite what I meant... though actually it was the comment in the sample ai_profiles.tbl that would be better served by the description. I committed a slightly tweaked version of the patch.

Issue History

Date Modified Username Field Change
2008-09-26 05:32 KeldorKatarn New Issue
2008-09-26 05:32 KeldorKatarn File Added: ai_afterburner_fix.patch
2008-09-27 05:52 Goober5000 Note Added: 0009710
2008-09-27 05:52 Goober5000 Status new => confirmed
2008-09-27 12:04 KeldorKatarn File Added: ai_afterburner_fix_new.patch
2008-09-27 12:05 KeldorKatarn Note Added: 0009719
2008-09-28 00:24 Goober5000 Note Added: 0009723
2008-09-28 00:24 Goober5000 Status confirmed => resolved
2008-09-28 00:24 Goober5000 Resolution open => fixed