Jump to content

Lucubration

Premium Member
  • Posts

    139
  • Joined

  • Last visited

Everything posted by Lucubration

  1. These warnings are just because I have some unused variables declared at the beginning of the function. It shouldn't hurt anything, but you can remove them if you like.
  2. Flush is supposed to make a target run away for one turn? Not sure on the details, but somewhere in class XComGameState_AIGroup.uc is a retreat function that triggers once you reduce a pod to 1 member. Maybe try finding out how that works exactly and try to see if you can either manually trigger it or if you can make your own ability from it? Thank you for the suggestion. I have looked at that one, and it didn't appear like it would be applicable to our purpose. The issue is that it simply weights the AI's behavior for getting allied units in sight. If the unit is still with their own pod, however, then they already have their allies in sight.
  3. Speaking of AI, one of the more frustrating hurdles we've got with the Escalation classes is the target unit's behavior when Flush is used on them. The behavior for most units is desirable because they tend to run away from the user towards their default range, but melee units specifically will charge the player's units because their default range is 1 or 0. DerBK, do you know if there's a straightforward way to make the unit simply open up distance between them and the enemy rather than moving relative to the default range? I couldn't really find anything along those lines in the weights for move tile selection.
  4. I'm not sure it is precisely a problem in the engine; it's working as it "should" by spec (the Chryssalid has no original player, and that's exactly what it's returning to you). It's just not a useful behavior in this case. I think the most straightforward way to get it working is probably as you suggest: duplicate the slash attack with a custom effect subclass of the parathenogenic poison effect, which in turn "fixes" the GetTeam method.
  5. Hey, davidlallen, I don't know if you saw this on Reddit, but it's basically exactly what you were asking about regarding saving .ini file changes. It's really simple and works dead easy, too: https://www.reddit.com/r/xcom2mods/comments/4c6qrr/new_way_to_loadsave_ini_configs/
  6. The team does get set for friendly units, just not when they're created in the strategic game. The pathenogenic poison effect specifically looks for the original controlling player when it applies; I'm not sure how many other effects do that, but probably not very many if any (maybe the Andromedon's robot phase?). The Chryssalid's abilities were just created with the assumption that the unit would always be created only for the tactical game, so it would always have an original controlling player. I think that it does get set for enemy units at the start of tactical as well in the XComAISpawnManager. That assumption isn't valid in your case since you create Chryssalids outside of the tactical game, so you need an effect that doesn't look for the original controlling player when spawning the cocoon.
  7. No, I don't think you are. From what I can, there is no XComGameState_Player for the player until the start of a tactical game, which means that units in your barracks all have no controlling player. When you launch a tactical game, the sequence of events seems to be: Create Player -> Copy Unit from Strategic to Tactical -> Assign Player as Unit.ControllingPlayer. That means that all units created during the strategic game will always have no original controlling player, and so the X2Effect_ParthenogenicPoison.GetTeam() will never return the correct team for a unit that was created before the tactical game was launched. I think the way around this is to use your PA_ParthenoEffect and override the GetTeam() function to not request the original team, only the current team. I just tried doing that before realizing that you no longer use the custom slash ability with the subclassed effect, so updating that class with an override didn't work out.
  8. I think the team is ultimately determined by the XComGameState_Unit.ControllingPlayer. We could set that, but the problem here is that as far as I can tell there is no player until we enter the tactical game, which means we can't set it initially when the unit is created. I'm going to try to override X2Effect_ParthenogenicPoison.GetTeam() to not request the original player, even though that could make things awkward if the Chryssalid gets mind controlled.
  9. Okay, I think I see what's happening there. The Chryssalid is indeed on the Xcom team; it's that the X2Effect_SpawnUnit is told to look for the unit's original team by the X2Effect_ParthenogenicPoison, not its current team. The Chryssalid was apparently spawned with no controlling player, so it has no original team at the start of gamestate history. The cocoon is therefore created on eTeam_None. Edit: The "dropunit" command seems to call XComAISpawnManager.CreateUnit(), which calls CreateUnitInternal(), which calls XComGameState_Unit.PostCreateInit() on the created unit, setting the initial controlling player to the player that typed the command, which must be why it works when spawning a unit with the console.
  10. Interesting. So one thing I'm seeing as I step through here is that it is trying to spawn a cocoon when the Chryssalid kills someone, and it's passing eTeam_None. When I step into the function that should resolve the team, it ends up disappearing down into XComUnitState.GetTeam(), which is a native function that I can't step into; it returns eTeam_None. It looks like the Chryssalid isn't technically on eTeam_Xcom and I suspect that may cause you some issues with the allegiance of the spawned units. Another thing I'm seeing is that it can't get the cocoon visualizer after it spawns the unit. I'll keep exploring in this area to see if I can't get more information about why it isn't appearing.
  11. Hey, Bret1. I use GameState objects because I often find that EventListeners and the default ability trigger functions aren't quite right for the sort of conditions under which I want my abilities to activate. Under the hood its all pretty similar, I'm just putting a new callback on a different object that I've created instead of using one of the default ones from the vanilla game scripts; I just find it a lot harder to track down what's not working correctly in situations like this when the even logic is all packaged away. If I understand correctly, the ability should be triggering damage against the unit with the ability every time they end a move? From what I can tell, it does look like that should be working.
  12. Write-protected template members is definitely one of the more annoying things I've run into with the SDK so far. I haven't found any solution other than to just replace the template outright using the template manager override.
  13. The little bugger just burrowed into the lift and messed up the hydraulics! Regarding the borrowed attack part, I'd suggest the first thing to look at would be this condition on the Chryssalid's standard UnburrowedSawEnemyAbility: // Only triggers from player controlled units moving in range UnitPropertyCondition = new class'X2Condition_UnitProperty'; UnitPropertyCondition.IsPlayerControlled = false; Template.AbilityShooterConditions.AddItem(UnitPropertyCondition); ... // Only triggers from player controlled units moving in range UnitPropertyCondition = new class'X2Condition_UnitProperty'; UnitPropertyCondition.IsPlayerControlled = true; Template.AbilityMultiTargetConditions.AddItem(UnitPropertyCondition); I'd speculate that the Unburrow and the BurrowedAttack abilities have to run in tandem to get the Chryssalid to properly do its reaction fire-like ability against nearby units. If he never unburrows, he'll probably never attack.
  14. Foreword As mods are getting more complex - my own included - I'm seeing a need to move some mod options from .ini files into the in-game UI to be more accessible to users. I was going to pursue a custom solution for my particular case, but I can imagine that might lead to a cluttered UI if a number of mods all began doing the same. With this in mind, I put together a little system here for inserting a "Mod Options" menu item into the normal, in-game Options menu. The technique uses screen listeners, the event manager and some dynamic type resolution to allow any interested mods to utilize this same pathway for displaying their own mod options screen for the user. I've gone ahead and published this Mod Options Menu despite nothing using it just yet. I'd to submit the design here as a request for comments. If this is a pattern that's of interest to you, I'd very much appreciate it if you would take a minute to help me go over the API design to make sure that it will be robust enough and suitable for all of our use. I'm mostly interested in making sure that the contract between the API and clients is well-designed; I expect that the actual UI design will change over time relatively transparent to any client mods. Nexus link: http://www.nexusmods.com/xcom2/mods/522/? Workshop link: http://steamcommunity.com/sharedfiles/filedetails/?id=652998069 Design I begin this pattern by using a UIScreenListener to see when the Xcom 2 main Options menu pops up. I'm inserting an extra button right down by the Credits button (at least in the Shell menu) that opens up the mod list. This is where things get interesting. Depending on which XComPlayerController spawned the Options screen, I'm creating one of three subclasses of the mod list screen (for the Shell, HQ, and Tactical game modes). In the superclass, there is much ugly UI code going on to set up the list and so on, and right at the start of it all I'm registering for a new event 'ModOptionsMenu_AddItem', The next piece of the puzzle here is the contract between the client mods and the API, and it involves another UIScreenListener implemented by the client. This one listens for the Mod Options Menu screen(s) and triggers the 'ModOptionsMenu_AddItem' event to advertise itself to the API. In this example I have it listening for all three different subclasses. The event data included in the 'ModOptionsMenu_AddItem' event contains the display name that should appear in the Mod Options Menu list of mods, and the name of a UIScreen subclass that should be instantiated on behalf of the client mod when the user selects that mod's name from the list. As you can see, I'm using this strange 'XGParamTag' class to transfer the event data. I had this hard requirement for myself that I had to use only types available in the Xcom 2 source scripts so that any mod could consume this pattern. The 'XGParamTag' class was the simplest object I could find in their codebase that could actually be cast as an 'object' and still contain the information we need for the pattern to function (a string or two). Yeah, it's a hack. The Mod Options Menu screen then receives the 'ModOptionsMenu_AddItem' event and adds the item to the list. The final step occurs when the client clicks on a mod name in the mod list. The Mod Options Menu screen instantiates the class specified by the client mod and pushes it to the top of the screen stack. I've also put together a very simple example mod that uses this API (attached to this post). Afterword So. Is this pattern something you'd be interested in using? Would it have to be improved in some way for you to consider using it?
  15. Oh, You don't want to set it in the ability template, but in a subclass of X2TargetingMethod_Cone which you assign as the ability template's TargetingMethod; basically, replace the line about Cursor.m_fMaxChainedDistance from the example above with the assignment that you were trying for the cone length. The ability template won't know what UnitState is.
  16. One issue I found working with similar abilities is that weapon ranges are actually defined as being relatively infinite (99 tiles, I think), and the targeting restrictions for normal shooting abilities are done using the soldier's max sight range stat in the targeting method. I'd suggest making a similar override of the X2TargetingMethod_Cone and chaining the cursor to the unit's max sight range in the Init function. Something like: class X2TargetingMethod_YourModNameHere_Cone extends X2TargetingMethod_Cone; function Init(AvailableAction InAction) { local float TargetingRange; super.Init(InAction); // determine our targeting range TargetingRange = UnitState.GetCurrentStat(eStat_SightRadius); // lock the cursor to that range Cursor.m_fMaxChainedDistance = `METERSTOUNITS(TargetingRange); } I think 'Cursor' is defined in the superclass here and used to restrict the cursor movement range for the ability, but I can't be certain.
  17. One thing it sounds like you might not be doing is adding the X2Effect_Suppression as a MultiTargetEffect instead of just a TargetEffect. Here's a very similar ability template I put together for building an AoE version of Suppression for Beaglerush's Escalation classes: As you can see, I made this one a radius target instead of a cone target. There were two other things I had to do to get this to work: I changed the visualization function to make the first MultiTarget into the PrimaryTarget because the Suppression idle animation (which does the shooting loop) requires a primary target to aim at.I replaced the weapon's animation for Suppression with its normal animation for Firing if it didn't support the suppression animation. This is the same technique I used to create the Suppression Visualization Fix mod for the single-target effect.
  18. I don't think you need to give up just yet on creating an ability to add a particle effect to the helmet. I've done something similar in the past, and I think it shouldn't be too onerous. Here's the basics of what you need. First, the X2Effect class that will play the effect attached to the socket: // This is the effect that plays the particle effect attached to a socket class X2Effect_YourModNameHere_ParticleEffect extends X2Effect_Persistent; var name FXSocketName, FXEffectName; private function DoTargetFX(XComGameState_Effect TargetEffect, out VisualizationTrack BuildTrack, XComGameStateContext Context, name EffectApplyResult, bool bStopEffect) { local XComGameState_Unit PrimaryTarget; local X2Action_PlayEffect PlayEffectAction; if (FXSocketName == none) { `RedScreen("Forgot to assign the socket name."); return; } if (FXEffectName == none) { `RedScreen("Forgot to assign the effect name."); return; } PrimaryTarget = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(TargetEffect.ApplyEffectParameters.AbilityInputContext.PrimaryTarget.ObjectID)); if (PrimaryTarget != none) { // Play the effect animation for the detected unit PlayEffectAction = X2Action_PlayEffect(class'X2Action_PlayEffect'.static.AddToVisualizationTrack(BuildTrack, Context)); PlayEffectAction.EffectName = FXEffectName; // Okay, this is where my offhand knowledge breaks down. There are one or two more properties we need to set // on this action, including the socket name, but I don't know what they are and I don't have the source available // to me right now to look it up. I'll do so when I get home PlayEffectAction.SOMETHING = SOMETHING; PlayEffectAction.bStopEffect = bStopEffect; } else (TargetEffect == none) { `RedScreen("Could not find unit state."); return; } } simulated function AddX2ActionsForVisualization(XComGameState VisualizeGameState, out VisualizationTrack BuildTrack, name EffectApplyResult) { local XComGameState_Effect TargetEffect; if (EffectApplyResult != 'AA_Success') { // We're only going to visualize the Awareness active effect when it applies successfully return; } foreach VisualizeGameState.IterateByClassType(class'XComGameState_Effect', TargetEffect) { if( TargetEffect.GetX2Effect() == self ) { break; } } if (TargetEffect != none) { DoTargetFX(TargetEffect, BuildTrack, VisualizeGameState.GetContext(), EffectApplyResult, false); } else { `RedScreen("Could not find effect state."); } } simulated function AddX2ActionsForVisualization_Sync(XComGameState VisualizeGameState, out VisualizationTrack BuildTrack) { // We assume 'AA_Success', because otherwise the effect wouldn't be here (on load) to get sync'd AddX2ActionsForVisualization(VisualizeGameState, BuildTrack, 'AA_Success'); } simulated function AddX2ActionsForVisualization_Removed(XComGameState VisualizeGameState, out VisualizationTrack BuildTrack, const name EffectApplyResult, XComGameState_Effect RemovedEffect) { DoTargetFX(RemovedEffect, BuildTrack, VisualizeGameState.GetContext(), EffectApplyResult, true); } Second the X2AbilityTemplate class for the ability that applies the X2Effect to the unit: class X2Ability_YourModNameHere_AbilitySet extends X2Ability; // This method is natively called for subclasses of X2DataSet. Create and return the ability template static function array<X2DataTemplate> CreateTemplates() { local array<X2DataTemplate> Templates; Templates.Length = 0; Templates.AddItem(ParticleEffectAbility()); return Templates; } static function X2AbilityTemplate ParticleEffectAbility() { local X2AbilityTemplate Template; local X2Effect_YourModNameHere_ParticleEffect ParticleEffect; `CREATE_X2ABILITY_TEMPLATE(Template, 'YourModNameHere_ParticleEffectAbility'); Template.AbilitySourceName = 'eAbilitySource_Perk'; Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_NeverShow;// Doesn't show up on the unit's action bar Template.Hostility = eHostility_Neutral; Template.bIsPassive = true; Template.AbilityToHitCalc = default.DeadEye; Template.AbilityTargetStyle = default.SelfTarget; Template.AbilityTriggers.AddItem(default.UnitPostBeginPlayTrigger); // This effect will perform the creation and attachment of the particle effect ParticleEffect = new class'X2Effect_YourModNameHere_ParticleEffect'; ParticleEffect.EffectName = 'YourModNameHere_ParticleEffect'; ParticleEffect.BuildPersistentEffect(1, true, false); // Make the effect last forever ParticleEffect.SetDisplayInfo(ePerkBuff_Passive, Template.LocFriendlyName, Template.LocLongDescription, Template.IconImage, false,, Template.AbilitySourceName); // Hide the effect so it doesn't show up on the unit status ParticleEffect.DuplicateResponse = eDupe_Ignore; ParticleEffect.FXSocketName = 'YourSocketNameHere'; ParticleEffect.FXEffectName = 'YourFXNameHere'; Template.AddTargetEffect(ParticleEffect); Template.BuildNewGameStateFn = TypicalAbility_BuildGameState; // This function will (I think) call effect's visualization function, which is where we'll attach the particle effect Template.BuildVisualizationFn = TypicalAbility_BuildVisualization; return Template; } Lastly, have the item give the dummy ability to the unit that equips it by adding this line to the item template definition: Template.Abilities.AddItem('YourModNameHere_ParticleEffectAbility');
  19. Oh, wow, those look really good! Can't wait to see how they turn out in the end.
  20. Sorry; I've been pretty consumed with recent projects. Once I wrap up this next stage, I promise I'll step back and write up an article.
  21. You're welcome for the help, though I didn't do anything besides mention the build output directory. It's just such weird behavior, and it seems really relevant because it could cause issues for anyone working on a collaborative project. I didn't realize the Workshop didn't even have a way to allow multiple people to publish the same project. I'd have thought that was the point of the Contributors list.
  22. Hey, folks. One of our modders just ran into an interesting issue related to Steam's Publish IDs that I wanted to bring up. In this modder's case, they received a mod project that they were collaborating on and intended to build and publish it to Steam. After they built it and went to publish the file, ModBuddy published it with a new Publish ID instead of the one indicated in the mod project file. After some searching, we discovered that the built files that ModBuddy put into a subdirectory of 'Steam\SteamApps\common\XCOM 2 SDK\XComGame\Mods' contained a blank Publish ID. The modder changed the Publish ID in the 'XCOM 2 SDK' path and, voila, was able to properly publish to the existing project on Steam. I don't have any firsthand experience with this, but I wanted to ask if this is a common problem with collaborative mod projects when publishing to Steam. Has anyone experienced this before or know why this would occur?
  23. Oh, that's very sweet.
  24. Wow, the Sectoid animations actually look pretty good on the xeno model.
  25. From everything I've read, there was a ~100 MB patch to allow new customization options for right and left arm props, as well as a few bug fixes to stuff like the Grenadier's Demolish skill not updating the target's cover state.
×
×
  • Create New...