We had lot of new users and players who never played WiC before criticize our work for being completely unrealistic, including outlandish comments such as "helicopters never fly low in real life". But the most common criticisms were that helicopters fly *through* the ground, where their body becomes embedded inside terrain mesh and still nothing happens to them.
In the recent months, the PredictorFCS code base, which is a set of python scripts and C++ external link libraries we've written to facilitate fire control and weapons aiming in WiC has progressed and ventured into many areas that we once thought were impossible with WiC's limited modding support.
Recently we've worked on coding the auto-pilot and guidance control system for the BGM-109 Tomahawk missiles (where a game player no longer has to manually guide the missiles himself -- the missile automatically acquires and navigates to the area, locks onto the target at final stage, then attacks), we were spending lot of time during 2 weeks to write Inertial Navigation System simulation for WiC to guide a unit without having positive line of sight on the target.
You can see the auto-pilot script made for Tomahawk missiles in action here:
During the programming and research work in writing Inertial Navigation System (INS), one of us made an accidental discovery that we could control a unit's behavior over its lifetime throughout the game by running initialization "constructor" functions in python, in such a way that they link to an external script. This opened up a pandora's box for us in going beyond the guidance of cruise missiles.
The next step was to apply the unit's life-cycle effect behavior code into helicopter units. By being able to run a script constantly over unit's life cycle time, we are able to do things we've never done before in the past -- such as ground collision modeling.
Modeling the Ground Collision
Once we've gotten the above concept out of our way, we can now constantly check the radar altitude of each air unit as it is flying around in the game world. If altitude of the unit's bottom hitbox comes in contact with the ground (physics simulation), we simply apply damage to the unit at rate of -50 health points per 0.25 second. This means, if a helicopter barely scratches the ground, it will have little damage. If a helicopter does a hard crash, it will explode.
You can watch the video of ground collision modeling and GCAS warnings here:
Isn't this too much for an RTS? If I wanted a flight sim, I'm not playing WiC.
No, because, when the mod is completed, we are giving players two choices:
(1) You can elect to fly attack helicopter with Altitude-Hold auto-pilot enabled. This helicopter flies just like vanila WiC and you do not have to worry about colliding onto the ground or terrain mesh. This chopper has 16x air-to-ground missiles and 30mm cannon to give you lot of firepower too!
This auto-pilot enabled helicopter will be the default chopper for everyone to use.
(2) Or if you feel like being a pro air player and want to fly only 1 unit at a time and get a satisfying, rewarding feel of accomplishment, you can elect to fly our new Manual Flight Controlled attack helicopter, which uses the ground collision modeling we have outlined here!
The manual-flight attack helicopter has 8 air-to-ground missiles, 30mm cannon and also Hydra rockets, so you get lot of versatility. Most important of all, you can lower your altitude to evade radar guided SAM's.
If you want strategy-style gameplay, use the auto-pilot helicopter. But if you want flight-simulator style of feeling, use the new manual flight control helicopter to feel the Air role in its full glory!
Also, the next phase of the work is to implement altitude consideration into radar-guided SAM operations -- where, if an air target drops below 25wm AGL while a SAM radar is tracking it, the target simply disapears from the radar track and missile guidance is interrupted.
This will give us two features:
(a) Air pilots can raise altitude and wait for the SAM to fire on them, then quickly sink to low altitude to break the missile lock while the missile is en route. It is like dropping flares except you're not dropping any.
(b) It would also balance the game for support players too, because while air player can use altitude to his real advantage now, there is also inherent danger to that maneuver, where he could accidentally contact the ground in the process.
Right now, in the current version of mod, we do not model altitude for SAM guidance, only in a very primitive limited way for SAM target acquisition.
The new ground collision modeling allows us to really take altitude into context of game balancing to a degree that we were never been able to do before. Remember, there is a reason why you only control 2 helicopters maximum in MW Mod. It is to increase micro and reduce focus macro-work.
How do I "Land"? If I stop to get myself repaired, I'll crash and explode!
Simple. Engage "Hold-Fire" by pressing G key. Hold-fire will disable all of your weapons (Master Arm set to OFF), but will prepare your helicopter for landing operation. You can move around and stop in Hold-Fire condition without exploding/crashing to get repaired by repair vehicles.
Be sure to turn OFF Hold-Fire by pressing G key again when you're going back into combat! Otherwise none of your weapons will function, even if you issue force-attack orders.
Ground Collision Avoidance System (GCAS) "Bitching Betty"
To help air players avoid contact with ground and crash, we've spent some good deal of time writing a new program script to simulate GCAS in WiC.
Much of the GCAS was quickly written based on math codes done for PredictorFCS scripts, so the work is still in progress and need to be perfected at this stage. However, the principles of operation is as follows:
1. If a helicopter's altitude has a positive sink rate *and* its altitude hits below 25wm AGL, we sound 'ALTITUDE!' warning to let the player know that he's in the dangerous altitude area.
2. If a helicopter remains below 25wm AGL, we stay quiet so we don't spam the player with overly excessive nuisance warnings. We assume that air player is executing nap-of-the-earth (NOE) flight navigation when his altitude constantly remains low.
3. If the helicopter's altitude has a negative sink rate (increasing) and hits above 55wm AGL, we reset the altitude warning counter. Altitude warning will now be given again to alert the player if altitude drops below 25wm.
This was the easy part.
Now comes the harder part for us...
TERRAIN COLLISION WARNING
1. The script builds a historical log of the world Vector positions of the helicopter every 0.5 second and records the average flying speed and descent speed of the chopper.
2. The script uses the inertial navigation principle of "dead reckoning" to estimate the helicopter's predicted flying point 2 seconds ahead of itself, based on current unit heading azimuth, speed and the historical record of previous Vector positions.
3. Once the INS (inertial navigation system) produces the predicted move point, we request radar altitude of the terrain through the game application and apply our helicopter's current altitude sink rate.
4. If the sink rate at the predicted move point becomes too excessive in such a way that a contact with ground may occur 2 seconds from now, we immediately raise an alarm and sound 'PULL UP! PULL UP!' warning messages to the player. Also a text message of "GCAS BREAK X" will be displayed to the screen to get the attention of the player.
For geeks, here is a code snippet of our Ground Collision Avoidance System, written in Python for WIC.
""" VMU/GCAS Alert Abstraction
Basic abstract code to perform altitude "look ahead" check using inertial navigation principles.
Alerts the player if we're about to come in contact with ground.
2010/11/01 WIC MW Mod Missile and Fire Control Wicmwmod.com
$PredictorFCS: src/wic-UPDATE11/ClientServerModules/python/us_gcas_process.py,v 1.3126.96.36.199.1 2010/11/02 08:55:14 roycewicz Exp $
timenow = wic.common.GetCurrentTime()
timesince3 = timenow - self.MsgTimer33
# VMU / GCAS Alert Abstraction
if self.MsgFlag == 1:
# Rate-limit Bitching Betty so we don't spam the player with endless non-sense
if timesince3 >= 1:
self.MsgFlag = 0
# Check standby altitude on whether we're hitting the warning ceiling.
if self.NewAlt <= 25:
if self.Host.IsMoving() != True and self.Host.HoldFire == False and self.DescentWarned == 0:
PdFCS.com.exp.teamchat ( "AH-64D", 2, "<#ff0>CHECK LANDING GEAR!</> (Turn on Hold-Fire (Press G) to land safely.)")
PdFCS.com.exp.juicesound ( s2i("bitching_betty_landing_gear"), True)
self.DescentWarned = 1
elif self.DescentWarned == 0:
PdFCS.com.exp.teamchat ( "AH-64D", 2, "<#ff0>ALTITUDE! ALTITUDE!</>")
PdFCS.com.exp.juicesound ( s2i("bitching_betty_altitude"), True)
self.DescentWarned = 1
elif self.NewAlt >= 55:
self.DescentWarned = 0
if self.Host.IsMoving() and self.GCAScheckFlag == 1:
# Ground Collision Avoidance System (GCAS) Check Routine
if self.GCASwarningLimit >= 10:
self.GCASwarningLimit = 1
# Inertial Navigation System (INS) for Altitude Sink Rate
# Dead-Reckoning check on Y axis to predict our altitude closure rate relative to ground radar altitude
AltDelta = self.OldAlt - self.NewAlt
if AltDelta > 0:
NextAlt = self.NewAlt - ( AltDelta * timesince3 )
if NextAlt <= 2 and self.GCASwarningLimit <= 4:
# GCAS BREAK if descent rate exceeds predicted ground collision point
PdFCS.com.exp.teamchat ( "AH-64D", 1, "<#f00>GCAS BREAK X</> <#ff0>PULL UP! PULL UP!</> (Press T and Move far away!)")
PdFCS.com.exp.juicesound ( s2i("bitching_betty_pullup"), True)
self.GCASwarningLimit += 1
self.GCAScheckFlag = 0
# Terrain Correlation INS Check (TAINS) to see if air player is driving us into a hill.
# Match flight heading and predicted trajectory along terrain mesh matrix
INSstepPoint = wic.common.math.Vector3( 0.0, 0.0, 0.0 )
# TERCOM look-ahead check based on our heading azimuth and estimated inertial velocity
# Avg inertia = 28m(s-1), look ahead time = 2(s), 270 degrees = 4.71 radians appx
INSstepPoint.Z = self.Host.Position.Z + pdFCS.com.exg.GetTotalVelocityVector( self.Host, 1 ) * 2 * pdFCS.math.cos( 4.71 - self.Host.BodyHeading )
INSstepPoint.X = self.Host.Position.X + pdFCS.com.exg.GetTotalVelocityVector( self.Host, 1 ) * 2 * pdFCS.math.sin( 4.71 - self.Host.BodyHeading )
INSstepPoint.Y = round( wic.common.GetY( INSstepPoint.X, INSstepPoint.Z, True, True ), 2 )
INSpredictedAltHold = self.Host.Position.Y - INSstepPoint.Y
CollisionFlag = self.NewAlt / 1.6
# Is the air player pulling an RMS Titanic?
if INSpredictedAltHold <= 10 and INSpredictedAltHold <= CollisionFlag and self.GCASwarningLimit <= 10 and self.GCAScheckFlag == 1:
# Terrain ahead! GCAS BREAK
PdFCS.com.exp.teamchat ( "AH-64D", 1, "<#f00>GCAS BREAK X</> <#ff0>TERRAIN! TERRAIN! PULL UP! PULL UP!</> (Press T and Move far away!)")
PdFCS.com.exp.juicesound ( s2i("bitching_betty_pullup"), True)
self.GCASwarningLimit += 2
# Update our altitude log and rate limiter index
self.GCASwarningLimit += 1
self.GCAScheckFlag = 1
self.MsgTimer33 = wic.common.GetCurrentTime()
self.MsgFlag = 1
self.OldAlt = round( ( self.Host.Position.Y - wic.common.GetY( self.Host.Position.X, self.Host.Position.Z, True, True ) ), 2 )
That is it! As our motto always says: We balance gameplay with more realism™