# HG changeset patch # User Alys Brooks # Date 2021-09-28 09:06:52 # Node ID ad760cacfa0287347946a58fe8d3b5a58bb3c204 # Parent bef4b64bb99da35e2fe286e71049f0cced76248f Add Mass Vandalism event. diff --git a/TODO.taskpaper b/TODO.taskpaper --- a/TODO.taskpaper +++ b/TODO.taskpaper @@ -8,10 +8,10 @@ - Movement @done(2021-01-27) - Close button @done(2021-01-28) - Better appearance - - Money graph @maybe + - Money graph @maybe Procgen: short phase, maybe? - - Add some procedurally generated dialog @maybe @milestone(2: Procgen) + - Add some procedurally generated dialog @maybe @milestone(2: Procgen) - Add some procedurally generated newspaper @maybe @milestone(2: Procgen) @done(2021-03-15) - Basic NEWS tab @milestone(2: Procgen) - Different tabs for different sources @done(2021-02-21) @@ -33,7 +33,6 @@ - Add company images @milestone(3: Contracts) @maybe @done(2021-05-21) - Contracts should end Trees: - - Add basic maintenance cost @milestone(1: Basic Money) @done(2021-01-27) - Add basic age simulation - Add water @milestone(6: Trees and Tiles) @@ -46,7 +45,7 @@ Reduces cost of vandalism repair? - Sell Firewood? Staff: - - Ranger staffing? @maybe @milestone(1: Basic Money) + - Ranger staffing? @maybe @milestone(1: Basic Money) - Staffing window - Ranger allocation - Set employee salaries, leave, etc. @maybe @@ -56,7 +55,7 @@ Leisure: - Add way to mark off area for leisure @milestone(7: Leisure) - Basic satisfaction @milestone(7: Leisure) - - Set + - Set End games/outcomes: - Financial mismanagement @milestone(5: Events) - Figure out threshold @@ -76,12 +75,11 @@ - Land repatriation to indigenous @maybe Like the acknowledgement, don't want it to be too white savior-y (although obv. player isn't necessarily white) - Research center @maybe - - Community: Differing reputation with different groups. Could mix more and less political. Don't want to go too Democracy 3/4: being able to affect the group size via policy is probably out. (Groups being intersectional might work, but is kind of tricky.) - Maybe a procedurally generated set of groups with some hard-coded elements? E.g., - + Maybe a procedurally generated set of groups with some hard-coded elements? E.g + Misc: - Assistant commentary @milestone(5: Events) Need to ensure it's not annoying @@ -91,13 +89,13 @@ - Federal grant - Celebrity visit - Disasters @maybe - - Fire + - Fire would probably have to animate - Disease - Photos for dialog? - Graphs window Could use ImPlot for this - + Structure: - Add modes @milestone(5: Events) - Refactor stuff out of FNAGame @@ -154,11 +152,11 @@ - Relocate fonts to central place @done(2021-06-26) - Remove fonts from DebugWindow? - Adjust window dimensions when font changes - - Option to Turn off bad outcomes or disasters @maybe + - Option to Turn off bad outcomes or disasters @maybe - Dyslexic-friendly font @maybe @done(2021-06-26) Cursory research indicates open sans-serif fonts are best, although fonts only help so much. (Monospaced fonts are also cited as good options so Iosevka might already be good enough. Still, I added Roboto.) - + - Screen reader support @maybe Would probably be a big undertaking (sort of opposite to the web, where things tend to be accessible unless you start reimplenting things or going more advanced) - Investigate .NET support for screen readers @@ -172,7 +170,6 @@ - Linux - Look for prior art - Add a "describe" button/key that speaks the current scene @maybe - - - No fees when contracts break - Contracts go dormant instead of ending. Other QoL things: diff --git a/isometric-park-fna/Components/EventComponent.cs b/isometric-park-fna/Components/EventComponent.cs new file mode 100644 --- /dev/null +++ b/isometric-park-fna/Components/EventComponent.cs @@ -0,0 +1,8 @@ + + +using Encompass; + +namespace isometricparkfna.Components +{ + public struct EventComponent : IComponent { } +} diff --git a/isometric-park-fna/Content/dialog.ink b/isometric-park-fna/Content/dialog.ink --- a/isometric-park-fna/Content/dialog.ink +++ b/isometric-park-fna/Content/dialog.ink @@ -1,17 +1,32 @@ + +VAR playerSwears = 0 +VAR playerRude = 0 VAR GovernorOpinion = 0 + //This is needed to make both including and for jumpting to dialog sections work: === placeholder === -> END + +=== function alter(ref x, k) === + ~ x = x + k + + +=== function inc(ref x) === + ~ x = x + 1 + +=== function dec(ref x) === + ~ x = x - 1 + === Once === Once upon a time... - * There were two choices. - * There were four lines of content. + + There were two choices. + + There were four lines of content. - They lived happily ever after. -> END @@ -48,8 +63,6 @@ * [Nice to meet you.] You can use the mouse or arrow keys to move around, and the plus and minus keys to zoom in and out. B opens the budget and F lets you adjust Forest Policy. - -> BadNewsReact -> - * * [Got it, thanks.] \#assistantName\#: Bye @@ -61,9 +74,46 @@ === BadNewsReact === - * [Damn.] + + + + + [Damn.] {inc(playerSwears)} + ->-> + + [Fuck.] {inc(playerSwears)} + ->-> + + [Shoot.] {inc(playerSwears)} + ->-> + + [*Sigh.* Fine.] ->-> - * [Fuck.] + +=== AssistantAcknowlege === + + [Thanks.] + ->-> + + [Mmmm hmm.] + ->-> + + [Get to it.] {inc(playerRude)} + ->-> + + [I really appreciate it, \#assistantName\#] + -> Appreciate + + = Appreciate + \#assistantName\#: Oh, you're welcome. ->-> - * [Shoot.] - ->-> \ No newline at end of file + +=== MassVandalism === +\#assistantName\#: Bad news, director. + + [Oh?] + \#assistantName\#: A number of trees have been seriously damaged overnight. + + + [How bad are they?] + + \#assistantName\#: I'm no botanist, but they're not great. The gouges are pretty deep. + + -> BadNewsReact -> + + \#assistantName\#: Yeah, it's awful. + + I'll see who's around and get to cleaning. + + -> AssistantAcknowlege -> + + -> END \ No newline at end of file diff --git a/isometric-park-fna/Content/dialog.json b/isometric-park-fna/Content/dialog.json --- a/isometric-park-fna/Content/dialog.json +++ b/isometric-park-fna/Content/dialog.json @@ -1,1 +1,1 @@ -{"inkVersion":20,"root":[[["done",{"#f":5,"#n":"g-0"}],null],"done",{"placeholder":["end",{"#f":1}],"Once":[["^Once upon a time...","\n",["ev",{"^->":"Once.0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^There were two choices.",{"->":"$r","var":true},null]}],["ev",{"^->":"Once.0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^There were four lines of content.",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"Once.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"Once.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["^They lived happily ever after.","\n","end",{"#f":5}]}],{"#f":1}],"IntroGovernor":[["^Governor: Welcome to your new park, director!","\n","ev","str","^Okay","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["\n","^Governor: Make sure that you keep visitors happy and the budget in the black! You're currently getting an annual grant out of my budget—it'd sure be nice if you park were self-sufficient so we could drop that expense!","\n",["ev","str","^And I need to keep the forest healthy, too, right?","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Sounds good!","/str","/ev",{"*":".^.c-1","flg":20},{"c-0":["^ ","\n","ev",{"VAR?":"GovernorOpinion"},1,"-","/ev",{"VAR=":"GovernorOpinion","re":true},"^Governor: Ummm, yeah","\n",["ev","str","^...","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["\n","end",{"#f":5}]}],{"#f":5}],"c-1":["\n","ev",{"VAR?":"GovernorOpinion"},1,"+","/ev",{"VAR=":"GovernorOpinion","re":true},"^Governor: I'll check in soon.","\n","end",{"#f":5}]}],{"#f":5}]}],{"#f":1}],"IntroAssistant":[["^#assistantName#: Hello. I'm #assistantName#.","\n","ev","str","^Nice to meet you.","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["\n","^You can use the mouse or arrow keys to move around, and the plus and minus keys to zoom in and out. B opens the budget and F lets you adjust Forest Policy.","\n",{"->t->":"BadNewsReact"},["ev","str","^Got it, thanks.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^How are you?","/str","/ev",{"*":".^.c-1","flg":20},{"c-0":["\n","^#assistantName#: Bye","\n","end",{"#f":5}],"c-1":["\n","^#assistantName#: #howdoing#","\n","end",{"#f":5}]}],{"#f":5}]}],{"#f":1}],"BadNewsReact":[["ev","str","^Damn.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Fuck.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Shoot.","/str","/ev",{"*":".^.c-2","flg":20},{"c-0":["\n","ev","void","/ev","->->",{"#f":5}],"c-1":["\n","ev","void","/ev","->->",{"#f":5}],"c-2":["\n","ev","void","/ev","->->",{"#f":5}]}],{"#f":1}],"global decl":["ev",0,{"VAR=":"GovernorOpinion"},"/ev","end",null],"#f":1}],"listDefs":{}} \ No newline at end of file +{"inkVersion":20,"root":[[["done",{"#f":5,"#n":"g-0"}],null],"done",{"placeholder":["end",{"#f":1}],"Once":[["^Once upon a time...","\n",["ev",{"^->":"Once.0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":2},{"s":["^There were two choices.",{"->":"$r","var":true},null]}],["ev",{"^->":"Once.0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":2},{"s":["^There were four lines of content.",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"Once.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"Once.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["^They lived happily ever after.","\n","end",{"#f":5}]}],{"#f":1}],"IntroGovernor":[["^Governor: Welcome to your new park, director!","\n","ev","str","^Okay","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["\n","^Governor: Make sure that you keep visitors happy and the budget in the black! You're currently getting an annual grant out of my budget—it'd sure be nice if you park were self-sufficient so we could drop that expense!","\n",["ev","str","^And I need to keep the forest healthy, too, right?","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Sounds good!","/str","/ev",{"*":".^.c-1","flg":20},{"c-0":["^ ","\n","ev",{"VAR?":"GovernorOpinion"},1,"-","/ev",{"VAR=":"GovernorOpinion","re":true},"^Governor: Ummm, yeah","\n",["ev","str","^...","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["\n","end",{"#f":5}]}],{"#f":5}],"c-1":["\n","ev",{"VAR?":"GovernorOpinion"},1,"+","/ev",{"VAR=":"GovernorOpinion","re":true},"^Governor: I'll check in soon.","\n","end",{"#f":5}]}],{"#f":5}]}],{"#f":1}],"IntroAssistant":[["^#assistantName#: Hello. I'm #assistantName#.","\n","ev","str","^Nice to meet you.","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["\n","^You can use the mouse or arrow keys to move around, and the plus and minus keys to zoom in and out. B opens the budget and F lets you adjust Forest Policy.","\n",["ev","str","^Got it, thanks.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^How are you?","/str","/ev",{"*":".^.c-1","flg":20},{"c-0":["\n","^#assistantName#: Bye","\n","end",{"#f":5}],"c-1":["\n","^#assistantName#: #howdoing#","\n","end",{"#f":5}]}],{"#f":5}]}],{"#f":1}],"BadNewsReact":[["ev","str","^Damn.","/str","/ev",{"*":".^.c-0","flg":4},"ev","str","^Fuck.","/str","/ev",{"*":".^.c-1","flg":4},"ev","str","^Shoot.","/str","/ev",{"*":".^.c-2","flg":4},"ev","str","^*Sigh.* Fine.","/str","/ev",{"*":".^.c-3","flg":4},{"c-0":["\n","ev","void","/ev","->->",{"#f":5}],"c-1":["\n","ev","void","/ev","->->",{"#f":5}],"c-2":["\n","ev","void","/ev","->->",{"#f":5}],"c-3":["\n","ev","void","/ev","->->",{"#f":5}]}],{"#f":1}],"AssistantAcknowlege":[["ev","str","^Thanks.","/str","/ev",{"*":".^.c-0","flg":4},"ev","str","^Mmmm hmm.","/str","/ev",{"*":".^.c-1","flg":4},"ev","str","^Get to it.","/str","/ev",{"*":".^.c-2","flg":4},"ev","str","^I really appreciate it, #assistantName#","/str","/ev",{"*":".^.c-3","flg":4},{"c-0":["\n","ev","void","/ev","->->",{"#f":5}],"c-1":["\n","ev","void","/ev","->->",{"#f":5}],"c-2":["\n","ev","void","/ev","->->",{"#f":5}],"c-3":["\n","ev","void","/ev","->->",{"#f":5}]}],{"#f":1}],"MassVandalism":[["^#assistantName#: Bad news, director.","\n","ev","str","^Oh?","/str","/ev",{"*":".^.c-0","flg":4},{"c-0":["\n","^#assistantName#: A number of trees have been seriously damaged overnight.","\n",["ev","str","^How bad are they?","/str","/ev",{"*":".^.c-0","flg":4},{"c-0":["\n","^#assistantName#: I'm no botanist, but they're not great. The gouges are pretty deep.","\n",{"->t->":"BadNewsReact"},"^#assistantName#: Yeah, it's awful.","\n","^I'll see who's around and get to cleaning.","\n",{"->t->":"AssistantAcknowlege"},"end",{"#f":5}]}],{"#f":5}]}],{"#f":1}],"global decl":["ev",0,{"VAR=":"GovernorOpinion"},"/ev","end",null],"#f":1}],"listDefs":{}} \ No newline at end of file diff --git a/isometric-park-fna/Content/dialog_runner.ink b/isometric-park-fna/Content/dialog_runner.ink --- a/isometric-park-fna/Content/dialog_runner.ink +++ b/isometric-park-fna/Content/dialog_runner.ink @@ -4,6 +4,6 @@ INCLUDE dialog.ink --> IntroAssistant +-> MassVandalism -> END \ No newline at end of file diff --git a/isometric-park-fna/Engines/EventEngine.cs b/isometric-park-fna/Engines/EventEngine.cs --- a/isometric-park-fna/Engines/EventEngine.cs +++ b/isometric-park-fna/Engines/EventEngine.cs @@ -1,39 +1,75 @@ using System; +using Microsoft.Xna.Framework; + using Encompass; using isometricparkfna.Messages; +using isometricparkfna.Components; +using isometricparkfna.Utils; namespace isometricparkfna.Engines { [Receives(typeof(TickMessage))] [Sends(typeof(SpawnDialogMessage))] + [Reads(typeof(EventComponent), + typeof(TreeDeltaComponent))] + [Writes(typeof(TreeDeltaComponent))] class EventEngine : Engine { - Random Random; public EventEngine() { this.Random = new Random(); + } public override void Update(double dt) { + +#region random_events foreach (var tick in ReadMessages()) { - if (this.Random.Next(0, 10) == 1) + #region remove_events + foreach(var entity in ReadEntities()) + { + Logging.Debug("Destroying Event entity."); + Destroy(entity); + } + #endregion + if (this.Random.Next(0, 100) == 1) { Logging.Debug("Spawning Once dialog."); SendMessage(new SpawnDialogMessage { Path = "Once" }); } - } - } + if (this.Random.Next(0, 10) == 2) + { + Logging.Debug("Tree planting campaign!🎉"); + + var campaignEntity = CreateEntity(); + + AddComponent(campaignEntity, new TreeDeltaComponent{deltaTrees = new Fact(4)}); - + // AddComponent(campaignEntity, new AreaComponent{squares=final_squares}); + } + if (this.Random.Next(0, 10) == 3) + { + Logging.Debug("Mass vandalism 😿"); + + var campaignEntity = CreateEntity(); + AddComponent(campaignEntity, new TreeDeltaComponent{deltaTrees = new Fact(-100)}); + AddComponent(campaignEntity, new EventComponent{}); + + SendMessage(new SpawnDialogMessage { Path = "MassVandalism" }); + } + } +#endregion + + } } } diff --git a/isometric-park-fna/Engines/SimulationBridgeEngine.cs b/isometric-park-fna/Engines/SimulationBridgeEngine.cs --- a/isometric-park-fna/Engines/SimulationBridgeEngine.cs +++ b/isometric-park-fna/Engines/SimulationBridgeEngine.cs @@ -1,5 +1,8 @@ using System; using System.Linq; +using System.Collections.Generic; + +using Microsoft.Xna.Framework; using Encompass; @@ -23,10 +26,24 @@ private int ticksToSend; private Random random_generator; + Vector2[] all_squares; + public SimulationBridgeEngine(Simulation simulation) { this.simulation = simulation; this.random_generator = new Random(); + + List squares = new List(); + + for(int i = 0; i < simulation.map.MapWidth; i++) + { + for(int j = 0; j < simulation.map.MapHeight; j++) + { + squares.Add(new Vector2(i,j)); + } + } + this.all_squares = squares.ToArray(); + } public int addTick() @@ -106,44 +123,52 @@ foreach (ref readonly var entity in ReadEntities()) { - var status = GetComponent(entity).status; - var area = GetComponent(entity); - var delta = GetComponent(entity); + if ((HasComponent(entity) && GetComponent(entity).status == ContractStatus.Accepted) + || !(HasComponent(entity) )) + { + var delta = GetComponent(entity); - if (status == ContractStatus.Accepted) - { - var removed = 0; - var tree_squares = area.squares.Where((square) => simulation.map.cells[(int)square.X][(int)square.Y].hasTree); - var to_remove = -delta.deltaTrees.Value; + if (delta.deltaTrees.Value < 0) + { + var squares = HasComponent(entity) ? GetComponent(entity).squares : this.all_squares; + var removed = 0; + var tree_squares = squares.Where((square) => simulation.map.cells[(int)square.X][(int)square.Y].hasTree); + var to_remove = -delta.deltaTrees.Value; - //calculate the probability in order to get the expected number of removed trees - var expected = to_remove; - var trials = tree_squares.Count(); - double probability = ((double)expected / (double)trials) / 12; + //calculate the probability in order to get the expected number of removed trees + var expected = to_remove; + var trials = tree_squares.Count(); + double probability = ((double)expected / (double)trials) / 12; - foreach (var square in tree_squares) - { - var cell = simulation.map.cells[(int)square.X][(int)square.Y]; - if (cell.hasTree - && random_generator.NextDouble() < probability) - { - cell.removeTree(); - removed++; - } - if (removed >= to_remove) - { - // break; - } - } - } - } - } - this.ticksToSend = 0; + foreach (var square in tree_squares) + { + var cell = simulation.map.cells[(int)square.X][(int)square.Y]; + if (cell.hasTree + && random_generator.NextDouble() < probability) + { + cell.removeTree(); + removed++; + } + if (removed >= to_remove) + { + // break; + } + } + Logging.Info(String.Format("Destroyed {0} trees, expected {1}, P(destroy)= {2}", removed, (expected / 12), probability)); + } + else + { + } + } - simulation.contracts = new_contract_amount; - simulation.enforcement = new_enforcement_amount; + } + } + this.ticksToSend = 0; - } + simulation.contracts = new_contract_amount; + simulation.enforcement = new_enforcement_amount; + + } } }