Jump to content

mrpwn

Premium Member
  • Posts

    53
  • Joined

  • Last visited

Everything posted by mrpwn

  1. Have you had a look at the Threading Notes page on the CK wiki? You may have to make a single entity that updates the global variable when the other scripts call a specific function in a script attached to that entity. The function can use e.g. a spin lock to queue up the execution of the rest of the function and thus the incrementation of the global variable. Alternatively, you could have your scripts chuck a token item into a container and attach a script, which periodically clears out the container and increments the global variable by the number of token items, to the container. If you don't want to have the container script checking all the time and you don't need the global variable to update instantly, then you could set up a delay system that uses the OnItemAdded event to unregister any previous updates, and register for a single update. Or you could use the OnItemAdded event to switch into an active state (clear out the container every N seconds) and after some time of inactivity switch back to an idle state.
  2. Have you tried checking what happens if you move all of the container's contents to another container with RemoveAllItems? Does GetItemCount still return an unexpected value when called on that other container? EDIT: Are you always checking for the same item? If so, then you might be able to use the condition functions that are available in e.g. quests and magic effects. I'm not sure if that system is also affected by the same bug that GetItemCount appears to be suffering from.
  3. You can also compile your scripts from text editors like Notepad++, Sublime Text, and others. The CK wiki even has a page with instructions on how to setup Notepad++. You'll need to attach scripts to forms, ObjectReferences, etc. and fill any properties you may have in your scripts within the CK, but you can do essentially all of your scripting outside of the CK (script fragments are an exception and tend to be easier to do in the CK).
  4. You have an incomplete definition for an Int property. As IsharaMeradin pointed out, you will probably just want to declare it as an Auto property unless you want to implement some specific behavior when either assigning a value to the property or getting its value. You'll need to remove the EndProperty keyword from the last line or it will cause a compilation error once you have added the Auto keyword. The first error (mismatched input 'Event' expecting FUNCTION) was caused by the fact that you were incorrectly defining a "full" property (i.e. without the Auto keyword). Only specific functions (Set and/or Get functions with the appropriate return values, but at the very least one of the functions is required) may be defined inside of a property definition, but your script contained definitions for an event and a function, which is neither a Set nor a Get function, inside of the property definition.
  5. Minor point I'd like to add is that the following line is unnecessary: objectReference caster = akCaster akCaster is an Actor, which extends ObjectReference (which in turn extends Form), and as such any non-global ObjectReference (and Form) functions can be called on an instance of Actor. akCaster can also be passed as an argument to a function instead of using an explicitly declared ObjectReference variable as an intermediary. Not crucial to the functionality of this script, but a useful technical aspect of the language to know.
  6. It is only available for Sublime Text at the moment. The linter is integrated instead of being a standalone Python script in order to eliminate the overhead introduced by starting an external program (around 1-2 seconds in my experience). That said the linter could be separated into its own little program that could then be used with other editors just to do the linting (it also handles some of the completion system's logic in its current integrated form).
  7. The += operator is most likely the issue. You can only use the simple assignment operator, =, when assigning directly to an array element. So you should use this line instead: TalleyofMatchingWords[LoopCounter] = TalleyofMatchingWords[LoopCounter] + 1 By the way, the linter that I've included in SublimePapyrus can catch illegal code like that.
  8. SKSE added GetNumRefs and GetNthRef functions to the Cell script, if SKSE is an acceptable dependency for your mod.
  9. I got the following two errors when trying to compile the script source you posted: You are trying to call GetLeveledActorBase on an ObjectReference. You would need to cast akAggressor as an Actor: Target = (akAggressor as Actor).GetLeveledActorBase() However, you still have the problem of Target having been declared as an Actor variable while GetLeveledActorBase returns an ActorBase value. The script compiles just fine with the following substitution: Target = akAggressor as Actor
  10. Reading data from multiple sources (savegame, plugins, and potentially from the Skyrim process) may turn out to be a decent solution (e.g. some things only need to be read once, unavailable or cumbersome to access from some sources). There is an event in Papyrus for when a savegame is loaded, but you won't know which particular savegame is loaded. I'm already playing around with the idea of a map system that would allow the player to do their own map making while playing: - Buy a basic map with just the major cities and settlements marked on it. - The player could add their own map markers. - More serious roleplaying could be facilitated by requiring the player to use an in-game map and compass to figure out where they are (update position on the map) and their heading. Custom maps that look hand-drawn could be made. Tabletop RPG communities have plenty of suitable resources like brushes available for this kind of stuff. I've always been annoyed by the pin-point accuracy of quest markers in Skyrim and this map system could be made to point at an approximate area (e.g. circle containing the exact spot, but not centered on that spot). Dialogue and quest objectives don't always give enough info to be able to completely remove quest markers, but maybe the aforementioned idea could be a decent compromise. Mapping would probably be limited to large worldspaces (e.g. Skyrim, Solstheim) unless one wanted to figure out how to generate local maps based on the loaded plugins. By the way, the prototype does seem to also work quite well when entering a city worldspace (e.g. Whiterun) and the player position remains quite accurate on the Skyrim-wide map when moving through a city. Not sure how one would handle the discovery of locations, if one wanted to retain that from the map system in Skyrim. There is a Papyrus function that could be used, but it would require polling to find the markers and it would ignore the discovery radii set in the markers. The official wiki contains quite good documentation on the language specs and some tutorials. Should not be difficult since you already have programming experience. I'll take the opportunity to plug one of my projects, SublimePapyrus, then as it might make it a bit easier for you to get started with Papyrus. It's a package for a text editor called Sublime Text (major versions 2 and 3 are supported) and the package includes stuff like syntax highlighting, a linter, intelligent auto-completion based on Papyrus source files found in the import folders that you can define in a settings file, build system, etc. At least the auto-completion means less memorization and looking up of functions on the wiki. SublimePapyrus also happens to be written in Python, if you want to have a peek under the hood/modify/contribute. Wearing down SSDs crossed my mind as well and I agree that it would be better to use a socket or pipe. I think that would have to be implemented in C++ as an SKSE plugin to get data from Skyrim. My C++ knowledge is very basic and it has been quite a while since I last wrote C++ code. Not at the moment. I could probably clean it up a bit and host it somewhere, if you want to test it or have a look at it. It ain't pretty though. I might end up working on at least a map system as described above when I find enough time for it. If you want to collaborate (even if just on small parts), then I'd be up for it.
  11. I threw together a quick and very dirty prototype for showing the player's position in Skyrim. Here are two screenshots southwest of Solitude and north of Riften (a red X marks the player's location): - A Papyrus script outputs the player's X and Y coordinates as a JSON-formatted text file with the help of JContainers. - A Python script scales the coordinates and passes the generated values to a Rainmeter skin, which is displayed on a secondary 1280x1024 monitor, every 5 seconds. - The Rainmeter skin positions a red X on top of a map I stitched together from multiple screenshots of this map of Skyrim.
  12. On a technical level this seems like an interesting problem to solve. If you want to do prototyping, then you could probably use PapyrusUtil, JContainers, or FISS to output data to a text file from Skyrim's scripting system. NW.js or Electron could be used to watch those files and display the information. You would probably have to create an SKSE plugin at some point to get access to some of the data you are interested in (e.g. description fields in magic effects) that is currently not available even via SKSE's additions to Papyrus (mainly because the information is not relevant to game mechanics). However, a few things to think about: - Think about how the data is handled and its persistence in the context of the player's ability to load a save game at any point. - Is this data not available for the player to view already? If it is visible, then is the intention to make it more convenient to view in certain circumstances? - Why not implement this in the game (e.g. as a separate menu, a HUD element with the help of SkyUI's framework)? - Real-time access to data might be tricky, but event-based or regular (every N seconds) updates may work. What can be done within such limitations? - How will you take into account modded content (e.g. in terms of maps/player location info)? Relying on static information from a wiki is not viable in most cases. - What would the user experience be like (e.g. would one be forced to switch from the game window to the second screen to do stuff like changing what is displayed)?
  13. There is not a whole lot of documentation, but the functions are in the Utility script.
  14. You're welcome. You can compile scripts from within Sublime Text, though it still needs Bethesda's compiler (or a 3rd party compiler) to do so. The settings file of the SublimePapyrus package also allows you to use some of the more advanced features (e.g. multiple import folders), which cannot be used from within CK, that Bethesda's compiler is capable of. You'll still need CK to attach scripts, fill properties, and generate script fragments in quests and dialogue. Outside of those things I think you can do everything else from an external editor such as Sublime Text.
  15. The explanation that I provided is based on prior experience with writing a linter, which is a piece of software that checks the validity of source code just like a compiler would do in its front end, for Papyrus. I don't have any way of proving that what I said is actually happening since I do not have access to the source code of Bethesda's compiler, but it seems like the most likely scenario to me. The linter is a part of the SublimePapyrus (GitHub repository, Nexus page) package, which I am the primary developer and maintainer of, for Sublime Text 2 and 3. The package has other neat features as well for anyone doing a lot of scripting. As for how I figured it out; at first I could not see what the problem was with your script. I then copied the script into Sublime Text 3 with the SublimePapyrus package installed and let the linter have a look at the script. No errors found, but I have in the past forgotten to implement certain checks, and sometimes I have even managed to avoid bugs, found in Bethesda's compiler. At that point I figured I might need to fix something in my linter. Then I tried compiling the script with the compiler provided by Bethesda and got the same errors that you reported on the lines that you mentioned. Based on a hunch I tried messing with the whitespace between the variable names, operators, and integer literal in the lines that were causing compilation errors. No more errors when compiling with the minus and 1 characters separated by whitespace. It looks like the front end of Bethesda's compiler is based on a parser generated with ANTLR based on the names of certain files found in the same folder as the compiler. I cannot say for sure if the issue you brought up is a bug with ANTLR or just this one particular compiler. I was initially looking into the possibility of using ANTLR myself when I first started writing my own linter as it was my first time writing such a program, but I ended up not going that route. Edit: A bit more detail on my reasoning, if you or anyone else is interested. Lexical analysis deals with what could be considered words (names of variables, names of functions, operators, etc.). This analysis is done by grouping individual characters and generating what are often called tokens. These tokens include additional information such as the row/line number, column number of the first character in the group of characters, type of group (identifier, operator, literal, etc.). Grouping characters can sometimes be tricky as it is context-sensitive and implementation-sensitive. Consider the following two statements: a = 2 - 1 b = -1 + 2Those two lines assign the same value to two different variables once evaluated. However, they produce different token streams and as a result different parse trees. The first line would produce (in a simplified form): Identifier: a Binary operator: assignment Integer literal: 2 Binary operator: subtraction Integeral literal: 1If we did not have any whitespace between - and 1, then we could produce: Identifier: a Binary operator: assignment Integer literal: 2 Unary operator: negation Integeral literal: 1or Identifier: a Binary operator: assignment Integer literal: 2 Integeral literal: -1 but given the context (an integer literal prior to a unary operator or another integer literal) we can figure out that the two integer literals are separated by a binary operator (subtraction). The second line would produce either: Identifier: b Binary operator: assignment Unary operator: negation Integer literal: 1 Binary operator: addition Integer literal: 2or Identifier: b Binary operator: assignment Integer literal: -1 Binary operator: addition Integer literal: 2depending on the implementation. Here are some hastily drawn representations of the parse trees and how they would be evaluated (going from the parse tree at the top to the parse tree at the bottom).
  16. After a bit of testing it looks like the lexical analysis part of the compiler has a bug. It seems like it is having trouble telling the difference between a unary minus and a binary minus. It should be generating the following tokens: Identifier: LinesToSkip Binary operator: assignment Identifier: LineNumber Binary operator: subtraction Integer literal: 1 but it is probably generating the following: Identifier: LinesToSkip Binary operator: assignment Identifier: LineNumber Integer literal: -1 Solution: Add a space between the subtraction operator and the integer literal so that this: LinesToSkip=LineNumber-1becomes this: LinesToSkip=LineNumber- 1 I don't think I have noticed that bug before (or maybe I had just forgotten about it already) since I tend to put one space on both sides of an operator. LinesToSkip = LineNumber - 1
  17. You have to define the type of the value that is returned by a function. For example this function header: function GetWord(string SVE_CurrentLine) should look like this: string function GetWord(string SVE_CurrentLine)
  18. Did you extract the script sources for Skyrim? They are in a file called Scripts.rar in \Skyrim\Data. If you have done so (seems like it based on the error messages), then the first error Unable to find flags file: TESV_Papyrus_Flags.flg would suggest that TESV_Papyrus_Flags.flg, which should be among the aforementioned script sources, is not where it should be (\Skyrim\Data\Scripts\Source). EDIT: As far as I know the unknown types are basically a result of the compiler's inability to successfully process other script sources while trying to compile the script you told it to compile. Many in-game objects (spells, weapons, NPCs, etc.) have base scripts that define what can be done with such an object and some of them extend (or inherit functions and events from) another script, which in turn may extend another script (and so forth). So the compiler is parsing your source file and ends up finding types (GlobalVariable, Actor, ActiveMagicEffect, etc) other than the base types (bool, float, int, and string) that require it to look for the corresponding script sources for the former types. The missing flags file is preventing the successful parsing of those types (e.g. GlobalVariable) when the compiler encounters certain keywords/flags that it is not sure what to do with. This parsing of other script sources is necessary so that all function calls and their return values can be resolved correctly, auto-casting of variables from one type to another can be done, etc.
  19. Have you checked to see that the definition for the OnKeyUp event in the copy of Form.psc that you are using does indeed match with what you are using in the script in your original post? Are you compiling from within CK's script editor or do you have a setup involving an external text editor? I'm asking just in case you have a setup that uses a more complex argument for the import folders when running the compiler. If that is the case, then you might accidentally be using the vanilla version of Form.psc when compiling.
  20. How did you install SKSE? Installer or 7z archive? The latter is required for developing mods since it contains the source files for the modified scripts and it sounds like you might not have those modified script source files.
  21. Did you extract the source files from Scripts.rar in \Skyrim\Data?
  22. 1. ReferenceAlias is kind of a wrapper around the instance of ObjectReference that the alias is filled with. ReferenceAlias receives events available to scripts that extend ObjectReference (and Actor, if the alias is filled with an instance of Actor). However, Self points to the instance of ReferenceAlias and not the instance of ObjectReference or Actor that the alias is filled with. To access the latter requires using the GetReference or GetActorReference functions. Script SomeAlias extends ReferenceAlias Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) ;The ObjectReference/Actor filling this alias was hit by something, let's delete it Self.Delete() ;Won't compile as this ReferenceAlias does not have such a function ObjectReference kRef = Self.GetReference() ;Get the thing that is filling this alias kRef.Delete() ;Delete the thing that is filling this alias EndEvent 2. ActiveMagicEffect is a special case since it is usually very short-lived and you should not try to manipulate an instance of that from another script. An instance of ActiveMagicEffect is volatile and may be terminated at any time by the game engine. Let's say you had a script called MagicalStone, which extends ObjectReference and is attached to a stone object placed somewhere in the game world. You could use a property, which is of the type MagicalStone, in another script to access that specific stone. MagicalStone Property kStoneRef Auto Event SomeEvent() kStoneRef.MoveTo(Game.GetPlayer()) EndEvent The property, kStoneRef, is then filled inside of Creation Kit via the properties window of the second script that you attached to something. Let's say all instances of that stone object had the MagicalStone script, were scattered around the game world, and you wanted to access functions (or other stuff) from any instance of that stone object that is near the player. What you could do is get the nearest instance of such a stone object either as an ObjectReference via e.g. Game.FindClosestReferenceOfTypeFromRef or by filling a ReferenceAlias in a quest. Form Property kStoneBase Auto Event SomeEvent() ObjectReference kStoneRef = Game.FindClosestReferenceOfTypeFromRef(kStoneBase, Game.GetPlayer(), 1024.0) If kStoneRef MagicalStone kMagicalStoneRef = kStoneRef as MagicalStone kMagicalStoneRef.SomeFunction() ;Call non-global functions from MagicalStone on kMagicalStoneRef EndIf EndEvent You can "traverse" the tree of inheritance by casting a variable from one type to another. If scripts A and B are both attached to an object in the game world and extend script ObjectReference, then you can call functions from script B inside of script A by doing a double-cast. Script A extends ObjectReference Event SomeEvent() B kBRef kBRef = Self as B ;Does not work as A does not extend B nor does B extend A kBRef = (Self as ObjectReference) as B ;We get around the issue by going back one step to ObjectReference and then going down another branch to B kBRef.SomeFunction() EndEvent The Import keyword simply allows you to call functions, which have the Global keyword, without prefixing the function call with the imported script's name. ;Case #1 - Script that does not import the Debug script Event SomeEvent() Debug.Notification("Some message") EndEvent ;Case #2 - Script that does import the Debug script Import Debug Event SomeEvent() Notification("Some other message") Debug.Notification("Some other message") ;The "Debug." part is not necessary, but it is still allowed EndEvent ;Case #3 - Script that does import the Debug script, but also has (or inherits) a definition for a function called Notification Import Debug Function Notification(String asText) ;Does something EndFunction Event SomeEvent() Notification("First message") ;This will not compile, because the compiler does not know which definition to use Self.Notification("Second message") ;Uses the definition from this script or an inherited definition Debug.Notification("Third message") ;Uses the definition in the Debug script EndEvent
  23. I missed the use of akReferenceItem when I had a quick look at the script. The ObjectReference may still be valid then. The developers of SKSE may have mentioned the reason(s) for needing to implement the functions in the WornObject script in addition to the ones in the ObjectReference script, but I don't remember what those would be.
  24. Let's say that you have enchanted an Ebony dagger with an enchantment that does fire damage. The problem is that you are calling the GetEnchantment function on akBaseObject, which is the base (unmodified) Ebony dagger that does not have an enchantment applied to it. Hence the lack of an enchantment. You will probably have to make use of SKSE's WornObject script to get enchantments from equipped items. If the player-enchanted Ebony dagger was placed somewhere in the game world and not in a container or some character's inventory, then you could use the GetEnchantment function found in the ObjectReference script. ObjectReferences tend to not be valid anymore once the ObjectReference is placed in a container or an NPC's inventory as the game engine "converts" most references to their base forms and increments the object count in the container instead of storing each reference. So if you pick up five unmodified Ebony daggers, then the game will essentially store them as: - Ebony dagger (5 pcs) instead of - Ebony dagger - Ebony dagger - Ebony dagger - Ebony dagger - Ebony dagger There are exceptions, which remain as valid ObjectReferences in containers, such as quest items and pre-enchanted items that are not fully charged. Player-enchanted items may also be valid ObjectReferences in containers.
  25. SKSE adds both global and non-global functions. Global functions, which follow the logic that you described, can be called without the need to have an instance of that script/class (e.g. Debug.Notification, UI.IsMenuOpen) while non-global functions have to be called on instances of a script/class (e.g. Actor.GetLevel, DefaultObjectManager.GetForm). JMSFedaykin's approach is correct (the line appears to be from the relevant CK wiki article, which I updated several months ago when I ended up using DefaultObjectManager in a mod). GetFormFromFile is not the only function that cannot be called outside of an event or another function. No functions or events can be called outside of an event or function.
×
×
  • Create New...