Allure-0.11.0.0: GameDefinition/Content/FactionKind.hs
-- Copyright (c) 2008--2011 Andres Loeh
-- Copyright (c) 2010--2021 Mikolaj Konarski and others (see git history)
-- This file is a part of the computer game Allure of the Stars
-- and is released under the terms of the GNU Affero General Public License.
-- For license and copyright information, see the file LICENSE.
--
-- | Definitions of kinds of factions present in a game, both human
-- and computer-controlled.
module Content.FactionKind
( -- * Group name patterns
pattern EXPLORER_REPRESENTATIVE, pattern EXPLORER_SHORT, pattern EXPLORER_NO_ESCAPE, pattern EXPLORER_MEDIUM, pattern EXPLORER_TRAPPED, pattern EXPLORER_AUTOMATED, pattern EXPLORER_AUTOMATED_TRAPPED, pattern EXPLORER_CAPTIVE, pattern EXPLORER_PACIFIST, pattern COMPETITOR_REPRESENTATIVE, pattern COMPETITOR_SHORT, pattern COMPETITOR_NO_ESCAPE, pattern CIVILIAN_REPRESENTATIVE, pattern CONVICT_REPRESENTATIVE, pattern MONSTER_REPRESENTATIVE, pattern MONSTER_ANTI, pattern MONSTER_ANTI_CAPTIVE, pattern MONSTER_ANTI_PACIFIST, pattern MONSTER_TOURIST, pattern MONSTER_TOURIST_PASSIVE, pattern MONSTER_CAPTIVE, pattern MONSTER_CAPTIVE_NARRATING, pattern ANIMAL_REPRESENTATIVE, pattern ANIMAL_MAGNIFICENT, pattern ANIMAL_EXQUISITE, pattern ANIMAL_CAPTIVE, pattern ANIMAL_NARRATING, pattern ANIMAL_MAGNIFICENT_NARRATING, pattern ANIMAL_CAPTIVE_NARRATING, pattern HORROR_REPRESENTATIVE, pattern HORROR_CAPTIVE, pattern HORROR_PACIFIST
, pattern EXPLORER_EXTERMINATOR, pattern ROBOT_REPRESENTATIVE, pattern ROBOT_CAPTIVE, pattern ROBOT_NARRATING, pattern ROBOT_VIRUS, pattern ROBOT_GAUNTLET, pattern OFF_WORLD_REPRESENTATIVE
, pattern REPRESENTATIVE
, pattern ANIMAL_OR_ROBOT_NARRATING
, groupNamesSingleton, groupNames
, -- * Content
content
#ifdef EXPOSE_INTERNAL
, hiHeroExterminator
#endif
) where
import Prelude ()
import Game.LambdaHack.Core.Prelude
import Game.LambdaHack.Content.FactionKind
import qualified Game.LambdaHack.Content.ItemKind as IK
import Game.LambdaHack.Definition.Ability
import Game.LambdaHack.Definition.Defs
import Game.LambdaHack.Definition.DefsInternal
import Content.ItemKindActor
import Content.ItemKindOrgan
-- * Group name patterns
groupNamesSingleton :: [GroupName FactionKind]
groupNamesSingleton =
[EXPLORER_REPRESENTATIVE, EXPLORER_SHORT, EXPLORER_NO_ESCAPE, EXPLORER_MEDIUM, EXPLORER_TRAPPED, EXPLORER_AUTOMATED, EXPLORER_AUTOMATED_TRAPPED, EXPLORER_CAPTIVE, EXPLORER_PACIFIST, COMPETITOR_REPRESENTATIVE, COMPETITOR_SHORT, COMPETITOR_NO_ESCAPE, CIVILIAN_REPRESENTATIVE, CONVICT_REPRESENTATIVE, MONSTER_REPRESENTATIVE, MONSTER_ANTI, MONSTER_ANTI_CAPTIVE, MONSTER_ANTI_PACIFIST, MONSTER_TOURIST, MONSTER_TOURIST_PASSIVE, MONSTER_CAPTIVE, MONSTER_CAPTIVE_NARRATING, ANIMAL_REPRESENTATIVE, ANIMAL_MAGNIFICENT, ANIMAL_EXQUISITE, ANIMAL_CAPTIVE, ANIMAL_NARRATING, ANIMAL_MAGNIFICENT_NARRATING, ANIMAL_CAPTIVE_NARRATING, HORROR_REPRESENTATIVE, HORROR_CAPTIVE, HORROR_PACIFIST]
++ [EXPLORER_EXTERMINATOR, ROBOT_REPRESENTATIVE, ROBOT_CAPTIVE, ROBOT_NARRATING, ROBOT_VIRUS, ROBOT_GAUNTLET, OFF_WORLD_REPRESENTATIVE]
pattern EXPLORER_REPRESENTATIVE, EXPLORER_SHORT, EXPLORER_NO_ESCAPE, EXPLORER_MEDIUM, EXPLORER_TRAPPED, EXPLORER_AUTOMATED, EXPLORER_AUTOMATED_TRAPPED, EXPLORER_CAPTIVE, EXPLORER_PACIFIST, COMPETITOR_REPRESENTATIVE, COMPETITOR_SHORT, COMPETITOR_NO_ESCAPE, CIVILIAN_REPRESENTATIVE, CONVICT_REPRESENTATIVE, MONSTER_REPRESENTATIVE, MONSTER_ANTI, MONSTER_ANTI_CAPTIVE, MONSTER_ANTI_PACIFIST, MONSTER_TOURIST, MONSTER_TOURIST_PASSIVE, MONSTER_CAPTIVE, MONSTER_CAPTIVE_NARRATING, ANIMAL_REPRESENTATIVE, ANIMAL_MAGNIFICENT, ANIMAL_EXQUISITE, ANIMAL_CAPTIVE, ANIMAL_NARRATING, ANIMAL_MAGNIFICENT_NARRATING, ANIMAL_CAPTIVE_NARRATING, HORROR_REPRESENTATIVE, HORROR_CAPTIVE, HORROR_PACIFIST :: GroupName FactionKind
pattern EXPLORER_EXTERMINATOR, ROBOT_REPRESENTATIVE, ROBOT_CAPTIVE, ROBOT_NARRATING, ROBOT_VIRUS, ROBOT_GAUNTLET, OFF_WORLD_REPRESENTATIVE :: GroupName FactionKind
groupNames :: [GroupName FactionKind]
groupNames = [REPRESENTATIVE, ANIMAL_OR_ROBOT_NARRATING]
-- This pattern was supposed to be used in faction lore to distinguish
-- the faction kinds to show. Instead all factions from the current game
-- are shown. Perhaps in the future we'll also show encountered actions
-- from previous games and then this will be useful to limit the number.
pattern REPRESENTATIVE :: GroupName FactionKind
pattern ANIMAL_OR_ROBOT_NARRATING :: GroupName FactionKind
pattern REPRESENTATIVE = GroupName "representative"
pattern EXPLORER_REPRESENTATIVE = GroupName "explorer"
pattern EXPLORER_SHORT = GroupName "explorer short"
pattern EXPLORER_NO_ESCAPE = GroupName "explorer no escape"
pattern EXPLORER_MEDIUM = GroupName "explorer medium"
pattern EXPLORER_TRAPPED = GroupName "explorer trapped"
pattern EXPLORER_AUTOMATED = GroupName "explorer automated"
pattern EXPLORER_AUTOMATED_TRAPPED = GroupName "explorer automated trapped"
pattern EXPLORER_CAPTIVE = GroupName "explorer captive"
pattern EXPLORER_PACIFIST = GroupName "explorer pacifist"
pattern COMPETITOR_REPRESENTATIVE = GroupName "competitor"
pattern COMPETITOR_SHORT = GroupName "competitor short"
pattern COMPETITOR_NO_ESCAPE = GroupName "competitor no escape"
pattern CIVILIAN_REPRESENTATIVE = GroupName "civilian"
pattern CONVICT_REPRESENTATIVE = GroupName "convict"
pattern MONSTER_REPRESENTATIVE = GroupName "monster"
pattern MONSTER_ANTI = GroupName "monster anti"
pattern MONSTER_ANTI_CAPTIVE = GroupName "monster anti captive"
pattern MONSTER_ANTI_PACIFIST = GroupName "monster anti pacifist"
pattern MONSTER_TOURIST = GroupName "monster tourist"
pattern MONSTER_TOURIST_PASSIVE = GroupName "monster tourist passive"
pattern MONSTER_CAPTIVE = GroupName "monster captive"
pattern MONSTER_CAPTIVE_NARRATING = GroupName "monster captive narrating"
pattern ANIMAL_REPRESENTATIVE = GroupName "animal"
pattern ANIMAL_MAGNIFICENT = GroupName "animal magnificent"
pattern ANIMAL_EXQUISITE = GroupName "animal exquisite"
pattern ANIMAL_CAPTIVE = GroupName "animal captive"
pattern ANIMAL_NARRATING = GroupName "animal narrating"
pattern ANIMAL_MAGNIFICENT_NARRATING = GroupName "animal magnificent narrating"
pattern ANIMAL_CAPTIVE_NARRATING = GroupName "animal captive narrating"
pattern HORROR_REPRESENTATIVE = GroupName "horror"
pattern HORROR_CAPTIVE = GroupName "horror captive"
pattern HORROR_PACIFIST = GroupName "horror pacifist"
-- ** Allure-specific
pattern ANIMAL_OR_ROBOT_NARRATING = GroupName "animal or robot narrating"
pattern EXPLORER_EXTERMINATOR = GroupName "explorer exterminator"
pattern ROBOT_REPRESENTATIVE = GroupName "robot"
pattern ROBOT_CAPTIVE = GroupName "robot captive"
pattern ROBOT_NARRATING = GroupName "robot narrating"
pattern ROBOT_VIRUS = GroupName "robot replicant"
pattern ROBOT_GAUNTLET = GroupName "robot virus-infested"
pattern OFF_WORLD_REPRESENTATIVE = GroupName "off-world mercenary"
-- * Teams
teamCompetitor, teamCivilian, teamConvict, teamMonster, teamAnimal, teamHorror, teamRobot, teamOffWorld, teamOther :: TeamContinuity
teamCompetitor = TeamContinuity 2
teamCivilian = TeamContinuity 3
teamConvict = TeamContinuity 4
teamMonster = TeamContinuity 5
teamAnimal = TeamContinuity 6
teamHorror = TeamContinuity 7
teamRobot = TeamContinuity 8
teamOffWorld = TeamContinuity 9
teamOther = TeamContinuity 10
-- * Content
content :: [FactionKind]
content = [factExplorer, factExplorerShort, factExplorerNoEscape, factExplorerMedium, factExplorerTrapped, factExplorerAutomated, factExplorerAutomatedTrapped, factExplorerCaptive, factExplorerPacifist, factCompetitor, factCompetitorShort, factCompetitorNoEscape, factCivilian, factConvict, factMonster, factMonsterAnti, factMonsterAntiCaptive, factMonsterAntiPacifist, factMonsterTourist, factMonsterTouristPassive, factMonsterCaptive, factMonsterCaptiveNarrating, factAnimal, factAnimalMagnificent, factAnimalExquisite, factAnimalCaptive, factAnimalNarrating, factAnimalMagnificentNarrating, factAnimalCaptiveNarrating, factHorror, factHorrorCaptive, factHorrorPacifist]
++ [factExplorerExterminator, factRobot, factRobotCaptive, factRobotNarrating, factRobotVirus, factRobotGauntlet, factOffWorld]
factExplorer, factExplorerShort, factExplorerNoEscape, factExplorerMedium, factExplorerTrapped, factExplorerAutomated, factExplorerAutomatedTrapped, factExplorerCaptive, factExplorerPacifist, factCompetitor, factCompetitorShort, factCompetitorNoEscape, factCivilian, factConvict, factMonster, factMonsterAnti, factMonsterAntiCaptive, factMonsterAntiPacifist, factMonsterTourist, factMonsterTouristPassive, factMonsterCaptive, factMonsterCaptiveNarrating, factAnimal, factAnimalMagnificent, factAnimalExquisite, factAnimalCaptive, factAnimalNarrating, factAnimalMagnificentNarrating, factAnimalCaptiveNarrating, factHorror, factHorrorCaptive, factHorrorPacifist :: FactionKind
factExplorerExterminator, factRobot, factRobotCaptive, factRobotNarrating, factRobotVirus, factRobotGauntlet, factOffWorld :: FactionKind
-- * Content
-- ** teamExplorer
factExplorer = FactionKind
{ fname = "Spacefarer"
, ffreq = [(EXPLORER_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]
, fteam = teamExplorer
, fgroups = [(HERO, 100)] -- don't spam the escapists, etc., in description
, fskillsOther = meleeAdjacent
, fcanEscape = True
, fneverEmpty = True
, fhiCondPoly = hiHeroLong
, fhasGender = True
, finitDoctrine = TExplore
, fspawnsFast = False
, fhasPointman = True
, fhasUI = True
, finitUnderAI = False
, fenemyTeams =
[teamCompetitor, teamMonster, teamAnimal, teamRobot, teamHorror]
, falliedTeams = []
}
factExplorerShort = factExplorer
{ ffreq = [(EXPLORER_SHORT, 1)]
, fhiCondPoly = hiHeroShort
}
factExplorerNoEscape = factExplorer
{ ffreq = [(EXPLORER_NO_ESCAPE, 1)]
, fcanEscape = False
, fhiCondPoly = hiHeroMedium
}
factExplorerMedium = factExplorer
{ ffreq = [(EXPLORER_MEDIUM, 1)]
, fhiCondPoly = hiHeroMedium
}
factExplorerTrapped = factExplorer
{ ffreq = [(EXPLORER_TRAPPED, 1)]
, fcanEscape = False
, fhiCondPoly = hiHeroLong
}
factExplorerAutomated = factExplorer
{ ffreq = [(EXPLORER_AUTOMATED, 1)]
, fhasUI = False
, finitUnderAI = True
}
factExplorerAutomatedTrapped = factExplorerAutomated
{ ffreq = [(EXPLORER_AUTOMATED_TRAPPED, 1)]
, fcanEscape = False
, fhiCondPoly = hiHeroLong
}
factExplorerCaptive = factExplorer
{ ffreq = [(EXPLORER_CAPTIVE, 1)]
, fneverEmpty = True -- already there
}
factExplorerPacifist = factExplorerCaptive
{ ffreq = [(EXPLORER_PACIFIST, 1)]
, fenemyTeams = []
, falliedTeams = []
}
-- ** teamCompetitor, symmetric opponents of teamExplorer
factCompetitor = factExplorer
{ fname = "Red Collar Bro"
, ffreq = [(COMPETITOR_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]
, fteam = teamCompetitor
, fhasUI = False
, finitUnderAI = True
, fenemyTeams = [teamExplorer, teamMonster, teamAnimal, teamRobot, teamHorror]
, falliedTeams = []
}
factCompetitorShort = factCompetitor
{ ffreq = [(COMPETITOR_SHORT, 1)]
, fhiCondPoly = hiHeroShort
}
factCompetitorNoEscape = factCompetitor
{ ffreq = [(COMPETITOR_NO_ESCAPE, 1)]
, fcanEscape = False
, fhiCondPoly = hiHeroMedium
}
-- ** teamCivilian
factCivilian = FactionKind
{ fname = "Civilian"
, ffreq = [(CIVILIAN_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]
, fteam = teamCivilian
, fgroups = [(HERO, 100), (CIVILIAN, 100)] -- symmetric vs player
, fskillsOther = zeroSkills -- not coordinated by any leadership
, fcanEscape = False
, fneverEmpty = True
, fhiCondPoly = hiHeroMedium
, fhasGender = True
, finitDoctrine = TPatrol
, fspawnsFast = False
, fhasPointman = False -- unorganized
, fhasUI = False
, finitUnderAI = True
, fenemyTeams = [teamMonster, teamAnimal, teamRobot, teamHorror]
, falliedTeams = []
}
-- ** teamConvict, different demographics
factConvict = factCivilian
{ fname = "Hunam Convict"
, ffreq = [(CONVICT_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]
, fteam = teamConvict
, fhasPointman = True -- convicts organize better
, finitUnderAI = True
, fenemyTeams = [teamMonster, teamAnimal, teamRobot, teamHorror]
, falliedTeams = []
}
-- ** teamMonster
factMonster = FactionKind
{ fname = "Alien Hierarchy"
, ffreq = [(MONSTER_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]
, fteam = teamMonster
, fgroups = [ (MONSTER, 100)
, (MOBILE_MONSTER, 1), (AQUATIC_MONSTER, 1) ]
, fskillsOther = zeroSkills
, fcanEscape = False
, fneverEmpty = False
, fhiCondPoly = hiDweller
, fhasGender = False
, finitDoctrine = TExplore
, fspawnsFast = True
, fhasPointman = True
, fhasUI = False
, finitUnderAI = True
, fenemyTeams = [teamExplorer, teamCompetitor, teamCivilian, teamConvict]
, falliedTeams = [teamAnimal, teamRobot]
}
-- This has continuity @teamMonster@, despite being playable.
factMonsterAnti = factMonster
{ ffreq = [(MONSTER_ANTI, 1)]
, fhasUI = True
, finitUnderAI = False
}
factMonsterAntiCaptive = factMonsterAnti
{ ffreq = [(MONSTER_ANTI_CAPTIVE, 1)]
, fneverEmpty = True
}
factMonsterAntiPacifist = factMonsterAntiCaptive
{ ffreq = [(MONSTER_ANTI_PACIFIST, 1)]
, fenemyTeams = []
, falliedTeams = []
}
-- More flavour and special backstory, but the same team.
factMonsterTourist = factMonsterAnti
{ fname = "Alien Tourist Office"
, ffreq = [(MONSTER_TOURIST, 1)]
, fcanEscape = True
, fneverEmpty = True -- no spawning
, fhiCondPoly = hiHeroMedium
, finitDoctrine = TFollow -- follow-the-guide, as tourists do
, fspawnsFast = False -- on a trip, so no spawning
, finitUnderAI = False
, fenemyTeams =
[teamAnimal, teamExplorer, teamCompetitor, teamCivilian, teamConvict]
, falliedTeams = [teamRobot]
}
factMonsterTouristPassive = factMonsterTourist
{ ffreq = [(MONSTER_TOURIST_PASSIVE, 1)]
, fhasUI = False
, finitUnderAI = True
}
factMonsterCaptive = factMonster
{ ffreq = [(MONSTER_CAPTIVE, 1)]
, fneverEmpty = True
}
factMonsterCaptiveNarrating = factMonsterAntiCaptive
{ ffreq = [(MONSTER_CAPTIVE_NARRATING, 1)]
, fhasUI = True
}
-- ** teamAnimal
factAnimal = FactionKind
{ fname = "Animal Kingdom"
, ffreq = [(ANIMAL_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]
, fteam = teamAnimal
, fgroups = [ (ANIMAL, 100), (INSECT, 100), (AQUATIC_ANIMAL, 100)
-- only the distinct enough ones
, (MOBILE_ANIMAL, 1), (IMMOBILE_ANIMAL, 1), (SCAVENGER, 1) ]
, fskillsOther = zeroSkills
, fcanEscape = False
, fneverEmpty = False
, fhiCondPoly = hiDweller
, fhasGender = False
, finitDoctrine = TRoam -- can't pick up, so no point exploring
, fspawnsFast = True
, fhasPointman = False
, fhasUI = False
, finitUnderAI = True
, fenemyTeams = [teamExplorer, teamCompetitor, teamCivilian, teamConvict]
, falliedTeams = [teamMonster, teamRobot]
}
-- These two differ from outside, but share information and boasting
-- about them tends to be general, too.
factAnimalMagnificent = factAnimal
{ fname = "Animal Magnificent Specimen Variety"
, ffreq = [(ANIMAL_MAGNIFICENT, 1)]
, fneverEmpty = True
, fenemyTeams =
[teamMonster, teamExplorer, teamCompetitor, teamCivilian, teamConvict]
, falliedTeams = []
}
factAnimalExquisite = factAnimal
{ fname = "Animal Exquisite Herds and Packs Galore"
, ffreq = [(ANIMAL_EXQUISITE, 1)]
, fteam = teamOther
-- in the same mode as @factAnimalMagnificent@, so borrow
-- identity from horrors to avoid a clash
, fneverEmpty = True
, fenemyTeams =
[teamMonster, teamExplorer, teamCompetitor, teamCivilian, teamConvict]
, falliedTeams = []
}
factAnimalCaptive = factAnimal
{ ffreq = [(ANIMAL_CAPTIVE, 1)]
, fneverEmpty = True
}
factAnimalNarrating = factAnimal
{ ffreq = [(ANIMAL_NARRATING, 1), (ANIMAL_OR_ROBOT_NARRATING, 70)]
, fhasUI = True
}
factAnimalMagnificentNarrating = factAnimalMagnificent
{ ffreq = [(ANIMAL_MAGNIFICENT_NARRATING, 1)]
, fhasPointman = True
, fhasUI = True
, finitUnderAI = False
}
factAnimalCaptiveNarrating = factAnimalCaptive
{ ffreq = [(ANIMAL_CAPTIVE_NARRATING, 1)]
, fhasUI = True
}
-- ** teamHorror, not much of a continuity intended, but can't be ignored
-- | A special faction, for summoned actors that don't belong to any
-- of the main factions of a given game. E.g., animals summoned during
-- a brawl game between two hero factions land in the horror faction.
-- In every game, either all factions for which summoning items exist
-- should be present or a horror faction should be added to host them.
factHorror = FactionKind
{ fname = "Horror Den"
, ffreq = [(HORROR_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]
, fteam = teamHorror
, fgroups = [(IK.HORROR, 100)]
, fskillsOther = zeroSkills
, fcanEscape = False
, fneverEmpty = False
, fhiCondPoly = []
, fhasGender = False
, finitDoctrine = TPatrol -- disoriented
, fspawnsFast = False
, fhasPointman = False
, fhasUI = False
, finitUnderAI = True
, fenemyTeams = [teamExplorer, teamCompetitor, teamCivilian, teamConvict]
, falliedTeams = []
}
factHorrorCaptive = factHorror
{ ffreq = [(HORROR_CAPTIVE, 1)]
, fneverEmpty = True
}
factHorrorPacifist = factHorrorCaptive
{ ffreq = [(HORROR_PACIFIST, 1)]
, fenemyTeams = []
, falliedTeams = []
}
-- * Allure-specific
factExplorerExterminator = factExplorer
{ ffreq = [(EXPLORER_EXTERMINATOR, 1)]
, fhiCondPoly = hiHeroExterminator
}
hiHeroExterminator :: HiCondPoly
hiHeroExterminator =
hiHeroShort
++ [([(HiConst, 200)], [Conquer])] -- bonus for extermination over escape
-- ** teamRobot
factRobot = FactionKind
{ fname = "Robot Anarchy"
, ffreq = [(ROBOT_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]
, fteam = teamRobot
, fgroups = [ (ROBOT, 100), (MECHANICAL_CONTRAPTION, 100)
, (MOBILE_ROBOT, 1), (IMMOBILE_ROBOT, 1)
, (CONSTRUCTION_ROBOT, 1) ]
, fskillsOther = zeroSkills
, fcanEscape = False
, fneverEmpty = False
, fhiCondPoly = hiDweller
, fhasGender = False
, finitDoctrine = TRoam
-- TODO:TFollow -- coordinated via net, follow alien leader
, fspawnsFast = True
, fhasPointman = False
, fhasUI = False
, finitUnderAI = True
, fenemyTeams = [teamExplorer, teamCompetitor, teamCivilian, teamConvict]
, falliedTeams = [teamMonster, teamAnimal]
}
factRobotCaptive = factRobot
{ ffreq = [(ROBOT_CAPTIVE, 1)]
, fneverEmpty = True
}
factRobotNarrating = factRobot
{ ffreq = [(ROBOT_NARRATING, 1), (ANIMAL_OR_ROBOT_NARRATING, 30)]
, fhasUI = True
}
factRobotVirus = factRobot
{ fname = "Replicant Infestation"
, ffreq = [(ROBOT_VIRUS, 1)]
, fteam = teamOther -- not the same as other robots
, fgroups = [(MOBILE_ROBOT, 100)] -- help assign proper actors to the faction
, fneverEmpty = True -- faction dissolved when all killed, despite spawning
, falliedTeams = [] -- cut off, weird
}
factRobotGauntlet = factRobotVirus
{ ffreq = [(ROBOT_GAUNTLET, 1)]
, fgroups = fgroups factRobotVirus ++ [(GAUNTLET_ROBOT, 1)]
-- keep the faction description the same, despite different composition
}
-- ** teamOffWorld
factOffWorld = factCompetitor
{ fname = "Gray Off-World Mercenary"
, ffreq = [(OFF_WORLD_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]
, fteam = teamOffWorld
, fgroups = [(MERCENARY_HERO, 100)] -- summoned heroes all go to the player
, fcanEscape = False
, fhiCondPoly = hiHeroMedium
, fenemyTeams = [teamExplorer, teamMonster, teamAnimal, teamRobot, teamHorror]
, falliedTeams = []
}