Jump to content

foamyesque

Members
  • Posts

    835
  • Joined

  • Last visited

Everything posted by foamyesque

  1. Actually, I am a bit embarrassed: There's a very simple answer that a number of vanilla things use. Put the merchant chest in an alias. Add whatever you want them to sell to the alias's inventory list. It will be preserved through resets until removed.
  2. Put it in a levelled list with a global variable controlling the ChanceNone, and then set that global via script, maybe?
  3. Oh, that's slick. Never occurred to me to try that. It works reliably? No timing / UI issues or anything?
  4. Cleanliness of operation on the player's end. The goal here is to provide the enchantment as seamlessly as possible. What you propose *is* a workaround, one which the OP points out as an option, even, but it doesn't really flow smoothly with the 'I am sealing this corrupting artifact away from the world' aim of the quest and would be mechanically clunky from the player's end.
  5. There are some particular quirks to movement speed that will require scripting to implement; SpeedMult changes, no matter how applied, do not take effect until either the character's gait changes (e.g., shifting into or out of a sprint) or their carryweight changes. Fastest and most reliable way is to add a short script that directly modifies the player's CarryWeight actor value up 1 and then down 1, whenever the ability starts or stops.
  6. This is essentially the correct answer. There is no way, via ordinary Papyrus scripting, to teach a player a specific enchantment. It's entirely done by the game engine. There might be some kind of workaround with inventory shell games and using an enchanting table as part of the sealing process you're setting up, though. Player activates the table, the default artifacts are swapped out for dummies you can disenchant; as soon as the table's closed, the original ones are added back to the player. Do some filtering to avoid swapping out artifacts that were already sealed. It's similar in concept to some scripts I provided here awhile back to allow someone to use food in an alchemy station.
  7. The key thing about a quest is that it can run scripts without needing to place any object into the game world and will do so regardless of what cell the player is in and what stuff may or may not be loaded, and can be set to trigger as soon as the game starts. For this reason they get used to manage a lot of things, completely disconnected from what you might consider an in-game quest. The aliases they provide -- which allow you to dynamically attach scripts to objects -- are also very useful. Since levelled lists can't talk to perks directly, you need to use a GlobalVariable to control the chance of them returning anything. For perk driven stuff this is usually a toggle, set to disable them (i.e 100% chance of nothing), that then gets flipped when the perk is added to the player. You can look at how the Imperial Luck or Golden Touch perks work for examples. Prowler's Profit is done in a more helter-skelter fashion but follows the same principle. You'll also need to insert your new levelled list into the existing one, via AddForm.
  8. Can you post the full and complete scripts you were trying to compile? Those errors being thrown suggest there is more code you're using than I provided: there's errors that say you're using states, errors that say your code is much longer, errors that say you're defining the property's get and set functions, etc.
  9. This particular one should not be difficult, no. scriptname tothExplosionEffect extends ActiveMagicEffect Spell Property ExplosionSpell Auto float Property fDelayTime = 3.0 Auto Actor target Actor caster Event OnEffectStart(Actor akTarget, Actor akCaster) RegisterForSingleUpdate(fDelayTime) target = akTarget caster = akCaster EndEvent Event OnUpdate() ExplosionSpell.Cast(caster, target) EndEvent Another possibility would be to set it to fire when the effect *ends*, which would let you use the standard potion durations (eg. how poisons work) to act as your timer. That one would be just this: scriptname tothExplosionEffect extends ActiveMagicEffect Spell Property ExplosionSpell Auto Event OnEffectFinish(Actor akTarget, Actor akCaster) ExplosionSpell.Cast(caster, target) EndEvent
  10. You may need to clone and modify it somewhat: Magic effects have types that have to match the spell, and potions and fireball have some distinctions (fireball is a fire & forget aimed spell; a potion is generally a fire & forget self one). The J'Zargo scroll explosion effect may be more like what you want. Adding in a delay is a little more tricky. There's a few approaches; the simplest to my mind would be some scripting on a magic effect in the potion to, instead of putting the explosion effect on the potion proper, simply cast a spell with the explosion you want after the timer runs out. You'd need a custom spell, with a magic effect to define the explosion, a custom potion with a magic effect that has a script attached, and a short script that, on the effect firing, registers for an update in, say, 3 seconds, and then on that update, fires the spell targeting the actor the effect is on.
  11. It already exists as one. Spells are made up of magic effects, and so are potion effects.
  12. If you're just using it once, in an initialization routine, that's fine. I do that sort of thing a lot, especially for scripts I'm going to make a lot of copies of (e.g. on aliases). Putting it in a loop is bad mojo: It won't ever change, so there's no need to keep checking it. Stuff it in a variable and access that. EDIT: If you need more specific advice, I'd suggest giving code samples.
  13. If it weren't for the framelinking there wouldn't be particularly noticeable differences, TBH. There's a bit of overhead in function calls just generally, but very, very few Papyrus scripts need to be optimized that tightly for performance. In most cases even Game.GetPlayer() would be fine, too. Performance issues really only start to come into play when you're doing either a lot of processing or have something that needs to happen with as little latency as possible; inventory manipulation is a common example of both.
  14. Hm. I'm not clear on what you're asking in the first question, but in the second, there's nothing wrong with a set of if-elseif statements. It can look kludgey but it's often much clearer about what you're trying to do than, say, trying to remember which array element is a Staff or a Bow or a Sword or whatever. Something I do occasionally do is pair arrays. For example, you could have an array of Keywords and an array of strings. You can then transform from one to the other based on the index of an element: Look up a Keyword's position in the Keyword array, then use that position to pull its name from the string array.
  15. The other big advantage of a formlist -- and it is a big one -- is that other game systems, most particularly the condition one, can talk to it. It's also by default dynamically sizable, whereas doing so with arrays requires SKSE or some very kludgey (and limited) code. EDIT: As in fact I see I said in the 2017 thread you linked, ReDragon :)
  16. No. I have no idea how you got that from my posts, all of which explicitly said arrays are faster than FormLists.
  17. How would the game handle FormList in your opinion? I think is a safe bet that it places them into Arrays. So by going directly to an Array you are cutting out the middle man. Or is some other way of doing it? Please enlighten me. How does the game deal with Formlist? Mate, seriously, no offense intended, but even a web-page is just a glorified array of data manipulation. I would suspect -- I haven't delved into the C code to know -- that the internal guts of FormLists are implemented as a linked list stack in the C code. The publicly accessible APIs suggest it: it isn't fixed-length (and can in fact be arbitrarily large, AFIACT) and insertion always happens at the top. However, that's not relevant here. The reason FormLists are slower than Papyrus arrays is because all of the FormList manipulation functions, such as HasForm() or GetAt(), are both idiot-proofed and frame-linked. Compare the execution speed of calling HasForm() on a FormList, doing an iterative search of that FormList with GetAt(), using Find on an array, and doing an iterative search of an array with ArrayName. Although there is no logical difference between an iterated GetAt() and calling HasForm() -- HasForm() has to do exactly the same steps -- the HasForm() approach is significantly faster, because while HasForm() is frame-linked all of its internal steps are not. On the other hand, GetAt() is frame-linked and can't bundle a bunch of operations like HasForm() does. The upshot of all of this is that, assuming 30 FPS, if you have a moderately long FormList -- say, thirty elements -- HasForm() will return in ~1/30th of a second, but the GetAt() search could easily require a full second in the worst case. Since array operations are all treated as memory accesses, they are not frame-linked (and nor do they allow the thread to jump to another script, which can be important). The difference between using the array Find and RFind methods, and simply coding it yourself directly, is therefore much smaller, and both will be faster than HasForm() is.
  18. You'd think so, but you're wrong. Game.GetPlayer() is linked to the frame rate. It will not return any faster than the game can render a frame, which is much much much slower than accessing a property (which is not frame-linked, and therefore effectively instantaneous by comparison). This is also, by the by, why manipulating arrays are so much faster than FormLists.
  19. Function calls are *murder*, because a great many of them are linked to the games frame rate and will never execute faster than the game generates a frame. Pull it once and put it in a variable, or store it in a property directly in the CK. It isn't too bad if it's a one-and-done execution, but you say this is meant to 'be used continuously', and that'll make optimization important.
  20. Yeah, a loop while not 3Dloaded is okay in *some* circumstances -- for example if it's in an event which *should* make the item load -- but because it can very easily not fire as expected, it's best to put a timer on the maximum time to wait *and* some kind of fail-gracefully exit method. The reason to offload things from OnIniit() is that OnInit() code has two special properties: 1. While an OnInit() event is executing no external calls into the script can be made. 2. ... except from other script's OnInit() events. This can cause unexpected behaviour and should generally be kept to stuff that is as fast and as minimal as possible, with a very short RegisterForSingleUpdate()/OnUpdate() pair to do the heavy lifting. States can be used to overload the functions and events to behave differently once the initialization is complete. I am not certain from inspection what is causing the script lockup. Usual causes for the symptoms described are infinite loops or the script object getting garbage cleaned for some reason. Ordinarily for doing a twinned disable/enable I would recommend linking them together in the editor with the mannequin as an enable-parent of the pedestal. However what ones are active appear to be dynamically defined, which makes that a no-go.
  21. This is insanely complicated relative to what the OP is trying to achieve. Less is more when it comes to programming. That logic would be correct if all seven effects were required to advance the stage, but that's not what OP's code looks like they're trying to do. I agree with offloading the stage-setting to the quest proper as a design principle, but if this code is on, say, a quest alias, I'm not sure it matters much.
  22. Note: Strictly, the above code may also generate a race condition (it still has the potential for multiple OnMagicEffectApply() events firing). There's ways to mitigate that if it's relevant, but they're beyond the scope of your question.
  23. There's a variety of possible approaches here, depending on what exactly you *mean* to do. There's nothing wrong with a basketful of if statements, as such, but there are some approaches that would eliminate the need. As currently structured your script doesn't care about spells, it cares about magic effects. The same magic effect can potentially be used in many different spells or spell-like effects (such as enchantments or abilities). It is also set up so any one of the seven magic effects listed will trigger the code execution, so the potential for a race condition exists: If a spell has two of the effects you care about you will set the quest stage four times: It will fire two OnMagicEffectApply() events, both of which will have two successful matches. If you're using a structure like that it is generally best to make it go if-elseif, so that all the branches are mutually exclusive and only one will be chosen. My own setup here would be to use a FormList, so you can add and remove your triggering effects without needing to edit the properties or script code. It also greatly simplifies the code, to this: int property myStage auto Quest property myQuest auto FormList property myEffectList auto Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect) if akCaster == Game.GetPlayer() if myEffectList.HasForm(akEffect) myQuest.setStage(myStage) endif endif endEvent
  24. It'll be a bit tricky, since it intersects with the Civil War. The default guards are toggled on or off by an enable parent that the Civil War quests manage. The trouble is that in some cases it is just one marker, with the Imperials being enabled if it is, and the Stormcloaks being enabled if it is not; I don't know if that's the case for Rorikstead. You'd also need to place a bunch of Forsworn guards to enable when Rorik dies. Getting that, at least, isn't a problem; you'd put Rorik in an alias and listen for an OnDeath() event, maybe with some checks as to current quest stage and the like.
  25. Your problem is that you are extending an ActiveMagicEffect script, which doesn't have the OnRead() event. Papyrus therefore thinks you're creating a custom event, but no game system will ever call it, so your code doesn't get executed. If this script is on the books themselves, it should extend ObjectReference instead of ActiveMagicEffect. If it's on an alias pointing to a specific book, it should extend ReferenceAlias.
×
×
  • Create New...