FLAK
------------------------------------
Fleet Action Kombat
Introduction
=============
This is a multi-ship combat engine, intended to be used with PHost.
It can probably also be used with HOST, although that has not been
tested. It was designed in a joint venture of the PHost,
Planetsserver, Blutmagie and Vagabond people.
It is intended to be "plug-compatible" with existing ship lists. In
1:1 combat, it attempts to mimic PVCR as close as possible. It was
designed to be easy to use, for players and hosts.
The server is a portable open-source application based on the PDK,
included with the PCC2 source code.
The client-side viewer is available in multiple versions:
- included with PCC2/PlayVCR, portable, open-source application
that runs on Windows and Linux: <http://phost.de/~stefan/pcc2.html>
- built into PCC2 Web and the PCC2 Web Battle Simulator on
PlanetsCentral: <https://planetscentral.com/play/sim.cgi>
- as a DOS application, derived from PCC1: <http://phost.de/~stefan/flak/>
- as part of PCC2ng (c2ng) which is currently in development:
<http://phost.de/~stefan/pcc2ng.html>
Basic Concepts
===============
The main problem with standard one-on-one combat is that small ships
cannot team up against a big ship. In FLAK, they can. (Note that
we'll use the term 'ship' when we actually mean 'ship or planet'.
Planets behave mostly the same way as ships.)
For each fight, you can form fleets. Each fleet will attack an enemy
ship which matches their fighting strength. For example, a group of
5 Rubies will rather attack a Cube rather than a single Outrider,
because a Cube comes closer to the fighting strength of a five
Rubies. Conversely, 5 groups of one Ruby each will attack the
Outrider, since they independantly decide that a single Ruby is too
small to attack a Cube. Therefore, you can make targeting decisions
by defining small or large groups.
The rule to remember is: fleets attack ships. It does not matter whether
the enemy ship is part of a fleet or whether it fights alone.
To form fleets, use the battle-order friendly codes. Normally, you
can have up to 12 fleets in each fight, depending on the first digit
of the battle order:
1: -99 .. -1
2: 0 .. 99
3: 100 .. 199
...
11: 900 .. 999
12: non-numerical fcodes
Only the order matters. With friendly codes 102 193 409 444 lfm, you'll
get three groups:
102 193
409 444
lfm
The first one (with lowest battle order) starts closest in, followed
by the second one, etc. You cannot affect distance between groups,
i.e. if the friendly codes were 002 003 898 899 900, the overall
picture would look the same: 3 groups, equal distances between groups:
002 003
898 899
900
Planets will always fight alone, as a 13th group. Their relative
position in the battle setup is defined by their friendly code.
Hosts can restrict the maximum fleet size. If you define a group
with too many ships, FLAK will split it up. This way you might end up
with more groups.
Immunities and other Exceptions
--------------------------------
There are a number of "X cannot attack Y" rules. These are quite
problematic for a fleet combat engine. If you have some fleet, which
has an "X" member, and that fleet decides to attack "Y", "X" surely
shall not sit there twiddling thumbs.
The rule is: if no member of your fleet can attack a particular
target, they'll leave that target alone. If someone can attack and
someone can not, they will probably attack it, but they prefer ships
which everyone can attack.
Likewise, PHost has the Aggressor/Opponent concept. If you have no
primary enemy and not the "Kill" mission, your ships will sit there
patiently and wait to be attacked by some Aggressor. In FLAK, they'll
get active. Once it has been determined that your ship will take part
in combat, it will be aggressive.
The rule is: if someone is aggressive to you, you are also aggressive
to them.
Ships which are not a possible target for anyone will not take part in
the fight. For example, in deep space, noone can attack a fuelless ship,
so that ship will be left out. Likewise, if Lizards, Tholians and Borg
meet, but all the Lizards have primary enemy Tholian, all the Tholians
have primary enemy Lizards, and the Borg have no PE/Kill order, the Borg
will not take part in the fight.
The rule is: if you do not want to attack, and nobody wants to attack
you, you do not fight.
- "Ships with matching friendly codes cannot attack". If someone in a
fleet says 'My friendly code does not match, let's attack them', the
fleet will attack. Only if the friendly codes of all ships match,
they'll be safe. It is slightly less likely that a fleet attacks a
ship when there is at least one ship with matching code.
- "Fuelless ships cannot attack or be attacked". If a NUK planet
takes part in the fight, that planet will fight the ship.
Otherwise, the ship will not take part. (Actually, the ship will
attack the planet, because planets obviously cannot move towards
the ship.)
- "Nobody can attack a cloaked ship". If you match their PE, the
cloaked ship will decloak in order to attack you. Which you can
obviously use to attack them with your full forces.
- "Planets cannot attack Klingons or Rebels". This rule is enforced.
If the Klingon or Rebel does not want to attack the planet, the
planet will not fight them.
- "Planets cannot attack Super Star Destroyers". If the SSD is not
aggressive (no PE, no kill), it will not take part in the
fight. Therefore, this rule is enforced as well.
Intercept-attack is another special rule. If some intercept-attack
happens, an extra battle will be fought before normal combat. For
example, if a Lizard Class Cruiser intercepts an MBR, and the MBR
intercepts a Loki, these 3 ships will fight first, using the usual
rules.
Targeting in a Nutshell
------------------------
Note that these rules all take part in a big formula (see below). This
is not a "checklist".
o We prefer ships that match our size.
o We prefer slightly smaller ships over slightly bigger ones.
o We prefer ships matching our PE over those which don't match.
o We prefer ships which everyone can attack over ships which match one
of our friendly codes.
o We prefer damaged ships over undamaged ones.
o We prefer close targets over far ones.
o We prefer firing at our current target over switching to a new one.
Multi-Ship Effects
-------------------
Of course, a proper multi-ship combat engine does something more than
blindly extending 1:1 rules for multiple ships at once.
o Proper 2-D movement. Ships avoid crashing into each other. Two
fighting units will stop approaching each other at
StandoffDistance, as usual. Unrelated ships avoid coming closer
than 50% StandoffDistance. If some ships do come too close, they'll
automatically step aside a bit. Own ships maintain at least 25%
StandoffDistance. Fighters, torpedoes, or beam shots are small, and
do not avoid (or hit) objects in the way.
Note that this does mean 2-D. The 3-D display is just eye-candy;
the third dimension has no effect on the rules.
o Smarter fighters. If a target dies while a fighter is underway,
the fighters will automatically advance to the next target. If a
fighter's base dies, it will pick a new one. This might result in
an overloaded ship at the end of the turn, in which case the
excess fighters are destroyed.
o Smarter torpedoes. If a torpedo moves towards a target, but that
target dies inbetween, the torpedo randomly hits another member of
the target's fleet. Ships inside a fleet communicate to not waste
torpedoes. If only 10 torps are needed to smash an enemy, five
torpers in a fleet would fire 2 torps each (actually, they'll
probably fire 4 torps each to account for missing torpedoes and
still have some safety; but still a lot of savings compared to 10
torps each).
If a torpedo ship dies, other ships from its fleet will gather up
its torpedoes when they can carry them. This way, torpedo ships
(like carriers) can pick up material from their less fortunate
peers, to reduce losses. Likewise, if a torpedo hits a ship that
is already dead, it may ricochet and hit another ship of its
target fleet.
o Fleet combat requires more concentration from ship commanders than
1:1 combat. Therefore, if you come in with a big armada, you'll get
a slight penalty. So avoid taking ships into combat which do not
have enough offensive capability. (This is our lame excuse for the
compensation cheat, see below.)
o A ship's beams will fire at fighters which attack that ship's fleet,
or which belong to its target's fleet. Likewise, fighters will
intercept enemy fighters that target your fleet or which belong to
their enemy. Unrelated fighters will be left alone.
Another important effect is that attackers get more information
about their opponents than in 1:1 combat. If you attack a planet
with a scout, you'd normally only see the one ship which smashes
your probe. With FLAK, you'll see the whole armada awaiting you.
Conclusion of a Fight
----------------------
While in normal 1:1 combat, it is clear who captures whom, matters
are more complicated in multi-ship combat. Currently, FLAK
implements a very simple model:
o Death or capture is declared at the end of each battle tick.
Everything happens simultaneously. If a ship is hit by a lethal
beam, it is still allowed to fire its own beam. It dies at the end
of the battle tick.
o When a ship gets captured, it is captured by the ship who placed
the last shot on it during the tick when it died. Therefore, if
many ships fight against one ship, it is more or less random who
will get it.
- If the captor dies after capturing a ship, but there are still
other ships of his people, one of these will take the prey.
- If all the captor's ships are dead, but there are still ships
belonging to the people of the captured ship, one of those will
take control of the ship (i.e. capture it back).
- Otherwise, a random ship from the survivors is picked who takes
the crewless ship. If everyone else's dead, the ship explodes.
PAL/PBP and experience is awarded to race who finally captured the
ship. Note that no points are awarded if captor and captee are
allied, but full points are given (to the original owner) in case
of capture back!
o If the ship gets destroyed, or there is no surviving captor,
PAL/PBP and experience are awarded to the player whose ship
placed the last shot.
o Experience is handled slightly different in FLAK. Normally,
experience formulas have the form `their_mass * score / my_mass'.
In FLAK, the computation is `sum(mass_i * score_i) / sum(my_masses)',
for each ship `i' which entered the battle (`Score' is
EPCombatKillScaling, for example).
For example, when two 300 kt ships destroy a 500 kt ship, each is
awarded 500*800 / (300+300) = 666 points. Conversely, if the 500
kt ship wins, it gets (300*800 + 300*800) / 500 = 960 points.
All participating ships get the same amount of points. If we
replace the two 300 kt ships by a 580 kt battleship and a 20 kt
probe, results are the same: 500*800 / (580+20) = 666.
Differences to 1:1 Combat
--------------------------
When just two ships fight, results are intended to be close to
normal PVCR combat, but not identical. Here are all known
differences of FLAK to PVCR _for a one-on-one setup_.
o Torps need time to travel (and continue to travel after the torper
died)
o Fighters continue firing when their carrier dies
=> Effect: this can lead to a result of mutual annihilation which is
not possible in PVCR (but which is possible in Tim's VCR).
o All clean-up (removal of dead units) happens at once, not in the
middle of a battle tick.
=> Effect: more fairness, but also makes mutual annihilation more
likely.
o The fighter limit is `2 * Num_bays' (a big carrier can have more
fighters out than a small one; in PVCR, they have the same limit,
namely MaxFightersLaunched).
=> Effect: small. In PVCR, ships hardly ever get more fighters out
than our limit. However, in FLAK, ships often start farther out
and therefore have more time to launch fighters. Therefore, a
group of small carriers gets overly strong without this change.
o FLAK does not use the BeamHitFighterRange parameter; the
BeamFiringRange is used for fighters as well.
=> Effect: small. However, in big fights, this avoids that ships
fire across the whole battle arena, which simply looks dumb :)
o Only one fighter intercept per race pair (that is, in 1:1 combat,
only one fighter intercept at all per tick).
=> Effect: small. In big fights, unlimited fighter intercept would
lead to too many losses, though.
Considering PList, carriers tend to get a bit stronger with FLAK.
An Exterminator-vs.-Death-Star fight yields a 50/50 chance for each
ship to win. In FLAK, the Exterminator usually dies.
Formulas
=========
o Targeting. We pick the ship where
(Abs(Our_rating - Their_rating) + 100) * Multiplier / Divisor
yields the smallest value. Here,
- Our_rating is the sum of the ratings of all ships in our fleet
which can possibly attack the target (a ship with just death rays
cannot attack a planet). See below for how these ratings are
computed.
- Their_rating is the rating of the target ship
- Multiplier contains factors which make choosing this target less
likely. Summarized, this is the time needed to reach it.
. Multiplier = Distance / Movement_speed (time to reach target)
. Multiplier is at least 50
. for planets, we assume a Movement_speed of 100.
- Divisor consists of a number of bonuses which make choosing this
target more likely. Summarized, this decides how easy it would be
to kill that target.
. start with 100
. add 50 if target is smaller than we (Our_rating >= Their_rating)
. add targeting modifiers (see under configuration) to prefer
ships which match our PE, and to prefer ships which do not match
friendly codes
. add damage of the enemy (0..100)
. add one for each 5 shield points already lost by the target
. add 50 if we are already attacking that target
o Compensation Cheat. Applying normal combat formulas to multi-ship
combat yields an effect we call 'overcompensation'. Assuming equal
ships, a 10-vs-10 scenario yields random distribution of results,
which is what we want. However, slight imbalance will have a much
larger effect than the imbalance suggests. For example, in a
12-vs-10 situation, the 12-side usually keeps 6 ships, not 2. This
effect is perfectly logical, but it is not desirable for our game:
it somehow 'linearizes' combat (a 12/12 ship is twice as powerful
as two 6/6 ships), which was not intended by ship list designers
(the 12/12 ship costs much more than two 6/6 ships). Therefore,
FLAK cheats: if someone places a shot, and he has fewer ships than
his target, he will receive a bonus. The bonus is computed as
(Target_strength + 1000) / (Our_strength + 1000)
A typical top ship has a strength of 500. In our example, the 10-ship
side receives a bonus of 7000 / 6000 = 1.16 = +16%. The maximum bonus
is 2 = +100%.
The bonus is implemented by scaling down the target's mass for
computing weapon effects. In our example, if the target had a mass
of 420 kt, it would, for purposes of weapon computations, be scaled
down to 420 / 1.16 = 360 kt.
If the bonus value is below 1.0, no modifications are applied to the
formulas (i.e. the bonus never turns into a penalty).
Configuration
==============
The battle engine is highly configurable. The defaults are sensible,
but we want to allow everyone to try to tweak and improve the
behaviour. If you have some good settings, please share them with
us!
o Targeting Ratings. The following options define the targeting
mechanism.
RatingMassScale = 1
RatingBeamScale = 1
RatingTorpScale = 1
RatingFighterScale = 8
The rating of a ship is
RatingMassScale * Ship_mass
+ RatingBeamScale * Beam_type * Beam_count
+ RatingTorpScale * Torp_type * Tube_count
+ RatingFighterScale * Bay_count
The idea should be that two ships which are comparable in combat
should have similar ratings. In fight, ships always choose "matching"
targets, which match their rating as close as possible. These defaults
should work for all ship lists.
o Targeting modifiers. These configure how intense "other factors" affect
targeting.
RatingPEBonus = 20
applies if someone has this race as Primary Enemy.
RatingFullAttBonus = 20
applies if all ships from this group are aggressive (no FC match).
RatingRandomBonus = 20
a random bonus 0 <= x < RatingRandomBonus is always given. Recall
that ships usually accept targets which match their rating as close
as possible. By giving one of these bonuses, they're accepting a
greater tolerance for a matching ship. For example, setting
RatingPEBonus = 500 will cause ships to rush at matching PE ships,
ignoring most other conditions.
In addition, a bonus of +50 is given if our target is smaller than
we, and another +50 if we're keeping a target we're already
attacking; these figures are not configurable.
o Initial positions.
StartingDistanceShip = 26000
StartingDistancePlanet = 10000
These parameters define the initial distance from the center for each
unit.
StartingDistancePerPlayer = 1000
For each player taking part in the fight, the distance is increased
by this value (e.g. +5000 in a 5-player fight).
StartingDistancePerFleet = 5000
Fleets start this many meters apart.
In a ship-only fight, starting positions are assigned on a circle.
In a planet-vs.-ships fight, the ship-only races start in a half-
circle on the left, and the planet starts on the right side.
o Compensation.
CompensationShipScale = 0
CompensationBeamScale = 30
CompensationTorpScale = 90
CompensationFighterScale = 90
CompensationLimit = 500
The compensation weight for a ship is
CompensationShipScale
+ CompensationBeamScale * Beam_count
+ CompensationTorpScale * Tube_count
+ CompensationFighterScale * Bay_count
but at most CompensationLimit. Note that, unlike for targeting
ratings, weapon types have no effect. The above values are for PList;
double all the 'Scale' parameters for the standard ship list. You can
set all values to zero to turn off compensation, but this is not
recommended.
o Fleet Size Limit
MaximumFleetSize = 999
This parameter gives the maximum size for a fleet. If a player has
more ships than that with similar battle order, FLAK will build
two fleets. Sensible values start in the magnitude of 10 or 20.
Note that FLAK might build even smaller fleets sometimes. For
example, assume a group of 15 ships, two of them are fuelless, and
a MaximumFleetSize of 10. FLAK will build up fleets first, one
with 10 ships and one with the remaining 5. After noticing that
the fuelless ships cannot be attacked by someone else (which is
not obvious from the start; there could be a NUKing planet
around), FLAK will remove them from their group. Therefore, you'll
probably end up with an 8/5 split instead of the expected 10/3.
The default value accepts all sizes and never splits fleets.
However, in Ragnarok-style endfights, it makes sense to split
fleets to avoid making the fight look too stupid :).
FLAK uses almost all the PHost battle parameters.
o MaxFightersLaunched is not used. The fighter limit is hardwired to
twice the number of fighter bays on each ship.
o BeamHitFighterRange is not used. FLAK uses BeamFiringRange for
firing at fighters, too.
Miscellaneous
==============
FLAK combat data is transmitted in 'flakX.dat' files Although normal
combat (a handful of ships) will only need some hundred bytes, a
Ragnarok-style fight (all ships at once) can take up to 500k. Be
careful. If you are not yet sending your players zipped results, you
probably should now. (This large amount of memory can mainly be
attributed to the fact that FLAK is highly configurable, and that we
can change many aspects of a fight without having to exchange the
viewer application. Maybe we'll switch to a less flexible but
smaller format later.)
The FLAK viewer needs the 'pconfig.src'/'shiplist.txt' file to play
combat. It does not need the FLAK configuration itself.
The viewer will tell you if it encounters a fight it cannot play. That
is, if the server application does need an incompatible change, you will
not see bogus results.
Why FLAK?
==========
The 1:1 combat has been a point of criticism in VGAP since its
conception.
FLAK is not the first multi-ship combat system. There are some
earlier systems, namely TKF (The Killing Floor) and TVCR2 (Tactical
VCR 2).
Unfortunately, those systems are largely undocumented and
closed-source. FLAK aims to be a well-designed and documented combat
system. In particular, it aims at being a reasonable choice with
ship lists designed for PHost combat, and it aims to be friendly to
automatic hosting on a Linux server.
Cast of Characters
===================
- Design, Ideas and Simulations -
(in no particular order)
Matthias Degenhardt
Sascha Rambeaud
Stefan Reuther
Alexander Babanov
Thomas Voigt
Stefan Glasauer
- Coding -
Stefan Reuther
- Beer -
Olaf Selke
Christian Brückner
-eof-