General Category > Private Alpha Discussion
Improving Wave Options
BadgerBadger:
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.
* Disable Wave Warnings: Pretty straightfoward
* Wave Target Warnings: Determine which planet will get the next wave when a given wave is sent so that we can alert the player in advance of the wave target
* Direct Waves: Pick a planet owned by the humans, then drop a bunch of units of one type on it. Current behaviour
* Threat Waves: waves will now always spawn on an AI homeworld and just join the threat fleet
* Cross Planet Waves: waves will spawn at a nearby Warp Gate then have to travel to the target (Original AIW2 behaviour)
* Wave Composition: Homogenous/Schizophrenic: allow for a variety of ships to be sent in a waveFor 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]
keith.lamothe:
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.
BadgerBadger:
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.
BadgerBadger:
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).
keith.lamothe:
--- Quote from: BadgerBadger on 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.
--- End quote ---
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.
Navigation
[0] Message Index
[#] Next page
Go to full version