|
 |
| Author |
Message |
|
kirahirasai
|
Posted: 04 Jan, 2011
|
|
Joined: 30 Dec, 2010 Posts: 49 Location: Germany
|
Thanks. I try to get it working ingame today, but I will only add the bones and get it ingame. You will receive the scd file and the animation file. So building effects, scaling, effects in general and the code-side of your mod will be your job. Good luck with the project  . Of course I will keep an eye on the hot topic and if there is something, PM me or write in this thread  . Regards, Kira
_________________ the signature is currently not available...
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 04 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
|
Sounds like a plan. Send it to myname at gmail. We will look at the code with an angryface until it does what we want it to. Then we'll have our first new model. I'm so excited. On an unrelated note. I checked out your website and the videos of the fusion and sun bomb are shiney. If I recall correctly there was someone else who was making new nuke effects. I think it was the blackops guys but I could be wrong. You might look into working with them or possibly bouncing ideas off of them if you get stuck.
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
kirahirasai
|
Posted: 04 Jan, 2011
|
|
Joined: 30 Dec, 2010 Posts: 49 Location: Germany
|
got my pc first working now XD. 4 hours work. So I will work today on the issue, of getting it ingame. I will send the file, when I´m done. @homepage: I will think about that offer, but for now I´m messing with the effects files and nuke structure itself. I will see, where the whole idea will go. I will see, what I can do with the effects and I have some unique ideas, which could interest the community itself. But that´s a secret Edit: Model doesn´t work. It won´t be displayed correctly ingame, tried to rescue the model but it was hopeless. Only god knows, what I messed up and there were many things very wrong. I did make a new one, though. Hope you like it. And I tested it, it works ingame just splendid. You´ve got a pm with the pic. If anyone else is interested in getting the image, write me a pm. Over and out, Kira
_________________ the signature is currently not available...
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 10 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
|
So I got the model from Kira yesterday. We've gotten the spinning working for the gravity plates. I have sent a request to Kirvesnama to allow me to use his lightning effects hopefully that will be a yes. But I am running into a wall and hope that someone has an idea. Is there a way that I can apply an effect that would take the spires coming from a model and move them in and out based on the shieldhp of the shield generator that they are adjacent to. Similar to how mass and energy storage rise and fall based on available resources?
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
Mithy
|
Posted: 10 Jan, 2011
|
|
Joined: 19 Jul, 2009 Posts: 2972
|
|
Yes, that would be fairly simple. Make sure the model has bones defined for animating the parts you want, set up a slider animator for them in OnStopBeingBuilt, and kick off a looping thread with a ~1s interval that checks Sync.ShieldRatio on all adjacent structures (plural, you'll have to average for multiple adjacent shields) and sets the position of the slider accordingly. Look at how the storage units do their animators - everything will be the same except how it gets its data. You could also use this to start, stop, or alter emitters on the unit.
You'd probably have to hook OnAdjacentTo and OnNotAdjacentTo to maintain a table of adjacent structures, similar to what Fury mentioned previously (although since this would only be needed for effects and not adjacency functionality, it could be done non-destructively).
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 11 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
Ok. so I have been poking at this for a couple of days now. I am out of ideas. Oh great code gods. Please help me out here. I'm trying to take Mithy's advice but my limited understanding of LUA is fighting me here. Here's what I have so far. This is the script for the new model that I have gotten from Kira. Before I added the table and all the onadjacent stuff at the bottom. It would spin properly and I had the ambient effect directly under oncreate and it was working. Presently I am trying to get it to decide that it is adjacent to a shield generator and display some sparkely above the capacitor so I know the code's working. Then I will try to have the spires move in and out based on the shieldhp of the adjacent shield that should already know about. I have been looking at some of the stuff Gilbot did trying to figure this out. In addition to looking at the work of Lakitrid. I have got to be making some dumb mistakes here. Code: local TEnergyCreationUnit = import('/lua/terranunits.lua').TEnergyCreationUnit XSB1187 = Class(import('/lua/seraphimunits.lua').SEnergyCreationUnit) { OnCreate = function(self) self.adjacencytable = {} TEnergyCreationUnit.OnCreate(self) self.Spinners = { Spinner1 = CreateRotator(self, 'gravityplate', 'y', nil, 0, 30, 360):SetTargetSpeed(50), Spinner2 = CreateRotator(self, 'gravityplate2', 'y', nil, 0, 30, 360):SetTargetSpeed(80), Spinner3 = CreateRotator(self, 'gravityplate3', 'y', nil, 0, 30, 360):SetTargetSpeed(50), Spinner4 = CreateRotator(self, 'gravityplate4', 'y', nil, 0, 30, 360):SetTargetSpeed(80), } self.Sliders = { Slider1 = CreateSlider(self, 'left_energy_storage'), Slider2 = CreateSlider(self, 'right_energy_storage'), Slider3 = CreateSlider(self, 'top_energy_storage'), Slider4 = CreateSlider(self, 'bottom_energy_storage'), Slider5 = CreateSlider(self, 'front_energy_storage'), Slider6 = CreateSlider(self, 'back_energy_storage'), } for k, v in self.Spinners do self.Trash:Add(v) end, #Add Adjacent units to a table. #Is it done being built? OnAdjacentTo = function(self, adjacentUnit, triggerUnit) if self:IsBeingBuilt() then return end if adjacentUnit:IsBeingBuilt() then return end #Add it to the table. table.insert(self.adjacencytable, adjacentUnit) end, OnNotAdjacentTo = function(self, adjacentUnit) if self.remove then table.remove(self.adjacencytable, i) end #Is the unit destroyed? OnKilled runs after this. So we need to make sure it's dead. if self:GetHealth() <= 0 then self.remove = true end end, #If you're a shield generator then you should be adjacent and friendly right? if self.EntityCategoryContains(categories.STRUCTURE, unit) and adjacentUnit.EntityCategoryContains(categories.SHIELD, unit) then #How far around do we want to look? local radius = 5 local adjacentUnitsnow = self:GetFriendlyUnitsInSphere(radius) for kUnit,vUnit in adjacentUnitsnow do if self ~= vUnit and vUnit.EntityCategoryContains(categories.STRUCTURE, unit) and vUnit.EntityCategoryContains(categories.SHIELD, unit) and not self.AlreadyCalledOnAdjacentTo then self:OnAdjacentTo(vUnit) vUnit:OnAdjacentTo(self) end end end, #Now that it's been declared as adjacent, make some sparkles above it. if vUnit=OnAdjacentTo then AmbientEffects = 'ST2PowerAmbient', end,
} TypeClass = XSB1187
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
Mithy
|
Posted: 11 Jan, 2011
|
|
Joined: 19 Jul, 2009 Posts: 2972
|
I assume you're getting a bunch of log errors? First off, you're running functions from a class (TEnergyCreationUnit) other than the one you're inheriting from (SEnergyCreationUnit). Is there a particular reason for that? If not, that could be causing problems. Second, the class you're inheriting from doesn't have a local var defined so you can run its functions at all. If this were a simple class that didn't need to redefine anything, the way you're inheriting directly from an import would be fine, but when you need to redefine functions within your class, you want to import the inherited class to a local var so you can reference it within the functions in your class as well as in the inheritance itself. Third, your OnAdjacentTo is hard-overwriting the one from StructureUnit, as you're not calling (or able to call, with the way you have it set up) SEnergyCreationUnit.OnAdjacentTo from within yours. So the original StructureUnit OnAdjacentTo (which is inherited by SEnergyCreationUnit and subsequently your unit's class, until being overridden) is never being run, and your unit probably won't have functioning adjacency. I have noooo idea what your OnNotAdjacentTo is doing. Is that code ripped from Gilbot's area adjacency mod? Because that is definitely not anything you need to do simple table maintenance. The way you're trying to remove the un-adjacent unit's ref from the table is not going to work, either. I can only assume you're copying something from another mod there? This is more or less what the functions should look like: Code: OnAdjacentTo = function(self, adjacentUnit) SEnergyCreationUnit.OnAdjacentTo(self, adjacentUnit, triggerUnit) if EntityCategoryContains(categories.SHIELD, adjacentUnit) then self.adjacencytable[adjacentUnit:GetEntityId()] = adjacentUnit self:DoAdjacencyEffects() end end,
OnNotAdjacentTo = function(self, adjacentUnit) SEnergyCreationUnit.OnNotAdjacentTo(self, adjacentUnit) if EntityCategoryContains(categories.SHIELD, adjacentUnit) then self.adjacencytable[adjacentUnit:GetEntityId()] = nil self:DoAdjacencyEffects(true) end end,
DoAdjacencyEffects = function(self, remove) local numAdjUnits = table.getsize(self.adjacencytable) if not remove and numAdjUnits > 0 then --Add effects here elseif remove then --Remove effects here end end, This gives you a nice neat table containing only adjacent shield units, with no duplicates and no insert/remove ambiguity. It also assumes you have created an SEnergyCreationUnit var that imports SEnergyCreationUnit from seraphimunits.lua, obviously. Note how it's using a second function that counts the number of table entries to determine how many / whether or not shield units are adjacent and handles effects accordingly. This is definitely the easiest and surest way to handle that, since it updates any time adjacency changes. The sliders will require a running loop on the unit that also uses the table to set its values, but you need this basic framework functioning before you can start on that. Edit: That DoAdjacencyEffects function is kind of an oversimplification - I don't know if you want to vary the amount or type of effects based on how many shields are adjacent, or if you just want effects on when anything is adjacent, and off when nothing is. If the latter, you'll have to change the logic of it a bit so it never adds if the table is > 1, and only removes if < 1.
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 11 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
Surprisingly there was only one log error. And it didn't help at all. I am running the TEnergyCreationUnit because that was the only way I could get the spinners to work. Ok so when I am importing the TEnergyCreationUnit I should import it to a local var like so? Code: local seraphimcreation = (import('/lua/seraphimunits.lua').SEnergyCreationUnit) Then I should change the OnAdjacentTo to seraphimcreation.OnAdjacentTo right since I need to define the local variable which I just did above? Wait I see at the bottom of your bost that seraphimcreation should be SEnergyCreationUnit based on the code you offered. The OnNotAdjacentTo was originally pulled from defaultunits.lua, but after looking at how Gilbot and Lakitrid were doing it I saw fit to try and make it work with tables. The only thing that came directly from I believe it was Lakitrid's pipelines. And that was to remove it from the table if it had been added previously based on whether or not it was dead. With the code that you have offered I wouldn't I need to have the DoAdjacencyEffects before the OnAdjacentTo? Otherwise it will be lookign for a function that hasn't been defined yet? Unless it parses the entire thing before running it. Also, with the GetEntityID() that would apply to the unitID correct? Wouldn't it be better to have it only count the total number of shield structures that are adjacent? That way I wouldn't have to tell it what to do for each unitID? Wait, I see, it's merely a counter that is counting if a unit is a shield and adding 1 to the table each time. I really appreciate all the help. I am not trying to rip off other developers or pilfer their code. I am trying to see how things are setup similarly and adapt it for use with the capacitors where it applies. Don't want to step on any toes here. Thanks again Mithy. Edit: So I have been poking at this script for about eight hours now and it's still not quite right. Everything runs (no errors)when I remove the commas from end, when declaring the functions. For example in the script that Mithy just displayed. While keeping the end, after OnCreate and OnStopBeingBuilt. However with the commas removed it doesn't seem like it's running OnAdjacentTo or the others. I have tried consulting books, searching, and done tons of research but a simple answer would be awesome. What does the comma after end do and why do I need it?
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
Mithy
|
Posted: 12 Jan, 2011
|
|
Joined: 19 Jul, 2009 Posts: 2972
|
zinetwin wrote: I am running the TEnergyCreationUnit because that was the only way I could get the spinners to work. TEnergyCreationUnit does absolutely nothing that SEnergyCreationUnit doesn't also do, because it adds nothing from the basic EnergyCreationUnit. In fact, SEnergyCreationUnit has some shortcuts for adding ambient effects to the unit - from seraphimunits.lua: Code: SEnergyCreationUnit = Class(EnergyCreationUnit) {
OnCreate = function(self) EnergyCreationUnit.OnCreate(self) self.NumUsedAdjacentUnits = 0 end,
OnStopBeingBuilt = function(self,builder,layer) EnergyCreationUnit.OnStopBeingBuilt(self, builder, layer) local army = self:GetArmy() if self.AmbientEffects then for k, v in EffectTemplate[self.AmbientEffects] do CreateAttachedEmitter(self, 0, army, v) end end end, } So if you wanted some basic emitters on the unit, you would only need to add their blueprintid strings to a self.AmbientEffects table within the class. I have no idea what the self.NumUsedAdjacentUnits is - probably something vestigial, since it's never incremented or used elsewhere. zinetwin wrote: Ok so when I am importing the TEnergyCreationUnit I should import it to a local var like so? Yep, and it doesn't matter what you call it so long as you refer to it by that inside the functions, and don't declare another var with that name inside the functions you need to use it in. zinetwin wrote: With the code that you have offered I wouldn't I need to have the DoAdjacencyEffects before the OnAdjacentTo? Otherwise it will be lookign for a function that hasn't been defined yet? Unless it parses the entire thing before running it. As you guessed, the order doesn't matter - the whole file is parsed, the class is created, and the functions are all declared at that point, with none of them actually being run until an instance of the unit has been created. zinetwin wrote: Also, with the GetEntityID() that would apply to the unitID correct? Wouldn't it be better to have it only count the total number of shield structures that are adjacent? That way I wouldn't have to tell it what to do for each unitID? Wait, I see, it's merely a counter that is counting if a unit is a shield and adding 1 to the table each time. EntityIds are unique for each entity/unit in the game, and won't be re-used when a unit is destroyed - so it's a safe way to key a table where you want one unique entry per unit. If you're wondering what they look like, they're just numbers starting from 1. So it will look like a numerically keyed table, but it really isn't as it will have lots of gaps, so we have to use table.getsize (which manually iterates and counts) instead of table.getn, which just looks at the numbers of the keys. The purpose of the table is both to count and to get handles to those units, so when you go to do the sliders, you have a means to actually check the shield ratios of your adjacent shield units. I know of no built-in way to get a list of adjacent units; there's certainly nothing in the lua. So when you go to update your sliders based on the average shield percentage of adjacent shield units, you would get the number of units in the table with getsize, then iterate that table and add each unit's Sync.ShieldRatio together, dividing it by the total number. Without that table, you'd have no way to get the shieldratio of any adjacent units, and you'd have to rely on radius-based checks that might detect shield units that aren't actually adjacent. zinetwin wrote: Edit: So I have been poking at this script for about eight hours now and it's still not quite right. Everything runs (no errors)when I remove the commas from end, when declaring the functions. For example in the script that Mithy just displayed. While keeping the end, after OnCreate and OnStopBeingBuilt. However with the commas removed it doesn't seem like it's running OnAdjacentTo or the others. I have tried consulting books, searching, and done tons of research but a simple answer would be awesome. What does the comma after end do and why do I need it? That's.. not good! The comma after end is needed because those functions should be going inside your class table, and elements within a table need to be separated by commas or you'll get a parse error and the whole script will be thrown out. Which means that you're probably putting those functions somewhere else, like inside another function? Make sure they're inside the brackets {} of the class table, but outside any other function declarations. Feel free to pastebin the whole script if you're having trouble.
|
|
| Top |
|
 |
|
Mithy
|
Posted: 12 Jan, 2011
|
|
Joined: 19 Jul, 2009 Posts: 2972
|
|
Also, I just took a look at the existing storage sliders, and it's all basically handled by the engine with CreateStorageManipulator. So yours won't be updating quite as often, and won't look as smooth (especially when a shield jumps back online), but it can still be done. It might be possible to interpolate their movement a bit - we'll see.
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 12 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
Yeah, when you said to see how the existing storage units were doing it. I chased that down to about 15 different scripts and still came up with nothing. Ok, so the commas are only necessary when in the class table. That explains alot. Presently I have the adjacentTo functions under OnStopBeingBuilt. Was hoping that they would only run after finishing being built. but OnStopBeingBuilt is still under the class table. Unless the adjacentTo functions should not be under any function at all bust stuck within the class function just like AmbientEffects would be. I will give the other suggestions a try later this evening. Mithy you sir are a scholar and a gentleman. I may have to send you an e-sammich for your assistance. I hope you like.....  BACON! Edit: with the information you gave. I have gotten it working. Seems just like I had things in the wrong places. for instance the onadjacentto was under onstopbeingbuilt. So I moved them out into the main class. Added onstartbuild and removed the local declaration of army. Works like a champ now. To show off the test effect working have a screenshot. Also Kira is doing some reworking on the specmap and a few other things for the model. 
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 12 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
|
Next question. Are there certain types of effects? For instance I can call several ambient effects just fine. But when I try say projectile effects I get these type of errors. Even though the path hasn't changed. WARNING: Failed to create emitter as you passed in an invalid blueprint name /effects/emitters/seraphim_thunderstorm_artillery_projectile_trail_01_emit.bp. WARNING: Failed to create emitter as you passed in an invalid blueprint name /effects/emitters/default_polytrail_01_emit.bp. Thoughts?
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
Mithy
|
Posted: 12 Jan, 2011
|
|
Joined: 19 Jul, 2009 Posts: 2972
|
Yeah, those On/NotAdjacentTo functions need to be global functions on the unit, as they're called by the engine each time a new structure is (or is no longer) adjacent to the unit, including when the unit itself is first placed. But you figured that out eventually. And yes, certain types of emitters only work with certain emitter calls. CreateAttachedEmitter only takes normal particle emitters, and not trail emitters. There are separate engine functions for attaching trail emitters (CreateEmitterOnEntity should work), but the trail emitters may not behave as you expect on a stationary structure. Looking through sim/defaultprojectiles.lua should give a few examples of which CreateEmitter functions can handle which emitter types. There's no global list that clearly states this anywhere, but you can find a list of all of the emitter functions (along with all other engine functions) and their parameters in the luadoc: http://supcom.wikia.com/wiki/LUADOC_1.5.3599There's just little or no explanation there of how they're different, or for that matter, what half of these engine functions do.
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 12 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
|
Thank you sir. With that I should be able to get it all squared away.
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
kirahirasai
|
Posted: 13 Jan, 2011
|
|
Joined: 30 Dec, 2010 Posts: 49 Location: Germany
|
I have done every possible texture combination and so on. It was hell, because it didn´t work, as I wanted it to. But I´ve cracked the nut. @Zinet: You have a mail, sir. First I was  then I was  after that I was  and then finally Screen:  Regards, Kira
_________________ the signature is currently not available...
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 13 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
|
Awesome. Got it in game already and have everything working except for the lightning and the sliders to reference shieldhp. Shouldn't be long though. Thanks for the great work.
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
kirahirasai
|
Posted: 13 Jan, 2011
|
|
Joined: 30 Dec, 2010 Posts: 49 Location: Germany
|
no problem  . I´m glad I solved the problem 
_________________ the signature is currently not available...
|
|
| Top |
|
 |
|
Zataku
|
Posted: 13 Jan, 2011
|
|
Joined: 04 Jan, 2010 Posts: 383
|
|
0_0 Holy crap that's alot of bacon.
You're a loose cannon, sandwich, but you're a damn good cop! lol.
_________________ "We have intelligence, we have a sense of purpose, we have the element of surprise. so, what does Brackman have?" "... He has an 80 foot Tarantula"
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 14 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
You can never have enough bacon. It's only when you start weaving your bacon together that you have a real problem. http://www.bbqaddicts.com/blog/recipes/bacon-explosion/Maybe the sharp cheddar dip is a bit much. One of these days I'mma make me one of those.
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 14 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
Ok I am working on getting the Sync.ShieldRatio to work. Which I assume is a function I call to look at the table. Presently I just want it to display a different effect if the shieldratio is 100% so that I can know the script is working. Presently it's not. Of course. Everything else is working. It's just the checkshields function that isn't doing properly. What am I doing wrong? I'm sure it's yet another beginner mistake. Code: #Make the sliders move according to relative shieldhp. checkshields = function(self) if self.adjacencytable[adjacentUnit:Sync.ShieldRatio()] = 100 then for k, v in EffectTemplates.ST3PowerAmbient do CreateAttachedEmitter(self, 'top_energy_storage', self:GetArmy(), v) end end end, #If it's adjacent to something do this OnAdjacentTo = function(self, adjacentUnit, triggerUnit) SEnergyCreationUnit.OnAdjacentTo(self, adjacentUnit, triggerUnit) if EntityCategoryContains(categories.SHIELD, adjacentUnit) then self.adjacencytable[adjacentUnit:GetEntityId()] = adjacentUnit self:DoAdjacencyEffects() end end, #If it's not adjacent to something do this OnNotAdjacentTo = function(self, adjacentUnit) SEnergyCreationUnit.OnNotAdjacentTo(self, adjacentUnit) if EntityCategoryContains(categories.SHIELD, adjacentUnit) then self.adjacencytable[adjacentUnit:GetEntityId()] = nil self:DoAdjacencyEffects(true) end end, #Do what we want when something is adjacent DoAdjacencyEffects = function(self, remove) local numAdjUnits = table.getsize(self.adjacencytable) if not remove and numAdjUnits > 0 then self.checkshields(true) for k, v in EffectTemplates.ST2PowerAmbient do CreateAttachedEmitter(self, 'top_energy_storage', self:GetArmy(), v) end
elseif remove then end end,
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
Mithy
|
Posted: 14 Jan, 2011
|
|
Joined: 19 Jul, 2009 Posts: 2972
|
That's because Sync is a table on the unit, not a function. Also, there is no Sync.ShieldRatio - I was just pulling that from memory, and I was wrong. It looks like the engine handles shield ratio updating from sim->user on its own via a sim engine function called SetShieldRatio, rather than via the Sync table. So, to get a unit's online shield percentage, you have to check the actual health of its shield entity against its maxhealth. Something like: Code: local shieldRatio = unit.MyShield:GetHealth() / unit.MyShield:GetMaxHealth() This will give you a ratio of 0 to 1 of shield percentage. You'll want to make sure MyShield exists on the unit before doing this, of course, as not all shields will necessarily be set up using the automatic method that sets this handle to the unit's shield. Now, like I said, you can't just do shield effects in the adjacency functions, since those only run once each when a unit is built or destroyed next to the capacitor. It has to be in a running thread that checks periodically, since there isn't an update callback of any kind that we can use for this. Well, actually, there is, but it's a bit tricky, and would rely on a supporting hook of either Unit.lua or defaultunits.lua. I'll look into that and elaborate if I think it'll work. A few other things-- Your DoAdjacencyAffects is adding effects every time a structure is built adjacent to the capacitor, and never removing them. If you built a capacitor adjacent to four shield units, it would get effects added four times over. This is what I meant when I said the logic of that function that I provided was inadequate. You also need to make sure you're using an effects trashbag when you have effects that you want to be able to remove, otherwise they're permanent (except in the case of certain timed emitters that auto-remove). Also, your tabbing is kind of confusing. If you post code to the forums, make sure your tabs are four spaces instead of an actual tab, otherwise the code tag on the forums messes it all up. Most text editors will let you set the behavior of the tab key to use x number of spaces instead of a tab. Obviously you can use more than four spaces if you want, but the forums are fixed width, so more spaces equals greater likelihood of more code exceeding width and getting wrapped, which again makes it harder to read. Here's an untested example DoAdjacencyEffects that can remove the effects it adds: Code: DoAdjacencyEffects = function(self, remove) --Check for valid, living adjacent units, prune any dead ones local numAdjUnits = 0 for k, v in self.adjacencytable do if v and not v:IsDead() then numAdjUnits = numAdjUnits + 1 else self.adjacencytable[k] = nil end end --Handle effects if not remove and not self.AdjFX then self.AdjFX = {} for k, v in EffectTemplates.ST2PowerAmbient do local effect = CreateAttachedEmitter(self, 'top_energy_storage', self:GetArmy(), v) table.insert(self.AdjFX, effect) self.Trash:Add(effect) end elseif remove and numAdjUnits == 0 and self.AdjFX then for k, v in self.AdjFX do v:Destroy() end self.AdjFX = nil end end, Make sense? It only adds effects if they haven't already been added, and only removes them if they exist and there are no adjacent units left. It uses a table to store handles to the effects, for removal, and adds each effect to the unit's trash bag so they're properly removed on death. I also expanded on the unit count, so that it insures that no dead/destroyed shield units are being counted, and are being removed from the table. This should happen automatically, as OnNotAdjacentTo -should- be called whenever an adjacent unit is destroyed, but better safe than sorry. Now, I assume you probably don't know what I mean when I say to use a running thread to check adjacent units' shield ratios, so I'll run through that briefly - this should hopefully just be a stopgap method until I figure out a nice clean way to use callbacks to do this more efficiently and quickly: Code: OnStopBeingBuilt = function(self, builder, layer) SEnergyCreationUnit.OnStopBeingBuilt(self, builder, layer) self.ShieldCheckThread = self:ForkThread(self.ShieldCheck) end, ShieldCheck = function(self) --Loop while still alive while self and not self:IsDead() do local shieldRatio, shieldCount = 0, 0 for k, v in self.adjacencytable do if v and not v:IsDead() and v.MyShield then shieldCount = shieldCount + 1 --Only count shield's health if active if v.MyShield:IsOn() then shieldRatio = shieldRatio + ( v.MyShield:GetHealth() / v.MyShield:GetMaxHealth() ) end else --Remove unit reference if dead or no shield handle self.adjacencytable[k] = nil end end shieldRatio = shieldRatio / math.max(shieldCount, 1) --Handle shield effects, placeholder if shieldRatio == 1 and not self.ShieldFX then self.ShieldFX = {} for k, v in EffectTemplates.ST3PowerAmbient do local effect = CreateAttachedEmitter(self, 'top_energy_storage', self:GetArmy(), v) table.insert(self.ShieldFX, effect) self.Trash:Add(effect) end elseif shieldRatio < 1 and self.ShieldFX then --Remove effects for k, v in self.ShieldFX do v:Destroy() end self.ShieldFX = nil end
WaitSeconds(1) end end, As before, these are all global functions - OnStopBeingBuilt is called by the engine after the unit is completed, and this one kicks off a looping thread that checks adjacent shield units' on status and hp ratio every second. If all adjacent shield units have full shields, it should create the emitter. If any of them aren't full, it should remove it. If there are no adjacent units, shieldRatio should be 0, and thus removal of effects should be handled automatically (if somehow a shield were destroyed that had full HP at the last check - pretty unlikely anyway). Edit: Whoops, I had a potential divide by zero in there. Fixed so it's the highest of 1 or the number.
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 14 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
|
Awesome. For the record. The effects in DoAdjacencyEffects were updating when the shield generator was built after the capacitors were built. In addition to the effects going away when the generator was removed. Couple of questions. First, what do k and v represent. It shows up everywhere and I don't have a clue. Especially in the for loops. With the example you gave wouldn't I then have to define what self.AdjFX (wait I see it now) as well as self.Trash? Or is that already done somewhere else in a function somewhere? Why are there two equal signs in: elseif remove and numAdjUnits == 0 and self.AdjFX ? In the future, when using this code I would have to assign a variable to each effect as you have done with effect and then add that to the table and the trashbag right? With this new information I will attempt at getting that working. Once I have this last bit on the go it's just matter of choosing and getting everything to look right. Which takes time and patience, but I have that. Unlike my coding ability, which I do not have.
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
|
Mithy
|
Posted: 14 Jan, 2011
|
|
Joined: 19 Jul, 2009 Posts: 2972
|
zinetwin wrote: Awesome. For the record. The effects in DoAdjacencyEffects were updating when the shield generator was built after the capacitors were built. In addition to the effects going away when the generator was removed. Huh. I don't think they should have been doing that, unless you changed something from the code that you posted. zinetwin wrote: Couple of questions. First, what do k and v represent. It shows up everywhere and I don't have a clue. Especially in the for loops. for loops that iterate tables need two variables: one to hold the key name/number of the current table element, and the other to hold the value. Thus, (k)key and (v)alue. This isn't anything hardcoded, just familiar shorthand. You could call them anything you want, and with nested loops, I use more specifically identifying variable names (like bp, bpid for the first loop in a Blueprints.lua hook, for example) so you can refer back to the key and value of a higher-level earlier loop as well as the current loop. zinetwin wrote: With the example you gave wouldn't I then have to define what self.AdjFX (wait I see it now) as well as self.Trash? Or is that already done somewhere else in a function somewhere? Nope, see how in the effects addition I first check whether or not the table exists? And then nil it out upon removal. It's just a temp holder table. Tables and variables defined on the unit (self in this case) don't have to be declared in any particular place, just so long as any code that uses them happens after they are in fact declared (except for existence checks, of course). Lua is really, really flexible with its global variable handling, which is extremely convenient, but a bit harder to understand than strict languages like C/C++. Also, Trash is a trash-bag table on every unit and entity in the game. It's automatically 'emptied' upon the unit's death, to insure that attached/associated objects, threads, effects, etc are properly destroyed. zinetwin wrote: Why are there two equal signs in: elseif remove and numAdjUnits == 0 and self.AdjFX ? Standard relational operator: http://www.lua.org/manual/5.0/manual.html#2.5.2It means that if the variable equals the value provided, it evaluates as true, thus passing the if <> then statement it's contained in (assuming there isn't an 'and' following it, along with other evaluations). One equals sign is always a value assignment, and if you omit one in this case, it'll give you an error that might not make much sense unless you're used to seeing them (and I suuuure am). zinetwin wrote: In the future, when using this code I would have to assign a variable to each effect as you have done with effect and then add that to the table and the trashbag right? More or less, yeah. In that case, it still iterates the EffectTemplates table you were doing before and assigns each emitter call a temp var just so it can be tabled/trashed. If you wanted to add another iteration of a table of effects, you could just duplicate that method (assuming it works, I just pulled it out of my *** from what I remember of effects creation and destruction). zinetwin wrote: With this new information I will attempt at getting that working. Once I have this last bit on the go it's just matter of choosing and getting everything to look right. Which takes time and patience, but I have that. Unlike my coding ability, which I do not have. Gotta start somewhere, right? A year and a half ago, I was about where you are, and I haven't actually done much productive modding in that time, so don't get discouraged.
|
|
| Top |
|
 |
|
Mithy
|
Posted: 14 Jan, 2011
|
|
Joined: 19 Jul, 2009 Posts: 2972
|
|
Ok, I've logically figured out a way to intercept SetShieldRatio calls to adjacent shield units. This means that you can make a slider on a capacitor unit update smoothly like the other storage units do, albeit with maybe a bit more CPU overhead than a 1 second loop check (but still pretty negligible as long as you don't have hundreds of them at once).
Once you get all the current stuff working I'll work out the actual code needed to do it.
|
|
| Top |
|
 |
|
zinetwin
|
Posted: 14 Jan, 2011
|
|
Joined: 31 Jul, 2010 Posts: 203
|
Mithy wrote: zinetwin wrote: Awesome. For the record. The effects in DoAdjacencyEffects were updating when the shield generator was built after the capacitors were built. In addition to the effects going away when the generator was removed. Huh. I don't think they should have been doing that, unless you changed something from the code that you posted. It totally was. Here's the full script for that unit. http://pastebin.com/tL327UzzI will get everything else working then report back. Thanks again. I very truly appreciate the time and effort you spend explaining things as well as the sample code.
_________________ “Hence to fight and conquer in all your battles is not supreme excellence; supreme excellence consists in breaking the enemy’s resistance without fighting.” Sun Tzu obviously didn't have giant robots to conquer with.
|
|
| Top |
|
 |
 |
 |
|