wghost81 Posted August 19, 2014 Author Share Posted August 19, 2014 Here's working random meld placement code: UPK_FILE=XComGame.upk // convert XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints.arrEasyMeldSpawnPoints to integer EXPORT_ENTRY=XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints.arrEasyMeldSpawnPoints OBJIDX=Core.IntProperty // new type REL_OFFSET=8 OBJIDX=XGBattle_SP.InitMeldContainers // new owner REL_OFFSET=12 NAMEIDX=A // new name REL_OFFSET=32 UNSIGNED=40 // new serial size // reset property flags for new var A OBJECT=XGBattle_SP.InitMeldContainers.A REL_OFFSET=20 UNSIGNED=0 // set PropertyFlagsL to zero // convert XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints dynamic array to structure EXPORT_ENTRY=XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints OBJIDX=Core.StructProperty // new type // make arrEasyMeldSpawnPoints a vector OBJECT=XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints REL_OFFSET=20 UNSIGNED=0 // set PropertyFlagsL to zero REL_OFFSET=40 OBJIDX=Core.Object.Vector // change inner type of arrHardMeldSpawnPoints array OBJECT=XGBattle_SP.InitMeldContainers.arrHardMeldSpawnPoints.arrHardMeldSpawnPoints REL_OFFSET=40 OBJIDX=XComSpawnPoint // link new var A to XGBattle_SP.InitMeldContainers OBJECT=XGBattle_SP.InitMeldContainers.kMeldActor_Arc REL_OFFSET=12 OBJIDX=XGBattle_SP.InitMeldContainers.A // NextRef OBJECT=XGBattle_SP.InitMeldContainers:AUTO ALIAS=World:12 20 <Class.XComWorldData> 0A 00 <XComWorldData.GetWorldData.ReturnValue> 00 1B <GetWorldData> 16 ALIAS=numX:19 <!World> 09 00 <XComWorldData.NumX> 00 01 <XComWorldData.NumX> ALIAS=numY:19 <!World> 09 00 <XComWorldData.NumY> 00 01 <XComWorldData.NumY> ALIAS=numZ:19 <!World> 09 00 <XComWorldData.NumZ> 00 01 <XComWorldData.NumZ> ALIAS=PlayerLocation:19 10 26 00 <.arrHardMeldSpawnPoints> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> //ALIAS=DebugLog:19 2E <Class.XComOnlineEventMgr> 19 2E <Engine.GameEngine> 12 20 <Engine.Engine> 0A 00 <Engine.Engine.GetEngine.ReturnValue> 00 1C <Engine.Engine.GetEngine> 16 09 00 <Engine.GameEngine.OnlineEventManager> 00 01 <Engine.GameEngine.OnlineEventManager> FF 00 <NullRef> 00 1B <DevOnlineMsg> [REPLACEMENT_CODE] //kMeldActor_Arc = XComMeldContainerActor(DynamicLoadObject("MeldCanister_MOD.MeldCanister_ARC", class'XComMeldContainerActor', false)) 0F 00 <.kMeldActor_Arc> 2E <Class.XComMeldContainerActor> 1C <Core.Object.DynamicLoadObject> 1F <%t "MeldCanister_MOD.MeldCanister_ARC"> 20 <Class.XComMeldContainerActor> 28 16 //arrHardMeldSpawnPoints = GetSpawnPoints(8) // get player start 0F 00 <.arrHardMeldSpawnPoints> 1B <GetSpawnPoints> 24 08 4A 16 /* <!DebugLog> 70 1F <%t "player_location_x: "> 38 55 35 <Core.Object.Vector.X> <Core.Object.Vector> 00 00 19 10 26 00 <.arrHardMeldSpawnPoints> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> 16 16 <!DebugLog> 70 1F <%t "player_location_y: "> 38 55 35 <Core.Object.Vector.Y> <Core.Object.Vector> 00 00 19 10 26 00 <.arrHardMeldSpawnPoints> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> 16 16 <!DebugLog> 70 1F <%t "player_location_z: "> 38 55 35 <Core.Object.Vector.Z> <Core.Object.Vector> 00 00 19 10 26 00 <.arrHardMeldSpawnPoints> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> 16 16 */ //A = 0 0F 00 <.A> 2C 00 [#loop1] 07 [@loop1end] 96 00 <.A> 2C 02 16 //arrEasyMeldSpawnPoints = World.FindClosestValidLocation(World.GetPositionFromTileCoordinates(Rand(numX), Rand(numY), Rand(numZ)), false, false, false); 0F 00 <.arrEasyMeldSpawnPoints> 19 <!World> <%s140> <XComWorldData.FindClosestValidLocation.ReturnValue> 00 1B <FindClosestValidLocation> 19 <!World> <%s106> <XComWorldData.GetPositionFromTileCoordinates.ReturnValue> 00 1B <GetPositionFromTileCoordinates> A7 <!numX> 16 A7 <!numY> 16 A7 <!numZ> 16 16 28 28 28 16 //kSpawnPoint = Spawn(class'XComMeldContainerSpawnPoint',,,arrEasyMeldSpawnPoints,,, true) 0F 00 <.kSpawnPoint> 1C <Engine.Actor.Spawn> 20 <Class.XComMeldContainerSpawnPoint> 4A 4A 00 <.arrEasyMeldSpawnPoints> 4A 4A 27 4A 16 //kSpawnPoint.m_iDestroyedOnTurn = int(VSize(kSpawnPoint.Location - PlayerLocation) / 768) // TileSize = 96, mobility = 8 tiles 0F 19 00 <.kSpawnPoint> 09 00 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 00 01 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 38 44 // cast float to int AC // / E1 // VSize D8 // - 19 00 <.kSpawnPoint> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> <!PlayerLocation> 16 // - end 16 // VSize end 1E <%f 768.0> 16 // / end /* <!DebugLog> 70 1F <%t "m_iDestroyedOnTurn: "> 38 53 19 00 <.kSpawnPoint> 09 00 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 00 01 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 16 16 */ //kSpawnPoint.m_iDestroyedOnTurn += 2 A1 19 00 <.kSpawnPoint> 09 00 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 00 01 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 2C 02 16 /* <!DebugLog> 70 1F <%t "m_iDestroyedOnTurn + 2: "> 38 53 19 00 <.kSpawnPoint> 09 00 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 00 01 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 16 16 */ //kMeldActor = Spawn(class'XComMeldContainerActor', self,, kSpawnPoint.Location,, kMeldActor_Arc) 0F 00 <.kMeldActor> 1C <Engine.Actor.Spawn> 20 <Class.XComMeldContainerActor> 17 4A 19 00 <.kSpawnPoint> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> 4A 00 <.kMeldActor_Arc> 4A 4A 16 //kMeldActor.InitFromSpawnPoint(kSpawnPoint) 19 00 <.kMeldActor> 13 00 <NullRef> 00 1B <InitFromSpawnPoint> 00 <.kSpawnPoint> 16 //++A A3 00 <.A> 16 //goto loop1 06 [@loop1] [#loop1end] //return 04 0B //EOS 53 Result: http://i.imgur.com/YEU3acz.jpg Again, meld placement is this code is completely random. m_iDestroyedOnTurn timer is calculated based on distance between the squad and current container. Meld placement could be enhanced by dividing map to, say, 4 sections and placing containers randomly inside those sections (as random pods code does with pods). Additional logic to create 'easy' and 'hard' containers could also be programmed in. And I can also disallow containers placement inside 30 methers radius near LZ (again, as random pods code does). Link to comment Share on other sites More sharing options...
XMarksTheSpot Posted August 19, 2014 Share Posted August 19, 2014 You mean drop ThinMen on the roofs only?I think some gradation w.r.t. difficulty by factoring in elevation, cover and proximity to overwatching XCOM troops would be cool. So, for instance, an 'easy' drop would happen smack in the middle of a bunch of overwatching units whereas a 'hard' drop would maybe place a thin man on some roof in cover and outside the immediate visual range of your units so they invariably will run into its overwatch fire.Maybe coding in some special cases for 'cheap tricks' could be fun, too, like dropping a thin man right next to an injured soldier so that overwatch fire killing the thin man would be poisoning that already injured soldier, a 'suicide drop' if you will. Might be a little frustrating though, most people probably won't appreciate aliens playing dirty like that :happy: It would be cool if the drop-in animations for sectoids, chryssalids and mutons from the Slingshot DLC could be used to have more variation in alien unit types dropping in, but as far as I understand those are tied to the map packages in some fashion, bummer. Link to comment Share on other sites More sharing options...
wghost81 Posted August 19, 2014 Author Share Posted August 19, 2014 (edited) It's theoretically possible to do such thing, but it will be very-very difficult to script. I was thinking more about randomness and unpredictability. In vanilla game Council missions are not fun at all, because they're 100% scripted: 1. VIP/bomb/assets positions are fixed. 2. Pods positions are fixed, patrolling disabled. 3. ThinMen are always dropped to the same positions. 4. Drop-downs are triggered by VIP movement. So, basically, you could leave VIP at the start point, clear the map and then move VIP and overwatch all the drop-downs. The idea is to make player really guard the VIP. I.e. if the player will try to leave VIP at some 'safe' location, VIP will be killed by patrols/drop-downs. With current mechanics I see three ways to achieve this goal: 1. Make pods on map patrol randomly (done). 2. Make ThinMen drop down to random locations (almost done). 3. Make drop-downs trigger not only by VIP, but by any other squad member too. If I could make 3 possible, I'll probably tie drop-down locations to VIP position. About 30-40 meters in random direction. If I couldn't make 3 possible, it might be better to drop ThinMen at completely random locations for less overall predictability. Or I could randomly pick one of the squad members (including VIP) and drop ThinMen nearby. Edited August 19, 2014 by wghost81 Link to comment Share on other sites More sharing options...
johnnylump Posted August 21, 2014 Share Posted August 21, 2014 WGhost, could I trouble you for the UE explorer tokens view of the function you modded for the alien drops? Looks like that plus two variable type changes would allow me to get this into Long War, yes? Link to comment Share on other sites More sharing options...
wghost81 Posted August 21, 2014 Author Share Posted August 21, 2014 Yes. I'll post UE Explorer code later, as I'm under Linux now. Random drop-downs mod is playable, but I won't recommend including random Meld mod right now. With placement being completely random Meld canisters often end up close together and too close to LZ. I'm working on improved canister placement algorithm right now and will release the code when it's done. Link to comment Share on other sites More sharing options...
johnnylump Posted August 21, 2014 Share Posted August 21, 2014 Thanks! Random drop-downs mod is playable, but I won't recommend including random Meld mod right now. With placement being completely random Meld canisters often end up close together and too close to LZ. I'm working on improved canister placement algorithm right now and will release the code when it's done. Roger that. We like the vanilla easy / hard placement functionality (and have varied up the number of canisters from 1 to 3), so we'd probably stick with that unless it's more or less duplicated by your mod, but I'll take a look at your code when it's ready. Thanks again! Link to comment Share on other sites More sharing options...
wghost81 Posted August 21, 2014 Author Share Posted August 21, 2014 Decompiled code event Activated() { local Vector SpawnObj; local XComWorldData ThisObj; local XComSpawnPoint_Alien SpawnPt; // End:0x11 if(!bEnabled) { return; } ThisObj = class'XComWorldData'.static.GetWorldData(); SpawnedUnit = none; OutputLinks[1].bHasImpulse = false; m_kDropIn = new class'XGAISpawnMethod_DropIn'; m_kDropIn.InitDropIn(iDropHeight, bUseOverwatch, bTriggerOverwatch, bPlaySound, bRevealSpawn, bSpawnImmediately, ForceAlienType, kAdditionalSound, self); SpawnObj = ThisObj.FindClosestValidLocation(ThisObj.GetPositionFromTileCoordinates(Rand(ThisObj.NumX), Rand(ThisObj.NumY), ThisObj.NumZ - 1), false, true, false); SpawnPt = Spawn(class'XComSpawnPoint_Alien',,, SpawnObj,,, true); m_kDropIn.AddSpawnPoint(SpawnPt); // End:0x219 if(bSpawnImmediately) { m_kDropIn.CheckContentLoaded(); } OutputLinks[0].bHasImpulse = true; ActivateOutputLink(0); //return; } Tokens: (000/000) [07 11 00 81 2D 01 D5 0E 00 00 16] JIN(15/11) -> NF(12/8) -> BV(10/6) -> IV(9/5) -> EFP(1/1) if(!bEnabled) (00F/00B) [04 0B] R(2/2) -> N(1/1) return (011/00D) [0F 00 D8 0E 00 00 12 20 2A 0C 00 00 0A 00 C8 D2 00 00 00 1B 47 3C 00 00 00 00 00 00 16] L(41/29) -> LV(9/5) -> CC(31/23) -> OC(9/5) -> VF(10/10) -> EFP(1/1) ThisObj = class'XComWorldData'.static.GetWorldData() (03A/02A) [0F 01 CD 0E 00 00 2A] L(11/7) -> IV(9/5) -> NO(1/1) SpawnedUnit = none (045/031) [14 2D 35 DD FE FF FF F0 F8 FF FF 00 01 10 26 01 D9 FF FF FF 28] LB(33/21) -> BV(31/19) -> SM(30/18) -> DAE(11/7) -> IO(1/1) -> IV(9/5) -> F(1/1) OutputLinks[1].bHasImpulse = false (066/046) [0F 01 CC 0E 00 00 11 0B 0B 0B 20 53 B0 00 00 0B] L(24/16) -> IV(9/5) -> N(14/10) -> N(1/1) -> N(1/1) -> N(1/1) -> OC(9/5) -> N(1/1) m_kDropIn = new class'XGAISpawnMethod_DropIn' (07E/056) [19 01 CC 0E 00 00 59 00 00 00 00 00 00 1B B8 41 00 00 00 00 00 00 01 CF 0E 00 00 2D 01 D4 0E 00 00 2D 01 D3 0E 00 00 2D 01 D2 0E 00 00 2D 01 D1 0E 00 00 2D 01 D0 0E 00 00 01 D6 0E 00 00 01 CE 0E 00 00 17 4A 16] C(110/70) -> IV(9/5) -> VF(89/57) -> IV(9/5) -> BV(10/6) -> IV(9/5) -> BV(10/6) -> IV(9/5) -> BV(10/6) -> IV(9/5) -> BV(10/6) -> IV(9/5) -> BV(10/6) -> IV(9/5) -> IV(9/5) -> IV(9/5) -> S(1/1) -> NP(1/1) -> EFP(1/1) m_kDropIn.InitDropIn(iDropHeight, bUseOverwatch, bTriggerOverwatch, bPlaySound, bRevealSpawn, bSpawnImmediately, ForceAlienType, kAdditionalSound, self) (0EC/09C) [0F 00 D9 0E 00 00 19 00 D8 0E 00 00 8D 00 AC D2 00 00 00 1B 29 33 00 00 00 00 00 00 19 00 D8 0E 00 00 6B 00 BC 0C 00 00 00 1B DD 3A 00 00 00 00 00 00 A7 19 00 D8 0E 00 00 09 00 30 0D 00 00 00 01 30 0D 00 00 16 A7 19 00 D8 0E 00 00 09 00 2F 0D 00 00 00 01 2F 0D 00 00 16 93 19 00 D8 0E 00 00 09 00 2E 0D 00 00 00 01 2E 0D 00 00 26 16 16 28 27 28 16] L(172/116) -> LV(9/5) -> C(162/110) -> LV(9/5) -> VF(141/97) -> C(128/84) -> LV(9/5) -> VF(107/71) -> NF(32/20) -> C(30/18) -> LV(9/5) -> IV(9/5) -> EFP(1/1) -> NF(32/20) -> C(30/18) -> LV(9/5) -> IV(9/5) -> EFP(1/1) -> NF(33/21) -> C(30/18) -> LV(9/5) -> IV(9/5) -> IO(1/1) -> EFP(1/1) -> EFP(1/1) -> F(1/1) -> T(1/1) -> F(1/1) -> EFP(1/1) SpawnObj = ThisObj.FindClosestValidLocation(ThisObj.GetPositionFromTileCoordinates(Rand(ThisObj.NumX), Rand(ThisObj.NumY), ThisObj.NumZ - 1), false, true, false) (198/110) [0F 00 D7 0E 00 00 1C 12 FC FF FF 20 17 79 00 00 4A 4A 00 D9 0E 00 00 4A 4A 27 4A 16] L(44/28) -> LV(9/5) -> FF(34/22) -> OC(9/5) -> NP(1/1) -> NP(1/1) -> LV(9/5) -> NP(1/1) -> NP(1/1) -> T(1/1) -> NP(1/1) -> EFP(1/1) SpawnPt = Spawn(class'XComSpawnPoint_Alien',,, SpawnObj,,, true) (1C4/12C) [19 01 CC 0E 00 00 14 00 00 00 00 00 00 1B AE 02 00 00 00 00 00 00 00 D7 0E 00 00 4A 16] C(41/29) -> IV(9/5) -> VF(20/16) -> LV(9/5) -> NP(1/1) -> EFP(1/1) m_kDropIn.AddSpawnPoint(SpawnPt) (1ED/149) [07 19 02 2D 01 D0 0E 00 00] JIN(13/9) -> BV(10/6) -> IV(9/5) if(bSpawnImmediately) (1FA/152) [19 01 CC 0E 00 00 0A 00 00 00 00 00 00 1B 59 12 00 00 00 00 00 00 16] C(31/23) -> IV(9/5) -> VF(10/10) -> EFP(1/1) m_kDropIn.CheckContentLoaded() (219/169) [14 2D 35 DD FE FF FF F0 F8 FF FF 00 01 10 25 01 D9 FF FF FF 27] LB(33/21) -> BV(31/19) -> SM(30/18) -> DAE(11/7) -> IZ(1/1) -> IV(9/5) -> T(1/1) OutputLinks[0].bHasImpulse = true (23A/17E) [1C 7A FA FF FF 25 16] FF(11/7) -> IZ(1/1) -> EFP(1/1) ActivateOutputLink(0) (245/185) [04 0B] R(2/2) -> N(1/1) return (247/187) [53] EOS(1/1) Link to comment Share on other sites More sharing options...
wghost81 Posted August 21, 2014 Author Share Posted August 21, 2014 I've changed Meld placement algorithm a bit and also tested it with reused maps: all seems to work fine. http://i.imgur.com/ZAlFuGr.jpg New algorithm (PatchUPK/PatcherGUI modfile): UPK_FILE=XComGame.upk // convert XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints.arrEasyMeldSpawnPoints to integer EXPORT_ENTRY=XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints.arrEasyMeldSpawnPoints [MODDED_CODE] <Core.IntProperty> // new TypeRef <NullRef> // ParentClassRef <XGBattle_SP.InitMeldContainers> // new OwnerRef <A> // new NameIdx <NullRef> // ArchetypeRef <%u 0x00000000> // ObjectFlagsH <%u 0x00070004> // ObjectFlagsL <%u 40> // new SerialSize // reset property flags for new var A and make it a static array OBJECT=XGBattle_SP.InitMeldContainers.A REL_OFFSET=16 [MODDED_CODE] <%s 3> // increase ArrayDim <%s 0> // ElementSize <%u 0> // set PropertyFlagsL to zero // convert XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints dynamic array to structure EXPORT_ENTRY=XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints MODDED_CODE=<Core.StructProperty> // new type // make arrEasyMeldSpawnPoints a static array of vector type OBJECT=XGBattle_SP.InitMeldContainers.arrEasyMeldSpawnPoints REL_OFFSET=16 [MODDED_CODE] <%s 5> // increase ArrayDim <%s 0> // ElementSize <%u 0> // set PropertyFlagsL to zero <%u 0> // PropertyFlagsH <None> // CategoryIndex <NullRef> // ArrayEnumRef <Core.Object.Vector> // new InnerObjRef // change inner type of arrHardMeldSpawnPoints array OBJECT=XGBattle_SP.InitMeldContainers.arrHardMeldSpawnPoints.arrHardMeldSpawnPoints REL_OFFSET=40 MODDED_CODE=<Class.XComSpawnPoint> // new type // link new var A to XGBattle_SP.InitMeldContainers OBJECT=XGBattle_SP.InitMeldContainers.kMeldActor_Arc REL_OFFSET=12 MODDED_CODE=<XGBattle_SP.InitMeldContainers.A> // NextRef OBJECT=XGBattle_SP.InitMeldContainers:AUTO ALIAS=World:12 20 <Class.XComWorldData> 0A 00 <XComWorldData.GetWorldData.ReturnValue> 00 1B <GetWorldData> 16 ALIAS=numX:19 <!World> 09 00 <XComWorldData.NumX> 00 01 <XComWorldData.NumX> ALIAS=numY:19 <!World> 09 00 <XComWorldData.NumY> 00 01 <XComWorldData.NumY> ALIAS=numZ:19 <!World> 09 00 <XComWorldData.NumZ> 00 01 <XComWorldData.NumZ> ALIAS=PlayerLocation:19 10 26 00 <.arrHardMeldSpawnPoints> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> //ALIAS=DebugLog:19 2E <Class.XComOnlineEventMgr> 19 2E <Engine.GameEngine> 12 20 <Engine.Engine> 0A 00 <Engine.Engine.GetEngine.ReturnValue> 00 1C <Engine.Engine.GetEngine> 16 09 00 <Engine.GameEngine.OnlineEventManager> 00 01 <Engine.GameEngine.OnlineEventManager> FF 00 <NullRef> 00 1B <DevOnlineMsg> ALIAS=MIN_DIST_LZ:1E <%f 1600> // 25 meters ALIAS=MIN_DIST_OTHER:1E <%f 1920> // 30 meters ALIAS=NUM_CONTAINERS:2C 02 ALIAS=ADD_TURNS:2C 02 // num additional turns until destroyed [REPLACEMENT_CODE] //kMeldActor_Arc = XComMeldContainerActor(DynamicLoadObject("MeldCanister_MOD.MeldCanister_ARC", class'XComMeldContainerActor', false)) 0F 00 <.kMeldActor_Arc> 2E <Class.XComMeldContainerActor> 1C <Core.Object.DynamicLoadObject> 1F <%t "MeldCanister_MOD.MeldCanister_ARC"> 20 <Class.XComMeldContainerActor> 28 16 //arrHardMeldSpawnPoints = GetSpawnPoints(8) // get player start 0F 00 <.arrHardMeldSpawnPoints> 1B <GetSpawnPoints> 24 08 4A 16 /* <!DebugLog> 70 1F <%t "player_location_x: "> 38 55 35 <Core.Object.Vector.X> <Core.Object.Vector> 00 00 19 10 26 00 <.arrHardMeldSpawnPoints> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> 16 16 <!DebugLog> 70 1F <%t "player_location_y: "> 38 55 35 <Core.Object.Vector.Y> <Core.Object.Vector> 00 00 19 10 26 00 <.arrHardMeldSpawnPoints> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> 16 16 <!DebugLog> 70 1F <%t "player_location_z: "> 38 55 35 <Core.Object.Vector.Z> <Core.Object.Vector> 00 00 19 10 26 00 <.arrHardMeldSpawnPoints> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> 16 16 */ //find good spawn points //A[0] = 0 0F 1A 25 00 <.A> 25 [#loop1] //if (A[0] < NUM_CONTAINERS) 07 [@loop1end] 96 1A 25 00 <.A> <!NUM_CONTAINERS> 16 //A[1] = 0 0F 1A 26 00 <.A> 25 [#loop3] //if (A[1] < 100) 07 [@loop3end] 96 1A 26 00 <.A> 2C <%b 100> 16 //arrEasyMeldSpawnPoints[0] = World.FindClosestValidLocation(World.GetPositionFromTileCoordinates(Rand(numX), Rand(numY), Rand(numZ)), false, false, false); 0F 1A 25 00 <.arrEasyMeldSpawnPoints> 19 <!World> <%s140> <XComWorldData.FindClosestValidLocation.ReturnValue> 00 1B <FindClosestValidLocation> 19 <!World> <%s106> <XComWorldData.GetPositionFromTileCoordinates.ReturnValue> 00 1B <GetPositionFromTileCoordinates> A7 <!numX> 16 A7 <!numY> 16 A7 <!numZ> 16 16 28 28 28 16 //if (VSize(arrEasyMeldSpawnPoints[0] - PlayerLocation) < MIN_DIST_LZ) 07 [@check1] B0 E1 D8 1A 25 00 <.arrEasyMeldSpawnPoints> <!PlayerLocation> 16 16 <!MIN_DIST_LZ> 16 //goto loop3 06 [@loop3] [#check1] //A[2] = 1 0F 1A 2C 02 00 <.A> 26 [#loop4] //if (A[2] <= A[0]) 07 [@loop3end] 98 1A 2C 02 00 <.A> 1A 25 00 <.A> 16 //if (VSize(arrEasyMeldSpawnPoints[0] - arrEasyMeldSpawnPoints[A[2]]) < MIN_DIST_OTHER) 07 [@check2] B0 E1 D8 1A 25 00 <.arrEasyMeldSpawnPoints> 1A 1A 2C 02 00 <.A> 00 <.arrEasyMeldSpawnPoints> 16 16 <!MIN_DIST_OTHER> 16 //goto loop3 06 [@loop3] [#check2] //++A[2] A3 1A 2C 02 00 <.A> 16 //goto loop4 06 [@loop4] [#loop3end] //arrEasyMeldSpawnPoints[A[0] + 1] = arrEasyMeldSpawnPoints[0] 0F 1A 92 1A 25 00 <.A> 26 16 00 <.arrEasyMeldSpawnPoints> 1A 25 00 <.arrEasyMeldSpawnPoints> //++A[0] A3 1A 25 00 <.A> 16 //goto loop1 06 [@loop1] [#loop1end] //A[0] = 0 0F 1A 25 00 <.A> 25 [#loop2] //if (A[0] < NUM_CONTAINERS) 07 [@loop2end] 96 1A 25 00 <.A> <!NUM_CONTAINERS> 16 //kSpawnPoint = Spawn(class'XComMeldContainerSpawnPoint',,,arrEasyMeldSpawnPoints[A[0] + 1],,, true) 0F 00 <.kSpawnPoint> 1C <Engine.Actor.Spawn> 20 <Class.XComMeldContainerSpawnPoint> 4A 4A 1A 92 1A 25 00 <.A> 26 16 00 <.arrEasyMeldSpawnPoints> 4A 4A 27 4A 16 //kSpawnPoint.m_iDestroyedOnTurn = int(VSize(kSpawnPoint.Location - PlayerLocation) / 768) // TileSize = 96, mobility = 8 tiles 0F 19 00 <.kSpawnPoint> 09 00 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 00 01 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 38 44 // cast float to int AC // / E1 // VSize D8 // - 19 00 <.kSpawnPoint> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> <!PlayerLocation> 16 // - end 16 // VSize end 1E <%f 768.0> 16 // / end /* <!DebugLog> 70 1F <%t "m_iDestroyedOnTurn: "> 38 53 19 00 <.kSpawnPoint> 09 00 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 00 01 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 16 16 */ //kSpawnPoint.m_iDestroyedOnTurn += ADD_TURNS A1 19 00 <.kSpawnPoint> 09 00 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 00 01 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> <!ADD_TURNS> 16 /* <!DebugLog> 70 1F <%t "m_iDestroyedOnTurn + 2: "> 38 53 19 00 <.kSpawnPoint> 09 00 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 00 01 <XComMeldContainerSpawnPoint.m_iDestroyedOnTurn> 16 16 */ //kMeldActor = Spawn(class'XComMeldContainerActor', self,, kSpawnPoint.Location,, kMeldActor_Arc) 0F 00 <.kMeldActor> 1C <Engine.Actor.Spawn> 20 <Class.XComMeldContainerActor> 17 4A 19 00 <.kSpawnPoint> 09 00 <Engine.Actor.Location> 00 01 <Engine.Actor.Location> 4A 00 <.kMeldActor_Arc> 4A 4A 16 //kMeldActor.InitFromSpawnPoint(kSpawnPoint) 19 00 <.kMeldActor> 13 00 <NullRef> 00 1B <InitFromSpawnPoint> 00 <.kSpawnPoint> 16 //++A[0] A3 1A 25 00 <.A> 16 //goto loop2 06 [@loop2] [#loop2end] //return 04 0B //EOS 53 This part of the code ALIAS=MIN_DIST_LZ:1E <%f 1600> // 25 meters ALIAS=MIN_DIST_OTHER:1E <%f 1920> // 30 meters ALIAS=NUM_CONTAINERS:2C 02 ALIAS=ADD_TURNS:2C 02 // num additional turns until destroyed is adjustable. MIN_DIST_LZ sets minimum distance from landing zone and MIN_DIST_OTHER sets minimum distance from the other canisters. NUM_CONTAINERS sets number of Meld canisters and can vary between 1 and 4 (if you want more, you'll need to increase ArrayDim for arrEasyMeldSpawnPoints, but that much Meld is crazy :smile: ). ADD_TURNS sets number of additional turns for timer. Random placement sure adds something new to Meld tactics, as in lot of the cases you'll get two canisters on opposite map corners. In vanilla game you can always collect both canisters along the way, it's the matter of moving and killing everything quickly. But with randomness it might not be possible. I'm still working on improving placement algorithm. One thing I noticed: linear dependency between timer and distance to LZ is not good. The further Meld canister is, the more additional turns it needs, because squad will engage enemies and won't be able to move quickly. It needs additional in-game testing, but I'm thinking about changing linear dependency to, say, quadratic. And yes, THAT map (Highway1) can have Meld spawned on THAT roof. :smile: I really-really hate that map. I really do. johnnylump, if you like the idea of easy-hard-very hard three-canisters setup for LW, I can try to script it. I have some ideas of my own, like using three probabilities to determine if particular (easy, hard, very hard) canister will be spawned and spawning those canisters with random distance and angle. Distance restrictions will be set by canister difficultly, distance variation, LZ and other canister proximity. Angle can be completely random, or we can set some restriction, to create vanilla-like placement (I'm not sure I can do this, but it's worth a try anyway). Link to comment Share on other sites More sharing options...
johnnylump Posted August 22, 2014 Share Posted August 22, 2014 WGhost, Thanks much for the tokens. On meld cans, I'll actually defer to Amineri for what's best for Long War ... she designed what variety in canisters we have, so she should probably ring in on how we'd want to mix things up. She's taking a break right now but I'm sure she'll post here when she's back. Link to comment Share on other sites More sharing options...
wghost81 Posted August 23, 2014 Author Share Posted August 23, 2014 Regarding Highway1 map. Here are two examples of "Show VOLUMES" console command. Simple square map UPB_Bar: http://i.imgur.com/kX8L9TR.jpg Highway1 map: http://i.imgur.com/jdpdHfk.jpg Magenta color lines show the volumes we're looking for. It should be map object and it should be a volume. But I can't find it. :sad: If we could find this object (or group of objects), we could simply add another check: if spawn point is inside this volume. But, since I can't find it, I will add another check: if map is Highway1 and x coord < 40 and y coord > 900, do not spawn anything there. Link to comment Share on other sites More sharing options...
Recommended Posts