Arcen Games

General Category => AI War II => Private Alpha Discussion => : BadgerBadger November 08, 2017, 10:46:55 AM

: Improving Wave Options
: BadgerBadger November 08, 2017, 10:46:55 AM
I want to make sure that AIW2 comes with enough per game customization to satisfy an AIWC player. I was casting around for another AI War project, and I have an idea.

The Wave generation code is now in External Code. I think it would be possible to add a few extra flags pretty easily as Conducts.
For Wave Target Warnings, the player will be able to potentially affect the wave behaviour by destroying the Warp Gate the AI intends to use. I think in this case the wave should not be spawned as planned. However, this means that the next wave will be twice as large (since there will be a lot more budget to spend), and an additional "You've made the AI mad" increase to the budget should be given. So you can put off the next wave, but there's a price to pay.

Does this sound like a desirable set of flags? Are there any cool behaviours that I'm missing?

One thing I am intrigued by is an additional Wave Composition option. Instead of either Homogenous (and chosen at random) or Schizophrenic (purely random ships), the AI analyzes your planet and figures out what mix of ships will do the most damage. If you have lots of shields it includes a strong mix of shield busters. If you have no tachyon emitters then it will include some cloaked ships, etc...

I realize this is trending back toward "A million customization flags at game start that could be overwhelming for a novice", but having all those flags was one of the things I really enjoyed about AIWC. There was always another cool thing to try for my next game.
If necessary can hide such flags under an "Advanced Customization" menu so that a first time player wouldn't even have to look.[/list]
: Re: Improving Wave Options
: keith.lamothe November 08, 2017, 11:11:10 AM
This does look like a good area for modders to tinker with at the moment, in that you're likely to enjoy it and it would be helpful if someone fleshed this out while I'm absorbed in the UI upheaval.

Bear in mind one key structural difference between AIWC and AIW2: AIWC had an intermediate state _before_ a wave was launched where the wave was "planned" and assigned a timer. That plan was then added to a world-level list that was counted down every second, shown in the alert box, etc.

AIW2 doesn't have that. It has a budget, and a target "launch a wave when I get this much in the wave budget" number, and when it reaches that threshold it immediately generates a wave and does all the targeting and composition decisions in that instant.

So the timer you see in AIW2 is just a projection, based on current AIP levels (and anything else that impacts the wave budget), whereas in AIWC it was a literal countdown.

Accordingly, to do a number of the things you have in mind we need to change AIW2's behavior from "when budget hits threadshold, immediately spawn stuff" to "when budget hits threshold, create a PlannedWave object and add it to a list for this faction, and every game-second count down each of those objects, and when the timer hits zero do the spawn logic"; and then the visual timer could be changed to look at those lists.

That can probably be achieved through the per-faction custom data and faction custom per-second logic, so you could do it yourself. But I'm happy to do it if you'd rather not deal with that particular element of the problem.


Another point is that, while you could use the conduct structure for this, I think you'll get more mileage using the per-faction custom fields. This allows you to have different AIs with different wave behaviors. So if you have multiple AIs controlling different areas of the map, your defensive situation on a planet is different depending on the AI(s) it neighbors.


As always, thanks for your many contributions :)

I hope some of the other players become more active in this effort, as well, but I understand that wandering into a multidimensional lumber mill is not for everyone ;) And there's other factors like schedule and willingness to deal with C#, etc.
: Re: Improving Wave Options
: BadgerBadger November 08, 2017, 04:32:51 PM
Cool, I'll investigate this. If you have other ideas for some low hanging fruit that needs doing feel free to ask, we'll see what my (or other modders) schedule permits.
: Re: Improving Wave Options
: BadgerBadger November 10, 2017, 09:36:52 PM
I'd like to have my Waves know why GameEntityTypeData they will be using (so I can warn things like "Incoming Fighter Wave" if desired). Is there an obvious way to Serialize/Deserialize those? I believe I can "make it work the hard way" if necessary, but if there's something easy then that would be preferrable.

Same question for a GameEntity so I can save the spawn location (though in this case the "Hard Way" is not very hard, I just make some ExternalData to attach to the Wormhole).
: Re: Improving Wave Options
: keith.lamothe November 10, 2017, 10:38:06 PM
I'd like to have my Waves know why GameEntityTypeData they will be using (so I can warn things like "Incoming Fighter Wave" if desired). Is there an obvious way to Serialize/Deserialize those? I believe I can "make it work the hard way" if necessary, but if there's something easy then that would be preferrable.
I'm just going to give you my stream of consciousness of how I would plan to implement this feature (announced waves, in general), with some explanatory notes. If you want to do it, be my guest. Otherwise I'll already have the notes for when I do it :)


Extending the schema to fit the new gamestate:

1) Add an ExternalDataPattern named "PlannedWaves" or something like that. Its GetShouldInitializeOn would return true on "Faction" (that is, it's attached to Faction objects, rather than World or GameEntity or whatever).
2) In that pattern have a List<PlannedWave>
3) Define PlannedWave as a class containing:
- Planet TargetPlanet
- ArcenSparseLookup<GameEntityTypeData,int> Composition
- int GameSecondToSpawn
4) Implement the pattern's InitializeData, SerializeData, and DeserializeData methods to handle that list.
5) Similar to how DoomData does it, write a ExtensionMethodsFor_DoomData class with a GetPlannedWaves method so we can later write faction.GetPlannedWaves() and get that list with no extra fuss.
- if you like, you can add a convenience method there for AddWave or something like that

On the serialization, a few notes:
- for how to serialize a list at all, look at how DoomData handles DoomedPlanetIndices
- for serializing PlannedWave, give it the usual signatures:
-- public void SerializeTo( ArcenSerializationBuffer Buffer, bool IsForSendingOverNetwork )
-- public static PlannedWave DeserializeFrom( ArcenDeserializationBuffer Buffer, bool IsLoadingFromNetwork, GameVersion DeserializingFromGameVersion )
-- and where you'd normally just call Buffer.Add(int) call plannedWave.SerializeTo(Buffer,...), and similar on the deserialization side
- for serializing the Planet, just send planet.PlanetIndex down as an int, and when it comes back up call World_AIW2.Instance.GetPlanetByIndex(Buffer.ReadInt32())
- for serializing the <type,int> lookup, do it like a list with sending the count down first (.GetPairCount()) and then looping, but instead of doing one Add/SerializeTo call you do two.
- for serializing the GameEntityTypeData itself, just call GameEntityTypeDataTable.Instance.SerializeTo(type,buffer,...) ; there's a similar DeserializeFrom method for picking it back up.
-- if you're curious, all it does is serialize the InternalName (string) of the row, which is why InternalName mustn't change once a savegame has been created that references that particular row


Extending the simulation to populate the new gamestate:

1) Split the innards of SendWave into something like:
PlannedWave PlanWave()
- gets all the stuff involved in choosing the target, what ships to send, and (new logic) what time it should spawn
void SpawnWave(PlannedWave)
- gets all the rest of the stuff from SendWave (i.e. the actual spawning)

2) Have SendWave just call the first and then immediately the second.

3) Have TryToSpendBudget_Wave call only PlanWave, and then faction.AddWave(newWave)


Extending the simulation to use the new gamestate:

Override DoPerSimStepLogic in the class you're working in (SpecialFaction_AI), and have it:
- loop over GetPlannedWaves()
-- if GameSecondToSpawn > World_AIW2.Instance.GameSecond, skip
-- else call SpawnWave on that wave
--- and remove that wave from the list


Extending the UI to represent the new gamestate:

In Window_ResourceBar.tThreat_BottomLine.GetTextToShow() :
- instead of that stuff about threshold and perSecond and all that, just loop over GetPlannedWaves() inside the faction loop
- remember the smallest wave.GameSecondToSpawn you find
-- optionally filter on TargetPlanet.GetControllingSide().Type == Player or something like that, in case of later logic with the AI launching waves against minor factions or other AIs or other craziness ;)
- take smallest GameSecondToSpawn - World_AIW2.Instance.GameSecond, and save that as leastSecondsLeft, and the existing code will display it fine
- reimplement HandleMouseover to contain info on the ships that are coming, where it's going, etc.

You may want to encapsulate that "get the soonest-to-spawn wave" logic somewhere so you can use it in coloring a planet name on the galaxy map, etc. Though there it may be best to call it at the beginning of a UI frame and reference that computed value for the duration of the frame, or something like that. I'm not sure about the thread-safety considerations, though things like GetTextToShow are fairly well timed to occur when the sim is "stable" (not being written to), unlike other parts of the visualization code.


By the way, I forget if I asked before: why do you not use MonoDevelop? I think it will at least give you intellisense and some syntax autocompletion, etc.
: Re: Improving Wave Options
: BadgerBadger November 11, 2017, 12:03:25 AM
You'll be pleased to know that your sketched plan was very similar to what I was already planning, though more concretely and accurately realized. Good stuff.

I actually have MonoDevelop installed, but it crashes whenever I try to start it and I haven't gotten around to debugging it.
: Re: Improving Wave Options
: BadgerBadger November 13, 2017, 12:19:41 AM
Okay, I'm not quite done yet, but things are coming along nicely.

I do have one question. How large should the first wave be? For all waves past the first wave, I just spend the value in faction.AITypeData.BudgetItems[AIBudgetType.Wave] which is generated by the Budgeting code. But for the first wave the budget won't have accumulated yet.
: Re: Improving Wave Options
: keith.lamothe November 13, 2017, 07:42:41 AM
But for the first wave the budget won't have accumulated yet.
TryToSpendBudget (which calls TryToSpendBudget_Wave) is only called when faction.StoredStrengthByBudget[budget] >= faction.GetSpecificBudgetThreshold(budget) , so whenever TryToSpendBudget_Wave calls PlanWave you can trust that spending the amount in faction.StoredStrengthByBudget[budget] is a reasonable thing to do.

Are you not finding that to be the case?
: Re: Improving Wave Options
: BadgerBadger November 13, 2017, 08:57:09 AM
Ah, I didn't know how TryToSpendBudget was called (that call doesn't seem to be in external code). I actually assumed it was called every X seconds, based on faction.AITypeData.BudgetItems[AIBudgetType.Wave].SecondsBetweenAttemptsToSpend.

That said, the problem with the first wave is this. Lets say that the budget accumulates such that a wave comes every 5 minutes. In the old regime, this meant at the 5 minute mark a wave would show up. In the new regime I only queue the wave once the budget is filled, then the wave actually spawns faction.AITypeData.BudgetItems[AIBudgetType.Wave].SecondsBetweenAttemptsToSpend after it has been queued. So in the new regime, the first wave would show up at 10 minutes in. This means that the very first wave is a special case, since I would like to queue it as soon as the game begins.

Or am I missing something?
: Re: Improving Wave Options
: keith.lamothe November 13, 2017, 09:02:47 AM
Ah, I didn't know how TryToSpendBudget was called (that call doesn't seem to be in external code). I actually assumed it was called every X seconds, based on faction.AITypeData.BudgetItems[AIBudgetType.Wave].SecondsBetweenAttemptsToSpend.
It's only called when the threshold is hit. The threshold = (amount accumulated per second) * (SecondsBetweenAttemptsToSpend)


This means that the very first wave is a special case, since I would like to queue it as soon as the game begins.

Or am I missing something?
I think the thing you're missing is that the first game did not queue a wave as soon as the game begins, and that's why this model (adopted from the first game) does not fit well with an immediate wave :)
: Re: Improving Wave Options
: BadgerBadger November 13, 2017, 09:13:26 AM
Oh. That's fine then. Whew. I guess it makes more sense not to queue the wave immediately from a gameplay point of view (noone wants to be attacked at 1 second into the game).

: Re: Improving Wave Options
: keith.lamothe November 13, 2017, 09:23:19 AM
Oh. That's fine then. Whew. I guess it makes more sense not to queue the wave immediately from a gameplay point of view (noone wants to be attacked at 1 second into the game).
Yep.

If we did want that I could just set the starting budget equal to the threshold, done.

I'm planning to move more of the budget framework down into external later this week; we'll see. I don't think it will give you much more power for the already-defined budget-types, but it will make it easier to have budget-logic for factions that don't do the same things the AI does.
: Re: Improving Wave Options
: BadgerBadger November 13, 2017, 06:34:12 PM
See the hover text. How does that look?

Also note I tweaked the time modifier text to be like AIWC. Opinions?
: Re: Improving Wave Options
: keith.lamothe November 13, 2017, 06:56:47 PM
See the hover text. How does that look?

Also note I tweaked the time modifier text to be like AIWC. Opinions?
Looks good to me, great work getting the underlying guts to that point :)
: Re: Improving Wave Options
: BadgerBadger November 13, 2017, 09:02:48 PM
I've got a weird one. I don't think this is a bug in my code, so I'm asking for assistance. I have here this printout line in PlannedWave::SerializeTo()
:
          ArcenDebugging.ArcenDebugLogSingleLine( "SerializeTo: PlannedWave  " + output + " planetwithWarpGate " + planetWithWarpGate.Name + "(" + planetWithWarpGate.PlanetIndex + ")" + " targetPlanet " + targetPlanet.Name + "(" + targetPlanet.PlanetIndex + ")" , Verbosity.DoNotShow )\

This prints out
11/13/2017 8:54:14 PM   SerializeTo: PlannedWave   2 Laser Gatling,  6 Grenade Launchers to Colmerauer in 47s planetwithWarpGate Sten(18) targetPlanet Colmerauer(0)
So you see that targetPlanet.PlanetIndex is 0. However, when I run this through the Deserialize thusly
:
          int targetidx = buffer.ReadInt32();
          ArcenDebugging.ArcenDebugLogSingleLine( "ctor 2 target idx " + targetidx , Verbosity.DoNotShow );
          this.targetPlanet = World_AIW2.Instance.GetPlanetByIndex( targetidx );
          if(targetPlanet == null)
            {
              ArcenDebugging.ArcenDebugLogSingleLine( " targetPlanet is null" , Verbosity.DoNotShow );
            }

I get the log
11/13/2017 8:54:18 PM   ctor 2 target idx 0
11/13/2017 8:54:18 PM    targetPlanet is null

So it looks like a planet can legitimately have Index 0, but calling GetPlanetByIndex(0) gets "null".

Am I missing something? If I use a different seed where the planet index is non-zero then it works fine.

Edit: It looks like GetPlanetByIndex is just not working right....

:
              for(int i = 0; i < 80; i++)
                {
                  Planet planet = World_AIW2.Instance.GetPlanetByIndex( i );
                  if(planet == null)
                    {
                      ArcenDebugging.ArcenDebugLogSingleLine( " planet idx " + i + " is null" , Verbosity.DoNotShow );
                    }
                  else
                    {
                      ArcenDebugging.ArcenDebugLogSingleLine( " planet idx " + i + " is " + planet.Name , Verbosity.DoNotShow );
                    }
                }

tells me every planet is null:
:
11/13/2017 9:17:35 PM planet idx 0 is null
11/13/2017 9:17:35 PM planet idx 1 is null
11/13/2017 9:17:35 PM planet idx 2 is null
11/13/2017 9:17:35 PM planet idx 3 is null
11/13/2017 9:17:35 PM planet idx 4 is null
11/13/2017 9:17:35 PM planet idx 5 is null
11/13/2017 9:17:35 PM planet idx 6 is null
11/13/2017 9:17:35 PM planet idx 7 is null
11/13/2017 9:17:35 PM planet idx 8 is null
11/13/2017 9:17:35 PM planet idx 9 is null
<etc>

: Re: Improving Wave Options
: keith.lamothe November 13, 2017, 09:21:10 PM
So it looks like a planet can legitimately have Index 0, but calling GetPlanetByIndex(0) gets "null".
Planets are deserialized after Factions, so you'll just have to hold onto the index. In your case the planet list is empty at that point in time.

For this reason sometimes I only keep the index even during the game, and just look it up in any functions that need it. GetPlanetByIndex() is inexpensive.

Or you can keep a reference and populate it at some point after deserialization.

Make sense?
: Re: Improving Wave Options
: BadgerBadger November 13, 2017, 09:25:09 PM
Yup, I can work around that easily enough.
: Re: Improving Wave Options
: BadgerBadger November 14, 2017, 01:28:17 AM
   I am attaching here a patch that implements a rework of Wave Sending logic. It allows a lot more flexibility with things like

This patch re-implements the current behaviour. The only changes apparent to the player are a tooltip to show when and where the AI waves are incoming, that AI waves now default to 2 different types of ships (this done primarily to illustrate the capability. Currently hardcoded but easily tunable), and that the player gets a max of 5 minutes warning for the incoming wave (again hardcoded, done to illustrate the capability, but easily tunable)
   
The code as written seems to work okay for me, both the regular Wave path and the Hacking paths. Submitting this patch for review/critique. You are welcome to incorporate it as is, but I suspect you might prefer to send it back for some changes (be they only tidying/rationalization of variable names).

Future work includes flagging a planet with an incoming wave in the Galaxy Map (maybe by changign the planet colour?). Also explicitly allowing the player to choose between

Note for anything using this that the first wave will now appear 20 minutes into the game, so you will see a warning 15 minutes in (see the discussion about the first wave time earlier in this thread)
: Re: Improving Wave Options
: keith.lamothe November 14, 2017, 09:53:38 AM
Thanks very much :)

A few observations from testing:

1) The timer comes up about the time I would expect, and the tooltip tells me how many squads of what types will come, and it sounds reasonable, but when the timer is done the units don't spawn on my planet, but on a neighboring one. I mention it because I thought you said "Direct Waves" was the current behavior? Or did you mean something else?

2) After that wave launches, the timer remains (starting at 10 minutes), but the tooltip does not describe the contents. Later on it did describe them; I don't know if that was just a later stage of the same timer or a timer-after-that-timer. It's as if it's showing the time until the next announcement, or until the next wave, but the wave itself hasn't been planned yet. I have no idea.

Is this the behavior you intended?
: Re: Improving Wave Options
: BadgerBadger November 14, 2017, 10:04:09 AM
Neither of those behaviours sounds desirable. Looks like I haven't ironed out all the bugs yet; ah the joys of late night coding. I'll take another look tonight and hopefully make things happier.

I do have a question about what I call "Cross Planet Waves", where the ships should spawn on a remote Warp Gate then fly to the target system. If I spawn the units during PerSimStep then I need to control those units explicitly during the DoLongRangePlanning step and say "Go to your target". The obvious way to do that is to attach some ExternalData (the planet idx of the target, I expect) to those entities so I can check that in DoLongRangePlanning. Is that an approach you would recommend?
: Re: Improving Wave Options
: BadgerBadger November 14, 2017, 11:01:27 AM
Okay, both of the things you complained about are resolved thanks to two one-liner fixes. (in one case I picked the wrong end of the wormhole, in the other case I failed to reset a variable at the beginning of the "detect any valid incoming waves" loop). Give it another try.

Edit: also some minor code tidying. The number of different incoming ship types is now a random number between 1 and 3. Waves will sometimes spawn actually at a warp gate, then travel in regular space to the target planet; this style of wave will produce a different  tooltip message explaining the behaviour.
: Re: Improving Wave Options
: keith.lamothe November 14, 2017, 12:18:31 PM
I do have a question about what I call "Cross Planet Waves", where the ships should spawn on a remote Warp Gate then fly to the target system. If I spawn the units during PerSimStep then I need to control those units explicitly during the DoLongRangePlanning step and say "Go to your target".
It depends on what you want them to do. In AIWC CPWs basically just spawned as threat. If that's all you want here then set their Behavior to Attacker and you're done.

If you want them to path to a specific planet, or otherwise pursue a purpose beyond normal threat logic, you'll need to do something else.

The obvious way to do that is to attach some ExternalData (the planet idx of the target, I expect) to those entities so I can check that in DoLongRangePlanning. Is that an approach you would recommend?
I don't see why you'd need to do that; you can just queue up orders on the entities right as you spawn them and they'll generally follow those orders. If you find that the threat logic is "fighting" you by overriding those orders then let me know and we can sort out a mechanism whereby you can give non-overridable orders or something like that.

Thanks for the fixes, I'll look at those later today.
: Re: Improving Wave Options
: BadgerBadger November 14, 2017, 12:51:25 PM
You can't send orders without an ArcenLongTermPlanningContext, can you? And the code doesn't seem to have one of those in the PerSimStep logic.
: Re: Improving Wave Options
: keith.lamothe November 14, 2017, 01:29:19 PM
You can't send orders without an ArcenLongTermPlanningContext, can you? And the code doesn't seem to have one of those in the PerSimStep logic.
I don't mean send the orders, I mean queue the orders, like:

:
entity.EntitySpecificOrders.QueuedOrders.Add( EntityOrder.Create_Wormhole( 2, false ) );
Speaking more generally, in a PerSimStep situation you can modify the gamestate (that isn't flagged for use by some other thread) with a great degree of freedom as long as you stick to stuff that is synchronized between machines in MP (so don't base your modifications on what planet the player is looking at, because that's different between machines, and make sure you use the context-object's random generator for any random rolls you need, etc).

And EntityOrder objects are just gamestate. You don't need to deal with GameCommand objects there.

LongTermPlanning exists mainly so that cpu-intensive decision making can happen on a thread that doesn't need to complete before the end of the current sim step.
: Re: Improving Wave Options
: BadgerBadger November 14, 2017, 06:20:12 PM
I updated my previous patch to include support for allowing the ships to spawn on a remote planet then travel through normal space to the target. Looks like the ships tend not to actually go through the wormhole and attack. I'm not sure if this is a bug in my code or because the AI threat algorithm thinks I'm too much of a threat. You can see what I did at the end of the SpawnWave() function
: Re: Improving Wave Options
: keith.lamothe November 14, 2017, 07:37:16 PM
I updated my previous patch to include support for allowing the ships to spawn on a remote planet then travel through normal space to the target. Looks like the ships tend not to actually go through the wormhole and attack. I'm not sure if this is a bug in my code or because the AI threat algorithm thinks I'm too much of a threat. You can see what I did at the end of the SpawnWave() function
That's the normal waiting logic. Through the eyes of roaming threat ships, the Ark is perceived mainly as "A Big Pile 'O Pain", so they usually won't go after it until they have a fairly sizeable force waiting against it (that can come from multiple different entry points).

If you want something that ignores waiting logic that's doable, it's just something to be deliberate about in the design, because it's basically telling those particular ships to be terminally stupid.
: Re: Improving Wave Options
: BadgerBadger November 14, 2017, 07:54:02 PM
I thought Waves were always intended to be "Periodically the AI sends a kamikaze attack", which is a distinct behaviour from Threat ships (unless you specifically ask for the Waves to join Threat, like with Cross Planet Waves as implemented in AIWC).

So to my mind, anything spawned as a Wave should just kamikaze into defenses. I'd like the AI to have the choice between spawning those waves directly on the planet and spawning them at a nearby warp gate, then sending them to you. But either way, I think they should attack without delay, then press that attack home with some vigor (even if most of them die). One nice thing about this behaviour is sometimes the player overreacts and weakens their defenses elsewhere.

If you have a different conception of what Waves should be then that's fine (you are the Designer of the game, after all).  But I still think my preferred behaviour should be saved as an option, since it's basically what AIWC did.

Edit: there's also a gameplay issue with the Retreat code in LongRangePlanning for the Threat Fleet. When it's choosing to retreat from a planet due to suddenly arrived human reinforcements, it seems to choose an AI planet at random to retreat to. In one example caused the Threat fleet to walk right past my arrived reinforcements and all die, instead of flying directly away from my reinforcements to a wormhole to a different AI planet. I think this code needs to be aware of where the forces on the planet are (or at least privilege the closest wormhole to retreat to, if figuring out where the human forces are in relation to the AI ships is too much effort for now). I opened this as https://bugtracker.arcengames.com/view.php?id=19296 to make sure it's not forgotten; it's one of those little things that makes the AI look smart.

Also, the AI threat fleet has a nasty tendency to camp your wormholes, which makes it in many ways less threatening; you can always provoke a fight and try to whittle it down. I think having it lurk a planet or two away might make it much more scary to deal with.
: Re: Improving Wave Options
: BadgerBadger November 29, 2017, 08:38:46 PM
What's the desired behaviour of a wave when there are no warp gates immediately adjoining human space? I don't think my initial implementation handled this case as well as I wanted. I propose to have the wave spawn on the AI Master Controller and join the Threat Fleet (and possibly get something like 5% bonus strength because the AI doesn't like being unable to attack you directly), but I'm open to other suggestions.
: Re: Improving Wave Options
: keith.lamothe November 29, 2017, 08:51:55 PM
What's the desired behaviour of a wave when there are no warp gates immediately adjoining human space? I don't think my initial implementation handled this case as well as I wanted. I propose to have the wave spawn on the AI Master Controller and join the Threat Fleet (and possibly get something like 5% bonus strength because the AI doesn't like being unable to attack you directly), but I'm open to other suggestions.
The AIWC behavior was to pick a random warp gate (and iirc it had to be one of the ones closest to human space; so no picking a 3-hopper if there are any 2-hoppers) and spawn it there as threat.

I think that's probably a good behavior to start with, though it's easier to spawn at the MC. I wouldn't assign a strength boost; it's enough of an advantage to the AI that it gets the full "credit" of threat without running it through the human grinder first.

It's ironic, but in many ways the wave mechanic is a situation where the AI periodically gets reinforcements to its threat force, but they always get ambushed by the human's defenses before they can join the main force.

Unless AIP gets really high, or there's a ton of other bad stuff happening to the human at the same time. Then the waves can contribute to a real danger.
: Re: Improving Wave Options
: BadgerBadger November 30, 2017, 11:23:03 AM
How do you feel about allowing humans to cancel an incoming wave by destroying the warp gate that's going to be used, at <some cost>? I feel like it would add a fun sense of agency/strategy, and it always seemed really weird to me in AIWC that destroying the Warp Gate wouldn't stop the wave.

There are a three obvious things the AI can do once a wave is blocked.
One is to try to pick a new suitable warp gate/target.
Another is to spawn the wave as threat.
The third is to "refund" the wave (ie Cancel it, but add its strength to the next wave)

Proposed behaviour:
Humans destroy warp gate AI intends to use for a wave
if Player Has Not Been Warned About Wave
   attempt to pick a new suitable warp gate/target, else spawn wave as threat
       This way a player can't be penalized for interfering with a wave they don't know about

If player has been warned about the wave
    Refund the wave with a 5% strength bonus for interfering with the AI. So you can postpone a wave, but at a cost


: Re: Improving Wave Options
: keith.lamothe November 30, 2017, 03:05:24 PM
Proposed behaviour:
Humans destroy warp gate AI intends to use for a wave
if Player Has Not Been Warned About Wave
   attempt to pick a new suitable warp gate/target, else spawn wave as threat
       This way a player can't be penalized for interfering with a wave they don't know about

If player has been warned about the wave
    Refund the wave with a 5% strength bonus for interfering with the AI. So you can postpone a wave, but at a cost
That's fine, though I don't know if the strength bonus is necessary since destroying a warp gate costs 5 AIP.
: Re: Improving Wave Options
: keith.lamothe December 01, 2017, 03:53:35 PM
Btw, in my quest to get you a semi-reasonable C# editing environment (which would make it more reasonable for you to follow our indentation/etc patterns), have you tried https://www.jetbrains.com/rider/ ?

It's not free, but there's a 30-day trial, so you could see if it actually works or if it's another crashes-and-burns option.
: Re: Improving Wave Options
: BadgerBadger December 01, 2017, 04:25:29 PM
I'll take a look at that dev environment if I get the chance.

Okay, I think I have my proposed behaviour implemented. I'll spend a bit more time making sure it's bug free then sent it to you. Specifically I'd like to wait till the Resource bar hovertext works again (it's broken right now, https://bugtracker.arcengames.com/view.php?id=19301) so I can validate the behaviour there.

When I give you the code it will also include the "Letting wormhole colour indicate an incoming wave" (but that code relies on some of the other changes I made to implement cancelling waves once the warp gate is destroyed so it's not done yet). The colour indicator will glow between the "Wave incoming!" colour and the faction colour and it looks cool.

I'm not quite sure how you want to handle per-faction tunings (since as you say, the AI ifs a faction) like "How the AI should launch waves", but if can give me some examples I'll expose wave settings like "How much warning to give for incoming waves" (which is a cool thing that AIWC didn't have. You could disable wave warnings entirely, but the ability to tweak the warnings is new).
: Re: Improving Wave Options
: BadgerBadger December 01, 2017, 05:01:32 PM
Okay I lied, it seems to be working okay right now.

 Commit message
    Wave modifications
   
    Wormhole names indicate via colour if a wave will be coming through that wormhole.
    The colour will lerp from Red to the faction colour in an aesthetically pleasing fashion.
   
    In AIWC, once a wave was announced it would always hit, even if you destroyed the Warp Gate
    it was using. I found that behaviour Uninuitive and non-interactive, and think it woudl be cooler
    to let the player influence wave behaviour by destroying those warp gates.
   
    Here's how waves now handle their warp gate being destroyed. If a wave has been scheduled but  the humans are not yet alerted to it, the wave will
    change warp gate/target planet but stay on schedule. In other words, the player will just get a wave on schedule;
    even though it's not the one originally intended, and there's no way for the humans to know that the wave they are
    getting wasn't the original wave.
   
    If the player has been alerted to the incoming wave then that wave gets cancelled and doesn't arrive. Edit: However,
    some percentage of the wave's strength is added to the next wave so that there's a tradeoff. You can set the percentage on a per-wave
basis.

Edit: this new tarball has a few minor bugfixes and code cleanups

A lot of these new behaviours are ripe for tweaking for fun/balance. For example, darkarchon suggested that it would make more sense if the cancelled wave would partially spawn once the warp gate was destroyed (a % based on how close the wave was to launching), while the rest of the cancelled wave's strength would spawn as Threat. My goal is to introduce the mechanics and we'll see what's fun/challenging once people have gotten a chance to try the new wave style.