Jump to content

forli

Premium Member
  • Posts

    519
  • Joined

  • Last visited

Everything posted by forli

  1. Open the CS/CSE. You don't need to load Oblivion.esm, unless you need to use resources/objects/scripts from it. Open the script editor and create a new script. Set the type to "Magic effect" (in the top/bottom corner of the script editor) scn mySpellWhichAddAnAbility ;give it a better name Begin ScriptEffectStart AddSpell theAbilityToAdd ;whatever your abilit's called EndNow, in the Objects window go to Magic and create a new spell. Add the effect: Script Effect -> attach the script "mySpellWhichAddAnAbility" (or whatever name you gave it). Click ok and save the esp. NOTE: If used by an NPC it may be a problem: spells/abilities are added removed to the whole base object, so if a "Bandit" cast this spell, all "Bandits" receive the ability.
  2. Thinking about it... quests are always loaded (they are persistent objects), so there's no need to allocate/deallocate anything, but I admit this can be true also for the remote activator, if flagged as persistent. Still, if we take a simple CS Script code like this: Begin GameMode ... If Working Let timer -= GetSecondsPassed If timer <= 0 Let timer := 0.25 ;0.25 seconds ;do stuff EndIf EndIf ... End The command "Let", alone, runs the following wall of C++ code: And this is only the Let command! I can't take the If command, because it's a Vanilla command and so we don't have its code. while a possible implementation of the check for the Running flag and the fQuestDelayTimer for the quests is as simple as the following one (and the entire code is much faster than the single Let command above): #include <chrono> #include "something else" using namespace chrono; milliseconds currentTime; void checkAndRunQuest(Quest& quest, other params){ ... if (running) { currentTime = duration_cast<milliseconds>(system_clock::now ().time_since_epoch ()); if (quest.nextRunTime <= currentTime){ quest.nextRunTime = currentTime + quest.getVariable["fQuestDelayTime"]; ;run GameMode/MenuMode block } } } The difference is big enough to make me think about optimization for every single line I write with CS scripts, as each one may run a wall of text like that.
  3. In response to post #41277490. #41277685, #41278220, #41278890, #41280530 are all replies on the same post. 1. No mods is bugfree, and many bugs can only be discovered when thousands users play the mod (which require the author to upload the mod in the first place). If we follow your rule, then the Nexus would be an empty place. 2. There are "Beginner guides" everywhere on the forums. If every author must tech to every user how to (generically) install a mod, then they would need to create a 300 lines long description/readme every time. Except for complex mods, the procedure is always the same: download the package, extract it, read the readme, and if you understand what will happens to your game with the mod then drop everything in the Data folder, enable some esp/esm and play. The middle steps procedures are not our responsibilities. It's your problem if in 2016 you don't know how to extract a zip/rar/7z file. We must not teach you how to use a mod manager, as it's not our creation. The author of the mod manager is responsible for giving you the manual. If you don't know how to use a mod manager, you have to blame the mod manager's author, if he didn't give you enough/clear instructions, or yourself, if you don't like to read the readme. 3. I agree with this, but very often I see mods which clearly state there's a configuration file, with users which don't know just because they don't read what must be read, and very rarely I see mods which don't state there's a configuration file. Many ini I saw were very exhaustive with explanations (sometimes the explanations are contained in the readme/manual, but they still exists). This means most (not all) of the times the cause of the problem are the users who don't read. Finally: NMM is still far from begin a complete mod manager. I'll give you 3 trials: a) Try to change the "Installation order" (not the "Load order") of the mods with NMM. b) Tell me which files (one by one) are overwritten when you install/uninstall a mod. c) Install a complex package without the support of scripts. Complete mod mangers like Wrye Bash and Mod Organizer can execute these trials in no time, and the user is always informed of the situation before/after the changes. Instead, NMM can't do any of them.
  4. The game is built with C++ code, but CS Scripts are not C++ code. Every command you use in CS Script runs tons of C++ commands, which makes CS Scripts very inefficient (look at the OBSE source code if you don't believe me). Since we can't optimize internally the commands, we can only optimize our scripts and our algorithms. It's true many other scripts (not just quests) are poorly optimized, but this is not an excuse to write more poorly optimized ones. The Oblivion script engine is poorly optimized, and it's single thread: it only runs on a single core of your CPU (don't ask: there's no way to make it multi-thread without the Oblivion source code, which we will never have, and without breaking half of scripts in the entire community). With the tons of heavy scripted mods out there, the engine is already overloaded and the CPU core which must execute all those script is already busy enough. Adding more pounds won't make anything better. Even modern CPU can be crippled by this, as they are powerful, but split the power among many cores. Since Oblivion put the script engine on one core, it only uses a fraction of the power of the CPU. It's counter-intuitive, but it's possible old CPU which concentrate their power in only one or two cores may run Oblivion better than new CPU. Normally, assigning a variable every frame is not expensive, but assigning a variable in CS Scripts is 10 times more expensive than assigning a variable in C++ code. You're right it's not a performance killer... but why waste your precious CPU? As stated above, CPU is a valuable resource in Oblivion. While an object is loaded, it keeps running every frame all its GameMode/MenuMode blocks (depending if in game or menu mode), either directly attached to the object or attached to any object in its inventory. You can't "stop" the activator. You only set a variable to prevent it runs the code. The check you make at the beginning "If Working == 1" is necessary as that GameMode block runs (which means it's not stopped). But still, the game need to allocate all necessary resources, call the GameMode script, check that condition with the fast ( :confused: ) CS Scripts, reach "End" and deallocate resources. Repeat every frame. Sure, the performance hit is far from being noticeable, but the sum of many poorly optimized scripts may cause a noticeable (and sometimes, serious) performance hit. In programming you always need to think about optimization. Even if a quest is always loaded, it only runs its script when flagged as Running. When a quest is stopped, its script is not even considered, so it cause no performance hit at all. Think about the Running flag as an internal "Working" variable, but directly checked with C++ instead of CS Scripts, and before any resource is allocated for the script. If the Running flag is false, no resource is allocated/deallocated at all and no CS command is executed. Not implemented in the same way! GetSecondsPassed is a CS command, and as you learnt, it costs tons of C++ commands. This means the script effectively run every frame to update the timer and check whatever it's time to run the rest of the code. Every frame the cost is: allocate + GetSecondsPassed (script) + update timer variable (script) + check if time passed (script) + deallocate. Quests are timed internally by Oblivion, again, with C++ code and before any resource is allocated. If the time has not yet come, no resource is allocated/deallocated and the script doesn't run at all. Every frame the cost is: get time passed (C++) + update timer variable (C++) + check if time passed (C++). One final advice: If Working == 1"== 1" is not necessary. The game consider TRUE any condition whose result is != 0. Basically, the game does this: If (<condition>) != 0 In your case it's like this If (Working == 1) != 0As you may guess, "== 1" is a redundant operation in this case, since Working is either 0 or 1. If Working could assume value 2, and you want to consider "2" differently, then == 1 and == 2 are necessary. but in your case you can just drop that == 1. It makes the code more readable: "If Working". Ah, and there's a very tiny tiny tiny performance gain too!
  5. Little comparison remove activator <--> quest Easy to start Set working to 1 <--> StartQuest MyMenuQuest Easy to stop Set working to 0 <--> StopQuest MyMenuQuest Resist cell resets No, if the attached object is erased by cell reset <--> Yes, always. Doesn't care about cell resets Require assignments every frame to keep it running Yes <--> No Run and consume CPU power even when not used Yes (check "Working" every frame) <--> No (doesn't run at all) Can adjust script running speed to decrease performance hit No <--> Yes (fQuestDelayTime)
  6. Even if you solved the riddle, why are hurting yourself with an Object script attached to a remote activators? As you learnt, Object scripts stop working if the object they're attached to is unloaded, and you need to continuously set a variable to ensure the object is not unloaded. If you need to show a menu and ensure the script keep running anywhere you are, for as long as you need, change the script type to "quest script" and attach it to a quest. Quest are always loaded, runs independently from the location, and work even better because you can start and stop them at any time with StartQuest and StopQuest (so you can also erase the variable "Working"). Just don't forget to declare and set (only once, not every frame) the variable fQuestDelayTime in the Quest script, else it will run every 5 seconds. If you heard "Quests are bad", well, it's not true. You have full control of a Quest script and you can completely stop it with the above commands and change the running speed to (example) 5 times per second with the above variable. Instead, an Object script can't be controlled or stopped. The game keep processing its script every frame and it only stops when the game unload the object. And since it keep running, you need to keep it at bay with a "Working" variable. Object script for a menu? IMHO, a very bad choice...
  7. Little tip: if you use Wrye Bash you can click on the package BEFORE installing it, and on the right it will list all conflicts. Also, WB will tell you whatever the files in the Data folder have higher or lower priority than the files you're going to install (higher priority files always overwrite lower priority files), so it really helps you to quickly predict how the game folder will look like after the installation.
  8. Yes, it will drop the content from zip/Data into Oblivion/Data, and if there are further conflict even inside Oblivion/Data the rule is the same. The OS never overwrite a folder, only files (and only if you confirm, when it ask you to overwrite them).
  9. Unless your OS is dumb, it won't overwrite the data folder, but will merge the content of the two folders (so it will take the content of the data folder you're dropping and will move it inside the other data folder, and if there are common subfolders repeat the procedure with them).
  10. Very recommended OBSE plugins against CTD: - Engine Bug Fixes (self-explanatory) - Oblivion Stutter Remover (the name says everything, and it also prevent many CTD. The latest version also include the FastExit plugin, so you can remove FastExit2). - More Heap (oblivion only uses a limited amount of memory, but may require much more) - Oblivion Reloaded (enhance graphic while also fixing some little bugs in the engine) - Message Logger (not a bug fix per se, but allow you to see the Oblivion internal errors and maybe discover a bug you or someone else can fix) Recommended mod (it doesn't directly fix/prevent CTD, but it can still help you avoid many situations which may eventually lead to CTD): - MigMaster Script Resources (the SafeCloningFunction - Filter.esp require the bashed patch, but it's recommended)
  11. These mods are illegal. On your computer you're free to use the music from Oblivion and Skyrim as you want, even use it in other games. If everything only stay on your computer. If you uploading/redistribute said music anywhere, you will break the Oblivion/Skyrim EULA (you'll also break the Nexus site rules, which may cause a permanent ban).
  12. Actually, esms can have other esms as masters, and esps can have other esps as masters. The CS only allow esp->esm, but CSE also allow esp->esp and esm->esm which are fully supported by the engine. So, you can either make your esm require Migck's esm or turn your esm into an esp and still be able to use the "Merge to master style".
  13. CreateFullActorCopy is a dangerous command you should never use: - It clones the actor BASE object (and it also clones the scripted items in its inventory) and then create a new reference to that copy. - All scripts on the duplicate (or attached to any item in its inventory) may not work or may bug out, as they won't recognize the actor anymore. - DeleteFullActorCopy can destroy the actor's reference and base object, but it can't destroy the cloned scripted items in its inventory. I recommend MigMaster Script Resource instead, which add a safe cloning function to the game which, as the name state, is safer and avoid many pitfalls associated with the CreateFullActorCopy function.
  14. Well, GetGameRestarted is very useful, if used in a MenuMode 1044 Begin MenuMode 1044 If GetGameRestarted SetEventHandler "PostLoadGame" fnLoadGame ;the load game handler. A must for every mod ... ;you can set some event handler there. They will be registered only once EndIf EndThis block will run as soon as you reach the main menu and will register the event handlers you need. Using the "PostLoadGame" is faster than the "GetGameLoaded" check, because the event handler is not a check you do every frame (obviously!) and because it will fire just a while before entering GameMode (in the last seconds of the load screen), so it will surely runs before all GameMode blocks (so, everything is already initialized and ready when they run the first time). Little problem: as of OBSE v21, "PostLoadGame" seems to misfire for some Steam users. It has been reported and it's in the TODO list of OBSE v22. . Damn! 2016 and I still confuse "treat", "threat" and "thread". Even if english is not my native language, this is unacceptable!! Ok, be right back after 3-4 seppuku...
  15. Oh, one more tip: Event handlers are not linked to savegame but to the game session, and they can be registered multiple times, which means: they are not saved in the savegame, so you need to register all event handlers you need again when the savegame is loaded.they are not destroyed between loading, so if you load a savegame, create some handlers, then reload the same or another savegame, it will maintain all event handlers registered.they are only destroyed when you close the game (exit to desktop) or when you use the command RemoveEventHandler.you can't overwrite an event handler, so the same event handler can be registered multiple times: if you register it two times (same event, same function, same filters), then the event will call the function twice; if you register it three times, then the event will call the function three times, and so on... So, when you register an event handler, you need to ensure the event handler is not already register. How to ensure this? There's no command "IsEventhHandlerRegistered", but you can use RemoveEventHandler to erase any previously registered handler (it's safe to use even if there's no event handler registered).
  16. return ;will this bypass dialogue in an event handler?? else activate ;is this actually required? Nope. OnActivate event handler doesn't prevent the object activation like the Begin OnActivate block, so the object will be activated anyway. For the same reason, activate in the OnActivate event handler will cause the object to be activated one more time, which cause the event handler to fire again, in an endless "recursive" call (until the Oblivion stack explode with a CTD). Quotes around "ref" and "object" filter are not required. The compiler thread them as strings anyway (if you don't put quotes the compiler may show a warning, but the script will works exactly the same). About this: If Eval ( ( A.GetName ) == ( B.GetName ) ) MessageBox "Refs have the same name" EndIf You could just use CompareNames If Eval (A.CompareNames B) == 0 MessageBox "Refs have the same name" EndIfBut if you need to compare two references, you could just do: If A == B
  17. Even if it's the result of the code, machine code read during reverse engineering is the actual code executed by the CPU, so it's the most accurate (and difficult to read) code. I know there's no need to disassemble the machine code if we have the source code... but we don't have the source code! As I said, we still don't have not even the Morrowind source code, so I don't think we'll ever see the Oblivion's one. I believe these kind of engine fixes/patches will always be in the hands of few skilled programmers who succeed in read the machine code (the only code we have now, and probably the only code we'll ever have). I didn't excluded the possibility for errors, but the statement means IanPatt didn't digged in the Havok engine ("probably does what it sounds like..."), so he didn't really know if Havok really use it, while it's possible Alenet made further studies while developing OBGE4/OR (since he claims the engine uses 1 anyway). Still, if iNumHavokThreads makes a difference, then Alenet missed something.
  18. Machine code IS code (hard to read, but still code)! If you take a look at Oblivion Reloaded you'll see he has all skills required to read the machine code. Bethesda has still not released the Morrowind source code, so it's very unlikely they will ever release the Oblivion source code. It's true: without source, only Gods can create plugins like OR, OSR and EngineBugFixes to patch bugs in the game code.
  19. Nope, he used reverse engineering. In case you didn't noticed, Alenet is the author of Oblivion Reloaded, a very complex OBSE plugin which inject code directly in the game executable and can even patch bugs in the engine. This would have been completely impossible without reverse engineering. So Alenet surely saw the Oblivion code, and he knew exactly what he was saying in that article, as he saw the actual code used by Oblivion to manage those settings. When he said the game use 1 anyway for iNumHavokThreads, it means the actually saw in the code Oblivion does ignore whatever value you put in iNumHavokThreads and use 1 instead; and when he said iThreads and iOpenMPLevel are not used, it means Oblivion never reads/uses those values in the code. Of course, he added benchmark tests on top of that (like with iTreeClonesAllowed), and there's a chance he made a mistake (maybe some settings are really used but he didn't find them), but unless someone can prove he's wrong (by showing a piece of Oblivion's code, not by just showing benchmarks), his researches remain the most accurate ones we ever had. Benchmarks are never accurate. The performance differences you noticed may have been caused by anything, even external factors like the CPU/RAM/HD used by the OS at the time you did those benchmark tests or the temperature of your computer, which may have slowed everything down in some tests.
  20. 1) GetUserTime vs GetSecondsPassed GetUserTime is the Windows time, so if you save the game then reload after a day, the script will detect an entire day passed. GetSecondsPassed is the right command to use when you need to only consider the "game" or "script" time (and not the real world time), but remember GetSecondsPassed calculate the time passed since the previous run of the script, so you need to cumulate the result like a counter. Let TimePassed += GetSecondsPassed ;use += to cumulate the time passed in every frame. 2) GetContainer inside OnAdd block While it seems an obvious choice, it's bad instead: OnAdd fires in the same frame the item is being added, and sometimes the item has not yet registered his container, so GetContainer may return 0. When the GameMode block checks Attacker.IsAttacking with Attacker == NULL, the script may crash. So, you need to call GetContainer in the GameMode block, and return if the container is still 0 / NULL. Begin GameMode Let attacker := GetContainer If attacker == 0 Return EndIf .... 3) IsAttacking and GetDead/GetKnockedState Apart the fact == 1 and != 0 are totally useless/redundant (== 1 is useless in a boolean command/expression, while != 0 is always useless). Think about it: if the actor is attacking, he can't be dead/knocked, else if not attacking, the item is removed. This means the script will NEVER have a chance to enter the GetDead/GetKnockedState blocks, which can be removed. 4) RemoveMe called after other commandsThe script engine is very unstable with RemoveMe: this command must never be called after another command in the script in the same frame, else the game likes to CTD. Example: in the GameMode, you use RemoveMe after the commands IsAttacking, GetUserTime and MessageEx. This is bad.What to do? Just set to 1 a variable/flag and remove the item in the next frame, ensuring no command is called before RemoveMe. This implies the GameMode block's first action should be checking such flag and eventually use RemoveMe immediately (even before the GetContainer check). Begin GameMode If mustRemove ;first check RemoveMe ;RemoveMe called before any command. Good. EndIf Let attacker := GetContainer ;Check for container here, as OnAdd is not reliable. If attacker == 0 ;no container. Stop before we cause problems. Return ElseIf Attacker.IsAttacking MessageEx "ATTACK" Let TimePassed += GetSecondsPassed ;cumulate the time passed every frame If TimePassed > WeaponInteruptTime MessageEX "Time Up!" Let mustRemove := 1 EndIf Else MessageEX "Not Attacking" Let mustRemove := 1 EndIf End
  21. In the console you can't use the command Call to execute functions, but you can simulate it with a quest and the command SetStage: Create a quest (example: "myFnQuest"), enable "Allow repeated stages" and add a stage (example: stage 10) In the stage, create a new stage item (above, where your read "Log entry") and add the code you need in the "Result script". In the Result script you can even use the command Call to execute some function script. This effectively bypass the above Call limitation. Now, in the console, you can type: SetStage myFnQuest 10This will run the Result script of stage 10 (and can be repeated, thanks to the "Allow repeated stages").
  22. Even if incomplete, the most accurate guide for Oblivion.ini is the Alenet's one. Alenet didn't simply tested the values trying to find the differences. He actually used reverse engineering in the code to find out if/how the game really uses those values. The guide is here: http://www.nexusmods.com/oblivion/articles/44178/?
  23. I recall there's a bug in OBMM scripts which doesn't allow it to properly recognize OBSE.
  24. Not all mods contains esp/esm files you have to enable. Some mods just put textures/meshes/menus/etc files. You don't need to do anything else with those mods.
  25. Equipped items are only visible if they use at least one of the equipment slots. Problem is: you can't create new slots, and every slot can't be used by more items at the same time. Using another item's slot may cause even more problems, as using a slot automatically hide that body part (if use slot "Hands", equipping the item will make the hands will disappear, as the item is supposed to have a gloves/gauntlet mesh which should replace the hands).
×
×
  • Create New...