Advertisement
SarahNorthway

Rebuild 3 MoraleEvents.as

Jul 16th, 2019
765
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package rebuild3.events
  2. {
  3.     import flash.utils.Dictionary;
  4.     import rebuild3.*;
  5.     import rebuild3.colins.*;
  6.     import rebuild3.events.*;
  7.     import rebuild3.events.quests.*;
  8.     import rebuild3.factions.*;
  9.     import rebuild3.fort.*;
  10.     import rebuild3.game.*;
  11.     import rebuild3.game.sound.*;
  12.     import rebuild3.game.starling.*;
  13.     import rebuild3.gui.*;
  14.     import rebuild3.gui.main.*;
  15.     import rebuild3.gui.text.*;
  16.     import rebuild3.gui.widgets.*;
  17.     import rebuild3.map.*;
  18.     import rebuild3.missions.*;
  19.  
  20.     /**
  21.      * Contains static functions for executing daily morale events.
  22.      *
  23.      * @author Sarah Northway
  24.      */
  25.     public class MoraleEvents extends EventsBase
  26.     {
  27.         public function MoraleEvents()
  28.         {
  29.         }
  30.  
  31.         /**
  32.          * Only run in midgame and later when people are at least somewhat unhappy.
  33.          */
  34.         public static function frequency():Number
  35.         {
  36.             if (Config.ONLY_ALLOWED_EVENTS != null && Config.ONLY_ALLOWED_EVENTS != "morale") {
  37.                 return 0;
  38.             }
  39.  
  40.             if (Context.fort.happiness >= 40) {
  41.                 return 0;
  42.             }
  43.             if (Context.city.day < DayManager.MORALE_START_DAY) {
  44.                 return 0;
  45.             }
  46.             return 1;
  47.         }
  48.  
  49.         /**
  50.          * Warn that survivors are unhappy.
  51.          */
  52.         public static function warnUnhappy():Result
  53.         {
  54.             var colin:Colin = ColinManager.pickUnhappyColin();
  55.             if (colin == null) {
  56.                 return null;
  57.             }
  58.  
  59.             var result:Result = Text.fillEventResult(EventType.MORALE_WARN);
  60.             result.mentionedColin = colin;
  61.             return result;
  62.         }
  63.  
  64.         public static function suicide():Result
  65.         {
  66.             if (Context.fort.happiness >= 20) {
  67.                 return null;
  68.             }
  69.  
  70.             var colin:Colin = ColinManager.pickUnhappyColin();
  71.             if (colin == null) {
  72.                 return null;
  73.             }
  74.  
  75.             var result:Result = Text.fillEventResult(EventType.MORALE_SUICIDE);
  76.             result.mentionedColin = colin;
  77.             result.killMentionedColin("death_suicide");
  78.             return result;
  79.         }
  80.  
  81.         /**
  82.          * Two unhappy colins fight. One is injured or dies, you can decide how the other
  83.          * is punished.
  84.          */
  85.         public static function fight():Result
  86.         {
  87.             if (Context.fort.happiness >= 30) {
  88.                 return null;
  89.             }
  90.  
  91.             // peacekeeper perk often prevents fights, but MORALE_FIGHT event still flagged as happened
  92.             var peacekeeper:Colin = ColinManager.colinWithPerk(PerkType.PEACEKEEPER);
  93.             if (peacekeeper != null && Utils.getRandChance(2, 3)) {
  94.                 var resultAverted:Result = Text.fillEventResult(EventType.MORALE_FIGHT_AVERTED);
  95.                 resultAverted.mentionedColin = peacekeeper;
  96.                 return resultAverted;
  97.             }
  98.  
  99.             var result:Result = new Result();
  100.  
  101.             // mentionedColin is the culprit
  102.             var culprit:Colin = ColinManager.pickUnhappyColin(null, [result.mentionedColin]);
  103.             if (culprit == null) {
  104.                 Utils.log("Could not find a fight killer colin.");
  105.                 return null;
  106.             }
  107.             result.mentionedColin = culprit;
  108.  
  109.             // mentionedColin2 is the victim
  110.             var victim:Colin = ColinManager.pickUnhappyColin();
  111.             if (victim == null) {
  112.                 Utils.log("Could not find a fight victim colin.");
  113.                 return null;
  114.             }
  115.             result.mentionedColin2 = victim;
  116.  
  117.             // jail time is same as injury
  118.             // makes the perp unhappy and everyone else happy
  119.             var option1:Function = function(result:Result):Result {
  120.                 Text.fillEventResult(1, result);
  121.                 result.injureMentionedColin(false, true);
  122.                 // will gain happiness from vacation mission to make up for this
  123.                 result.addHappinessColin(-25, "happy_fightJailed");
  124.                 result.addHappiness(5, "happy_fightJustice");
  125.                 return result;
  126.             }
  127.  
  128.             // kick out of the fort (like killing), makes people happy
  129.             var option2:Function = function(result:Result):Result {
  130.                 Text.fillEventResult(2, result);
  131.                 result.killMentionedColin("death_fightExile", false);
  132.                 result.addHappiness(10, "happy_fightExile"); // death will be -5 so net is +5
  133.                 return result;
  134.             }
  135.  
  136.             // do nothing
  137.             var option3:Function = function(result:Result):Result {
  138.                 Text.fillEventResult(3, result);
  139.                 return result;
  140.             }
  141.  
  142.             // default to an injury
  143.             Text.fillEventResult(EventType.MORALE_FIGHT, result, [option1, option2, option3]);
  144.  
  145.             // victim dies sometimes instead of just injury
  146.             // sometimes the text will say there's no evidence, etc, but options always the same
  147.             var chanceOfDeath:Number = (30 - Context.fort.happiness) * (100 / 30);
  148.             if (ColinManager.injuryNotDeath(result.mentionedColin2, chanceOfDeath)) {
  149.                 ColinManager.injureColin(result.mentionedColin2, result);
  150.             }
  151.             if (result.injuredColins.length == 0) {
  152.                 // replace "fight" with "fightDeath" text
  153.                 result.killMentionedColin("death_fight", true, true);
  154.                 Text.replaceEventResult("fightDeath", result);
  155.             }
  156.  
  157.             return result;
  158.         }
  159.  
  160.         public static function deserter():Result
  161.         {
  162.             if (Context.fort.happiness >= 30) {
  163.                 return null;
  164.             }
  165.  
  166.             var faction:Faction = Utils.pickRandom(Context.city.factions);
  167.             if (faction == null) {
  168.                 return null;
  169.             }
  170.  
  171.             var colin:Colin = ColinManager.pickUnhappyColin();
  172.             if (colin == null) {
  173.                 return null;
  174.             }
  175.  
  176.             var result:Result = Text.fillEventResult(EventType.MORALE_DESERTER, null,
  177.                 null, faction.type.shortName);
  178.             result.mentionedColin = colin;
  179.             result.killMentionedColin("death_unhappyDeserted");
  180.             return result;
  181.         }
  182.  
  183.         public static function riots():Result
  184.         {
  185.             if (Context.fort.happiness >= 20) {
  186.                 return null;
  187.             }
  188.  
  189.             // peacekeeper perk often prevents riots, but MORALE_RIOTS event still flagged as happened
  190.             var peacekeeper:Colin = ColinManager.colinWithPerk(PerkType.PEACEKEEPER);
  191.             if (peacekeeper != null && Utils.getRandChance(2, 3)) {
  192.                 var resultAverted:Result = Text.fillEventResult(EventType.MORALE_RIOTS_AVERTED);
  193.                 resultAverted.mentionedColin = peacekeeper;
  194.                 return resultAverted;
  195.             }
  196.  
  197.             var result:Result = Text.fillEventResult(EventType.MORALE_RIOTS);
  198.             result.addEffect(City.EFFECT_RIOTING, 2);
  199.             return result;
  200.         }
  201.  
  202.         public static function theft():Result
  203.         {
  204.             if (Context.fort.numFood < 5) {
  205.                 return null;
  206.             }
  207.  
  208.             var result:Result = Text.fillEventResult(EventType.MORALE_THEFT);
  209.             var percentStolen:Number = Utils.getRandomNumber(0.10, 0.25);
  210.             var numFoodStolen:int = Context.fort.numFood * percentStolen;
  211.             numFoodStolen = Utils.minMax(numFoodStolen, 2, 100);
  212.             result.addFood( -1 * numFoodStolen);
  213.             return result;
  214.         }
  215.  
  216.         /**
  217.          *
  218.             Someone wants to kill themselves, what do you do?
  219.             talk them out of it (requires level 8 leader, lose the depressed trait)
  220.             offer them time off (they go on a recovery mission, lose the depressed trait)
  221.             do nothing (they gain the depressed trait & may kill themselves/leave/repeat later)
  222.          */
  223.         public static function depression():Result
  224.         {
  225.             var colin:Colin = ColinManager.pickUnhappyColin();
  226.             if (colin == null) {
  227.                 return null;
  228.             }
  229.  
  230.             // talk
  231.             var option1:Function = function(result:Result):Result {
  232.                 Text.fillEventResult(1, result);
  233.                 result.mentionedColin = colin;
  234.                 result.addHappinessColin(20, "happy_depressionTalk");
  235.                 return result;
  236.             }
  237.             if (!ColinManager.fortHasSkillLevel(Colin.SKILL_LEADERSHIP, 7)) {
  238.                 option1 = Result.OPTION_DISABLED;
  239.             }
  240.  
  241.             // time off
  242.             var option2:Function = function(result:Result):Result {
  243.                 Text.fillEventResult(2, result);
  244.                 result.mentionedColin = colin;
  245.                 result.injureMentionedColin(false, true);
  246.                 // 20 happiness now, more for every day of the vacation
  247.                 result.addHappinessColin(20, "happy_depressionTimeOff");
  248.                 return result;
  249.             }
  250.  
  251.             // leave him alone
  252.             var option3:Function = function(result:Result):Result {
  253.                 Text.fillEventResult(3, result);
  254.                 result.mentionedColin = colin;
  255.                 result.addHappinessColin(-10, "happy_depressionAlone");
  256.                 return result;
  257.             }
  258.  
  259.             var result:Result = Text.fillEventResult(EventType.MORALE_DEPRESSION,
  260.                 null, [option1, option2, option3]);
  261.             result.mentionedColin = colin;
  262.             return result;
  263.         }
  264.  
  265.         /**
  266.          * Someone wants to join another faction, do you let them?
  267.          *
  268.          * yes (+ faction like)
  269.          * talk them out of it (+ happiness)
  270.          * bribe them to stay (double rations, + happiness)
  271.          *
  272.          */
  273.         public static function wantsToLeave():Result
  274.         {
  275.             var colin:Colin = ColinManager.pickUnhappyColin();
  276.             if (colin == null) {
  277.                 return null;
  278.             }
  279.  
  280.             var faction:Faction = Utils.pickRandom(Context.city.factions);
  281.             if (faction == null) {
  282.                 return Result.RESULT_DISABLE;
  283.             }
  284.  
  285.             var option1:Function = function(result:Result):Result {
  286.                 Text.fillEventResult(1, result);
  287.                 result.mentionedColin = colin;
  288.                 result.faction = faction;
  289.                 result.addHappinessColin(20, "happy_leaveTalk");
  290.                 return result;
  291.             }
  292.             if (!ColinManager.fortHasSkillLevel(Colin.SKILL_LEADERSHIP, 7)) {
  293.                 option1 = Result.OPTION_HIDDEN;
  294.             }
  295.             var option2:Function = function(result:Result):Result {
  296.                 Text.fillEventResult(2, result);
  297.                 result.mentionedColin = colin;
  298.                 result.faction = faction;
  299.                 result.addHappinessColin(20, "happy_leaveRations");
  300.                 colin.addPerk(PerkType.DOUBLE_RATIONS);
  301.                 return result;
  302.             }
  303.             var option3:Function = function(result:Result):Result {
  304.                 Text.fillEventResult(3, result);
  305.                 result.mentionedColin = colin;
  306.                 result.faction = faction;
  307.                 result.killMentionedColin("death_wantsToLeave", false,
  308.                     false, false, false, faction.type.factionName);
  309.                 faction.addRespect(5, result);
  310.                 return result;
  311.             }
  312.  
  313.             var result:Result = Text.fillEventResult(EventType.MORALE_WANTS_TO_LEAVE,
  314.                 null, [option1, option2, option3]);
  315.             result.mentionedColin = colin;
  316.             result.faction = faction;
  317.             return result;
  318.         }
  319.  
  320.         /**
  321.          * Bob's having some kind of breakdown.
  322.             He's waving a gun and threatening to open the gates beside the McNoodles.
  323.             The zed on the other side are all riled up, maybe two dozen of them ready to pile
  324.             through the instant he raises that latch. What do you do?
  325.                 talk him down
  326.                     if you have a level 8 leader you succeed
  327.                     if not it triggers a zombie attack
  328.                 shoot him before he opens the latch
  329.                 convince him to leave the rest of the fort out of this
  330.                     he shoots himself
  331.          */
  332.         public static function gateBreakdown():Result
  333.         {
  334.             var colin:Colin = ColinManager.pickUnhappyColin();
  335.             if (colin == null) {
  336.                 return null;
  337.             }
  338.  
  339.             var toSquare:Square = FortUtils.getLeastDefenseSquare();
  340.             if (toSquare == null) {
  341.                 return null;
  342.             }
  343.  
  344.             var option1:Function = function(result:Result):Result {
  345.                 Text.fillEventResult(1, result);
  346.                 result.addHappinessColin(20, "happy_breakdownTalk");
  347.                 return result;
  348.             }
  349.             if (!ColinManager.fortHasSkillLevel(Colin.SKILL_LEADERSHIP, 7)) {
  350.                 option1 = Result.OPTION_HIDDEN;
  351.             }
  352.             var option2:Function = function(result:Result):Result {
  353.                 Text.fillEventResult(2, result);
  354.                 result.killMentionedColin("death_breakdownShot");
  355.                 return result;
  356.             }
  357.             var option3:Function = function(result:Result):Result {
  358.                 // bad defense leads to death and gate opening
  359.                 if (!Utils.getRandChance(Context.fort.fortDefense, 100)) {
  360.                     Text.fillEventResult("gateBreakdown_outcome3Gates", result);
  361.                     result.killMentionedColin("death_breakdownGates");
  362.                     FortUtils.loseSquare(toSquare, result);
  363.                 // better defense leads to suicide
  364.                 } else {
  365.                     Text.fillEventResult("gateBreakdown_outcome3Suicide", result);
  366.                     result.square = toSquare;
  367.                     result.mentionedColin = colin;
  368.                     result.killMentionedColin("death_breakdownSuicide");
  369.                 }
  370.                 return result;
  371.             }
  372.  
  373.             var result:Result = Text.fillEventResult(EventType.MORALE_GATE_BREAKDOWN,
  374.                 null, [option1, option2, option3]);
  375.             result.square = toSquare;
  376.             result.mentionedColin = colin;
  377.             return result;
  378.         }
  379.  
  380.         /**
  381.          * Someone gets angry about not having a city hall yet.
  382.          */
  383.         public static function needCityhall():Result
  384.         {
  385.             // must be ready to build a city hall for the last week but not have one yet
  386.             if (FortSquaresManager.fortSquaresOfType(SquareType.cityHall).length > 0) {
  387.                 return null;
  388.             }
  389.             if (!EventsBase.minDaysSinceEvent(EventType.WIN_CAN_BUILD_CITYHALL, 7, true)) {
  390.                 return null;
  391.             }
  392.  
  393.             var colin:Colin = ColinManager.pickUnhappyColin();
  394.             if (colin == null) {
  395.                 return null;
  396.             }
  397.  
  398.             var result:Result = Text.fillEventResult(EventType.MORALE_NEED_CITYHALL);
  399.             result.mentionedColin = colin;
  400.             result.addHappinessColin(-20, "happy_needCityHall");
  401.             return result;
  402.         }
  403.  
  404.         /**
  405.          * Divide the totalAmount of happiness among random living colins in full chunks of amountPerColin.
  406.          * If there is a remainder, it will randomly given or not a percentage of the time.
  407.          */
  408.         private static function divvyHappiness(totalAmount:Number, amountPerColin:Number,
  409.             reasonTextId:String, doubleColins:Vector.<Colin> = null, noneColins:Vector.<Colin> = null):void
  410.         {
  411.             //lets keep this positive for now
  412.             if ( amountPerColin < 0 ) {
  413.                 amountPerColin *= -1;
  414.             }
  415.  
  416.             // for pretty sake set amountPerColin to multiples of 5 with a minimum of 5
  417.             amountPerColin = Utils.minMax(5 * Math.round(amountPerColin / 5), 5);
  418.  
  419.             // 1.5 colins will become 1 half the time and 2 half the time
  420.             var numColins:int = Utils.randomRound(Math.abs(totalAmount) / amountPerColin);
  421.             numColins = Utils.minMax(numColins, 0, ColinManager.numLivingColins);
  422.             if (numColins == 0) {
  423.                 return;
  424.             }
  425.  
  426.             //now lets set amountPerColin to have the right sign
  427.             if ( totalAmount < 0 ) {
  428.                 amountPerColin *= -1;
  429.             }
  430.  
  431.             Utils.randomizeVector(ColinManager.livingColins);
  432.             for (var i:int = 0; i < numColins; i++) {
  433.                 var colin:Colin = ColinManager.livingColins[i];
  434.                 if (noneColins != null) {
  435.                     if (Utils.vectorContains(noneColins, colin)) {
  436.                         continue;
  437.                     }
  438.                 }
  439.                 if (doubleColins != null) {
  440.                     if (Utils.vectorContains(doubleColins, colin)) {
  441.                         // no result since this is during daily happiness
  442.                         colin.addHappinessNoResult(amountPerColin * 2, reasonTextId, true);
  443.                         continue;
  444.                     }
  445.                 }
  446.                 // no result since this is during daily happiness
  447.                 colin.addHappinessNoResult(amountPerColin, reasonTextId, true);
  448.             }
  449.         }
  450.  
  451.         /**
  452.          * Called every day, rain or shine. Increases or decreases happiness based on policies etc.
  453.          * http://my.hrw.com/math06_07/nsmedia/tools/Graph_Calculator/graphCalc.html
  454.          */
  455.         public static function dailyHappiness():void
  456.         {
  457.             var colin:Colin;
  458.             var i:int;
  459.             var possibleColins:Vector.<Colin>;
  460.             var numColins:int;
  461.             var originalHappiness:Number = Context.fort.happiness;
  462.  
  463.             // churches and bars
  464.  
  465.             // bars and churches give one guy 2% per day no matter how many people there are
  466.             // to balance overcrowding you need 1 bar for 10 guys but 100 bars for 100 guys
  467.             // so you need exponentially more over time to balance overcrowding
  468.             // with 10 colins, 1 bars give 1 guys 2% per day = (1 * 2) / (10 * 100) = fort av 0.2%
  469.             // with 20 colins, 4 bars give 4 guys 2% per day = (4 * 2) / (20 * 100) = fort av 0.4%
  470.             // with 50 colins, 25 bars give 25 guys 2% per day = (25 * 2) / (50 * 100) = fort av 1%
  471.             // with 100 colins, 100 bars give 100 guys 2% per day = (100 * 2) / (50 * 100) = fort av 2%
  472.             var pointsPerBuilding:Number = 2;
  473.             var numBars:int = FortSquaresManager.fortSquaresOfType(SquareType.bar).length;
  474.             var barPoints:Number = numBars * pointsPerBuilding;
  475.             if (ColinManager.hasMainLeaderPerk(PerkType.MAIN_STUDENT)) {
  476.                 barPoints *= 1.25;
  477.             }
  478.             var numChurches:int = FortSquaresManager.numChurches;
  479.             var churchPoints:Number = numChurches * pointsPerBuilding;
  480.  
  481.             // leading missions add extra points and are handled here, not in mission
  482.             var preachers:Vector.<Colin> = new Vector.<Colin>();
  483.             var bartenders:Vector.<Colin> = new Vector.<Colin>();
  484.             for each (var mission:Mission in Context.fort.missions) {
  485.                 var leadMission:MissionPostLead = mission as MissionPostLead;
  486.                 if (leadMission == null || !leadMission.started || leadMission.finished) {
  487.                     continue;
  488.                 }
  489.                 if (leadMission.square.type == SquareType.bar) {
  490.                     barPoints += leadMission.happinessMultiplier * pointsPerBuilding;
  491.                     bartenders = Utils.unionVectors(bartenders, leadMission.colins);
  492.                 } else if (leadMission.square.type == SquareType.church) {
  493.                     churchPoints += leadMission.happinessMultiplier * pointsPerBuilding;
  494.                     preachers = Utils.unionVectors(preachers, leadMission.colins);
  495.                 } else {
  496.                     Utils.logError("Unexpected square for lead mission, ", mission.square);
  497.                 }
  498.             }
  499.             var preacher:Colin = Utils.pickRandom(preachers);
  500.             var bartender:Colin = Utils.pickRandom(bartenders);
  501.  
  502.             if (PolicyOption.CHURCHVBAR_BAR.chosen) {
  503.                 barPoints *= 2;
  504.                 churchPoints /= 2;
  505.             } else if (PolicyOption.CHURCHVBAR_CHURCH.chosen) {
  506.                 barPoints /= 2;
  507.                 churchPoints *= 2;
  508.             }
  509.             if (PolicyOption.PRIORITY_RELIGION.chosen) {
  510.                 churchPoints *= 2;
  511.             }
  512.  
  513.             var skepticColins:Vector.<Colin> = ColinManager.colinsWithPerk(PerkType.SKEPTIC);
  514.             var devoutColins:Vector.<Colin> = ColinManager.colinsWithPerk(PerkType.DEVOUT);
  515.  
  516.             // if there's a bartender divvy points in chunks of +15 and mention bartender instead of usual +10
  517.             var barReasonId:String = (bartender != null) ? "happy_bartender" : "happy_bar";
  518.             var barDivvyAmount:int = (bartender != null) ? 15 : 10;
  519.             divvyHappiness(barPoints, barDivvyAmount, barReasonId, skepticColins, devoutColins);
  520.            
  521.             var churchReasonId:String = (preacher != null) ? "happy_preacher" : "happy_church";
  522.             var churchDivvyAmount:int = (preacher != null) ? 15 : 10;
  523.             divvyHappiness(churchPoints, churchDivvyAmount, churchReasonId, devoutColins, skepticColins);
  524.            
  525.             // up to 10% of living colins may comment on stuff every day
  526.             numColins = Utils.randomRound(0.10 * ColinManager.livingColins.length);
  527.  
  528.             // lategame upset affects 10% of colins
  529.  
  530.             // based on the size of the fort so that getting by with fewer people is a legit strategy
  531.             // http://my.hrw.com/math06_07/nsmedia/tools/Graph_Calculator/graphCalc.html
  532.             // with 10 colins,  0.5% happy lost,    1 colin loses 5 happiness per day
  533.             // with 15 colins,  0.75% happy lost,   1.5 colins lose 7.5 happiness per day
  534.             // with 20 colins,  1% fort happy lost, 2 colins lose 10 happiness per day
  535.             // with 50 colins,  2% fort happy lost, 5 colins lose 20 happiness per day
  536.             // with 100 colins, 3% fort happy lost, 10 colins lose 30 happiness per day
  537.             if (numColins > 0 && (DayManager.isLategame || ColinManager.numLivingColins >= 10)) {
  538.                
  539.                 // can lose devout if there are no churches, with a minus to happiness
  540.                 if (numChurches == 0) {
  541.                     if (Utils.getRandChance(1, 30)) {
  542.                         var randomDevout:Colin = ColinManager.colinWithPerk(PerkType.DEVOUT);
  543.                         if ( randomDevout != null && !randomDevout.hasPerk(PerkType.MAIN_PRIEST)) {
  544.                             randomDevout.removePerk(PerkType.DEVOUT);
  545.                             randomDevout.addHappinessNoResult( -40, "happy_noChurch", true);
  546.                         }
  547.                     } else if (Utils.getRandChance(1, 30)) {
  548.                         var randomCultist:Colin = ColinManager.colinWithPerk(PerkType.CULTIST);
  549.                         if ( randomCultist != null ) {
  550.                             randomCultist.removePerk(PerkType.CULTIST);
  551.                             randomCultist.addHappinessNoResult( -40, "happy_noChurch", true);
  552.                         }
  553.                     }
  554.                 }
  555.                
  556.                 // x ^ (0.5) * 0.4 * 10 - 8
  557.                 // colinsSlice should be 10 but randomRound might have made it more or less
  558.                 var colinsSlice:Number = (ColinManager.livingColins.length / numColins);
  559.                 var upsetPer:Number = Math.pow(ColinManager.numLivingColins, 0.5) * 0.4 * colinsSlice - 8;
  560.                
  561.                 // later halve it and divvy it among 2x as many people
  562.                 if (upsetPer >= 10) {
  563.                     var numColinsLategameUpset:int = numColins * 2;
  564.                     upsetPer = Utils.minMax(Utils.randomRound(upsetPer / 2), 1);
  565.                 }
  566.                 // for pretty sake set upsetPer to multiples of 5 with a minimum of 5
  567.                 upsetPer = Utils.minMax(5 * Math.round(upsetPer / 5), 5);
  568.  
  569.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  570.                 for (i = 0; i < numColinsLategameUpset; i++) {
  571.                     colin = possibleColins.pop();
  572.                     if (colin == null) {
  573.                         break;
  574.                     }
  575.  
  576.                     // for flavor and info, complain about various things
  577.                     // all of these generic complaints start with a * because we collapse them together
  578.                     // when we show them to the user and then parse the star off the front.
  579.                     var lategameReasons:Array = [];
  580.                     lategameReasons.push("happy_lategameRandom");
  581.                     if (FortSquaresManager.numSquareChunks > 10) {
  582.                         lategameReasons.push("happy_lategameBigFort");
  583.                     }
  584.                     if ( FortSquaresManager.numChurches < ColinManager.livingColins.length/10 && colin.hasPerk(PerkType.DEVOUT) ) {
  585.                         lategameReasons.push("happy_lategameChurches");
  586.                     }
  587.                     if ( FortSquaresManager.numBars < ColinManager.livingColins.length/10 && !colin.hasPerk(PerkType.DEVOUT) ) {
  588.                         lategameReasons.push("happy_lategameBars");
  589.                     }
  590.                     if ((ColinManager.colinSlotsAvail / FortSquaresManager.numHouses) < 0.10) {
  591.                         lategameReasons.push("happy_lategameHouses");
  592.                     }
  593.                     if (Context.fort.goats.length == 0) {
  594.                         lategameReasons.push("happy_lategameGoats");
  595.                     }
  596.                     if (!colin.hasPerk(PerkType.EQUIPMENT_RECREATION) && !colin.hasPerk(PerkType.MUSICIAN)
  597.                         && !colin.hasPerk(PerkType.EASYGOING)) {
  598.                         lategameReasons.push("happy_lategameRecreation");
  599.                     }
  600.                     if (!colin.hasPerk(PerkType.EQUIPMENT_PET) && !colin.hasPerk(PerkType.EQUIPMENT_GOAT)
  601.                         && RelationshipManager.getFriends(colin).length == 0) {
  602.                         lategameReasons.push("happy_lategamePet");
  603.                     }
  604.                     if (!FortSquaresManager.hasWorkingPowerPlant && !FortSquaresManager.hasWorkingWaterPlant) {
  605.                         lategameReasons.push("happy_lategameAmmenities");
  606.                     }
  607.                    
  608.                     // not grouped with the others (no *) so we'll see this separately, and it's more likely
  609.                     if (colin.mission.danger > 10) {
  610.                         lategameReasons.push("happy_lategameDanger");
  611.                         lategameReasons.push("happy_lategameDanger");
  612.                         lategameReasons.push("happy_lategameDanger");
  613.                     }
  614.                     var lategameReasonId:String = Utils.pickRandom(lategameReasons);
  615.  
  616.                     colin.addHappinessNoResult(-1 * upsetPer, lategameReasonId, true);
  617.                 }
  618.             }
  619.  
  620.             // policies
  621.  
  622.             // food policy makes people happy or sad
  623.             if (PolicyOption.RATIONS_HALF.chosen || PolicyOption.RATIONS_DOUBLE.chosen) {
  624.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  625.                 for (i = 0; i < numColins; i++) {
  626.                     colin = possibleColins.pop();
  627.                     if (colin == null) {
  628.                         break;
  629.                     }
  630.                     if (PolicyOption.RATIONS_HALF.chosen) {
  631.                         colin.addHappinessNoResult(-5, "happy_rationsReduced", true);
  632.                     } else if (PolicyOption.RATIONS_DOUBLE.chosen) {
  633.                         colin.addHappinessNoResult(5, "happy_rationsIncreased", true);
  634.                     }
  635.                 }
  636.             }
  637.  
  638.             // non-soldiers are unhappy about forced guard duty
  639.             if (PolicyOption.GUARD_MANDATORY.chosen) {
  640.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  641.                 for (i = 0; i < numColins; i++) {
  642.                     colin = possibleColins.pop();
  643.                     if (colin == null) {
  644.                         break;
  645.                     }
  646.                     if (colin.getFullSkillLevel(Colin.SKILL_DEFENSE) < 1) {
  647.                         colin.addHappinessNoResult(-10, "happy_mandatoryGuard", true);
  648.                     }
  649.                 }
  650.             }
  651.  
  652.             // devout men and women soldiers have opinions on women staying home or learning to shoot
  653.             if (PolicyOption.WOMEN_STAYHOME.chosen || PolicyOption.WOMEN_EVEN.chosen) {
  654.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  655.                 for (i = 0; i < numColins; i++) {
  656.                     colin = possibleColins.pop();
  657.                     if (colin == null) {
  658.                         break;
  659.                     }
  660.  
  661.                     // devout men want women to stay home
  662.                     if (colin.hasPerk(PerkType.DEVOUT) && colin.isMale) {
  663.                         if (PolicyOption.WOMEN_STAYHOME.chosen) {
  664.                             colin.addHappinessNoResult(10, "happy_womenHomeHappy", true);
  665.                         } else {
  666.                             colin.addHappinessNoResult(-10, "happy_womenAwaySad", true);
  667.                         }
  668.  
  669.                     // devout women non-soldiers hate guns
  670.                     } else if (colin.hasPerk(PerkType.DEVOUT) && !colin.isMale && colin.currentSkill != Colin.SKILL_DEFENSE) {
  671.                         if (PolicyOption.WOMEN_STAYHOME.chosen) {
  672.                             colin.addHappinessNoResult(10, "happy_womenHomeHappyFemale", true);
  673.                         } else {
  674.                             colin.addHappinessNoResult(-20, "happy_womenAwaySadFemale", true);
  675.                         }
  676.  
  677.                     // non-devout women are gain / lose skill
  678.                     } else if (!colin.hasPerk(PerkType.DEVOUT) && !colin.isMale) {
  679.                         if (PolicyOption.WOMEN_STAYHOME.chosen) {
  680.                             colin.adjustSkill(Colin.SKILL_DEFENSE, -5);
  681.                             colin.addHappinessNoResult(-10, "happy_womenHomeSadFemale", false);
  682.                         } else {
  683.                             colin.adjustSkill(Colin.SKILL_DEFENSE, 3);
  684.                             colin.addHappinessNoResult(10, "happy_womenAwayHappyFemale", false);
  685.                         }
  686.                     }
  687.                 }
  688.             }
  689.  
  690.             // devout like drug ban but addicts don't
  691.             if (PolicyOption.DRUGS_BAN.chosen) {
  692.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  693.                 for (i = 0; i < numColins; i++) {
  694.                     colin = possibleColins.pop();
  695.                     if (colin == null) {
  696.                         break;
  697.                     }
  698.                     if (colin.hasPerk(PerkType.ADDICT)) {
  699.                         // once a week on average addicts will lose their addiction
  700.                         if (Utils.getRandChance(1, 7 * numColins)) {
  701.                             colin.removePerk(PerkType.ADDICT);
  702.                             colin.addHappinessNoResult( 10, "happy_addictCured", true);
  703.                         // the rest of the time they're just unhappy
  704.                         } else {
  705.                             colin.addHappinessNoResult( -10, "happy_addictBan", true);
  706.                         }
  707.                     } else if (colin.hasPerk(PerkType.DEVOUT)) {
  708.                         colin.addHappinessNoResult(10, "happy_addictDevout", true);
  709.                     }
  710.                 }
  711.             }
  712.  
  713.             // banning church of chosen ones upsets those guys
  714.             if (PolicyOption.CHOSEN_BAN_YES.chosen) {
  715.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  716.                 for (i = 0; i < numColins; i++) {
  717.                     colin = possibleColins.pop();
  718.                     if (colin == null) {
  719.                         break;
  720.                     }
  721.  
  722.                     if (colin.hasPerk(PerkType.CULTIST)) {
  723.                         if (Utils.getRandChance(1, 10)) {
  724.                             colin.removePerk(PerkType.CULTIST);
  725.                             colin.addHappinessNoResult(-40, "happy_chosenBannedQuit", true);
  726.                         } else {
  727.                             colin.addHappinessNoResult(-10, "happy_chosenBanned", true);
  728.                         }
  729.                     }
  730.                 }
  731.             }
  732.  
  733.             // whoever gets the best stuff is happy
  734.             if (PolicyOption.WEALTH_SKILLED.chosen || PolicyOption.WEALTH_HARDWORK.chosen || PolicyOption.WEALTH_SOLDIERS.chosen) {
  735.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  736.                 //have to be two skill points better than the average, or level 10
  737.                 var averageSkillLevel:Number = ColinManager.getAverageSkillLevel();
  738.                 var wealthyLevel:int = Utils.minMax(averageSkillLevel + 2, 0, 10);
  739.                 for (i = 0; i < numColins; i++) {
  740.                     colin = possibleColins.pop();
  741.                     if (colin == null) {
  742.                         break;
  743.                     }
  744.                     // inequality is good times for very skilled survivors, less for the unskilled
  745.                     if (PolicyOption.WEALTH_SKILLED.chosen) {
  746.                         if (colin.currentLevel >= wealthyLevel) {
  747.                             colin.addHappinessNoResult(10, "happy_wealthSkilled", true);
  748.                         } else {
  749.                             colin.addHappinessNoResult( -5, "happy_wealthSkilledNo", true);
  750.                         }
  751.                     // hard work is rewarded... anyone on non-post missions is rewarded but nobody's unhappy
  752.                     } else if (PolicyOption.WEALTH_HARDWORK.chosen) {
  753.                         if (!(colin.mission is MissionPost)) {
  754.                             colin.addHappinessNoResult(5, "happy_wealthWork", true);
  755.                         }
  756.                     } else if (PolicyOption.WEALTH_SOLDIERS.chosen) {
  757.                         if (colin.currentSkill == Colin.SKILL_DEFENSE) {
  758.                             colin.addHappinessNoResult(10, "happy_wealthSoldiers", true);
  759.                         } else {
  760.                             colin.addHappinessNoResult( -5, "happy_wealthSoldiersNo", true);
  761.                         }
  762.                     }
  763.                 }
  764.             }
  765.  
  766.             // more vs less taxes and public property
  767.             if (PolicyOption.PROPERTY_PUBLIC.chosen || PolicyOption.PROPERTY_PRIVATE.chosen) {
  768.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  769.                 for (i = 0; i < numColins; i++) {
  770.                     colin = possibleColins.pop();
  771.                     if (colin == null) {
  772.                         break;
  773.                     }
  774.                     // all property is public property
  775.                     if (PolicyOption.PROPERTY_PUBLIC.chosen) {
  776.                         colin.addHappinessNoResult( -5, "happy_propertyPublic", true);
  777.                     // all property is private property, no "taxes"
  778.                     } else if (PolicyOption.PROPERTY_PRIVATE.chosen) {
  779.                         colin.addHappinessNoResult(5, "happy_propertyPublicNo", true);
  780.                     }
  781.                 }
  782.             }
  783.  
  784.             // electricity uses fuel but gains happiness, so long as we have fuel
  785.             if ((PolicyOption.POWER_SOMETIMES.chosen || PolicyOption.POWER_ALWAYS.chosen)
  786.                 && FortSquaresManager.hasWorkingPowerPlant) {
  787.                 var currentFuel:Number = Context.fort.getNumResource(ResourceType.FUEL);
  788.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  789.                 for (i = 0; i < numColins; i++) {
  790.                     colin = possibleColins.pop();
  791.                     if (colin == null) {
  792.                         break;
  793.                     }
  794.                    
  795.                     // being out of fuel makes people sad
  796.                     if (currentFuel < 0.5) {
  797.                         colin.addHappinessNoResult(-1, "happy_powerFuel", true);
  798.                     // run power in the morning and evening
  799.                     } else if (PolicyOption.POWER_SOMETIMES.chosen) {
  800.                         colin.addHappinessNoResult(3, "happy_powerSometimes", true);
  801.                     // run it all the time
  802.                     } else if (PolicyOption.POWER_ALWAYS.chosen) {
  803.                         colin.addHappinessNoResult(6, "happy_powerAlways", true);
  804.                     }
  805.                 }
  806.                
  807.                 // lose 1-2 fuel per week
  808.                 if (PolicyOption.POWER_SOMETIMES.chosen) {
  809.                     Context.fort.setNumResource(ResourceType.FUEL, currentFuel - (1 / 7));
  810.                 } else if (PolicyOption.POWER_ALWAYS.chosen) {
  811.                     Context.fort.setNumResource(ResourceType.FUEL, currentFuel - (2 / 7));
  812.                 }
  813.             }
  814.  
  815.             // showers make people happy but might cause injury due to thirst in a random event
  816.             if ((PolicyOption.SHOWER_SOMETIMES.chosen || PolicyOption.SHOWER_ALWAYS.chosen)
  817.                 && FortSquaresManager.hasWorkingWaterPlant) {
  818.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  819.                 for (i = 0; i < numColins; i++) {
  820.                     colin = possibleColins.pop();
  821.                     if (colin == null) {
  822.                         break;
  823.                     }
  824.                    
  825.                     // shower once a week
  826.                     if (PolicyOption.SHOWER_SOMETIMES.chosen) {
  827.                         colin.addHappinessNoResult(2, "happy_waterSometimes", true);
  828.                     // shower all the time
  829.                     } else if (PolicyOption.SHOWER_ALWAYS.chosen) {
  830.                         colin.addHappinessNoResult(4, "happy_waterAlways", true);
  831.                     }
  832.                 }
  833.             }
  834.  
  835.             // banshee keeps people awake at night
  836.             if (Context.city.hasEffect(City.EFFECT_BANSHEE)) {
  837.                 possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  838.                 for (i = 0; i < numColins; i++) {
  839.                     colin = possibleColins.pop();
  840.                     if (colin == null) {
  841.                         break;
  842.                     }
  843.  
  844.                     colin.addHappinessNoResult(-10, "happy_banshee", true);
  845.                 }
  846.             }
  847.  
  848.             // check 10% of people for cats etc
  849.             possibleColins = Utils.cloneVector(ColinManager.livingColins, true);
  850.             for (i = 0; i < numColins; i++) {
  851.                 colin = possibleColins.pop();
  852.                 if (colin == null) {
  853.                     break;
  854.                 }
  855.                 if (colin.hasPerk(PerkType.EQUIPMENT_PET) && colin.nonweapon != null && colin.nonweapon.type.isPet) {
  856.                     if (colin.hasPerk(PerkType.ANIMAL_LOVER)) {
  857.                         colin.addHappinessNoResult(10, "happy_petLove", true,
  858.                             colin.nonweapon.type.typeName, colin.nonweapon.properName);
  859.                     } else {
  860.                         colin.addHappinessNoResult(5, "happy_pet", true,
  861.                             colin.nonweapon.type.typeName, colin.nonweapon.properName);
  862.                     }
  863.                 }
  864.                 if (colin.hasPerk(PerkType.EQUIPMENT_GOAT) && colin.nonweapon != null && colin.nonweapon.type.isGoat) {
  865.                     colin.addHappinessNoResult(10, "happy_goat", true, colin.nonweapon.properName);
  866.                 }
  867.             }
  868.  
  869.             // change colin stats based on their new happiness
  870.             Context.fort.calculateHappiness();
  871.            
  872.             // record whether happiness increased or decreased today for the hud
  873.             // it involves randomness so this is only an estimate
  874.             // average with 2x yesterday's so it doesn't change too quickly
  875.             var happinessChange:Number = Context.fort.happiness - originalHappiness;
  876.             var averageChange:Number = happinessChange * 1/3 + Context.fort.lastDailyHappinessChange * 2/3;
  877.             Context.fort.lastDailyHappinessChange = averageChange;
  878.         }
  879.     }
  880. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement