-- 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 = [] }