wghost81 Posted March 23, 2014 Author Share Posted March 23, 2014 Uploaded new "Alien Squad Size Randomized" mod to Random Alien Pods page. It is an example of really big mod, entirely written in PatchUPK 3.0 pseudo-code. I actually worked with individual files, usually one function per file. I joined all files later for the ease of distribution, but I left all the comments in place, so this can be considered as mod "source code". :smile: Link to comment Share on other sites More sharing options...
wghost81 Posted March 31, 2014 Author Share Posted March 31, 2014 (edited) Anyhow, I've been thinking about how to try and translate something like :Game().GetDifficulty()into the correct hex line, without the need for manually looking up hex. I've been thinking too and after writing a really long mod with PatchUPK I finally came to aliases:ALIAS=GameDiff:19 1B <Game> 16 0A 00 <XGStrategy.GetDifficulty.ReturnValue> 00 1B <GetDifficulty> 16 After you define an alias you can use it in the code with '!' marker:// if(Game().GetDifficulty() >= 2) 07 [@label1] 99 <!GameDiff> 2C <%b2> 16 // return 2 04 2C 02 // goto (else) 06 [@label2] [#label1] // return 1 04 26 [#label2] Aliases work similar to C/C++ macro: all <!Something> references are replaced with corresponding code strings. This should help with making very long code lines like// if(iPod < m_kDesc.m_kAlienSquad.arrPods.Length) 07 [@loop1end] 96 00 <.iPod> 36 35 <XComGame.XGGameData.TAlienSquad.arrPods> <XComGame.XGGameData.TAlienSquad> 00 00 19 01 <XGMission.m_kDesc> 09 00 <XComGame.XGBattleDesc.m_kAlienSquad> 00 01 <XComGame.XGBattleDesc.m_kAlienSquad> 16 shorterALIAS=arrPods:35 <XComGame.XGGameData.TAlienSquad.arrPods> <XComGame.XGGameData.TAlienSquad> 00 00 19 01 <XGMission.m_kDesc> 09 00 <XComGame.XGBattleDesc.m_kAlienSquad> 00 01 <XComGame.XGBattleDesc.m_kAlienSquad> 16 ... // if(iPod < m_kDesc.m_kAlienSquad.arrPods.Length) 07 [@loop1end] 96 00 <.iPod> 36 <!arrPods> This is especially helpful when there are multiple references to one "long" object. Furthermore, I've added '@' marker for auto-finding member variables://m_iCounter 01 <@m_iCounter> instead of//m_iCounter 01 <XGStrategyAI.m_iCounter> Edited March 31, 2014 by wghost81 Link to comment Share on other sites More sharing options...
wghost81 Posted April 1, 2014 Author Share Posted April 1, 2014 Updated nexus file and git sources with new features. Also updated GUI wrapper with new log feature. Link to comment Share on other sites More sharing options...
wghost81 Posted April 8, 2014 Author Share Posted April 8, 2014 Updated to v.3.2 (nexus files and git sources). See readme for details. Link to comment Share on other sites More sharing options...
wghost81 Posted April 20, 2014 Author Share Posted April 20, 2014 (edited) With pseudo-code feature adding a new names/objects finally started to make some sense. So right now I'm working on this. This is how adding a new local variable looks right now:UPK_FILE=XComStrategyGame.upk // WGhost81 [ADD_NAME_ENTRY] <% u9> // string length <% t"WGhost81"> // ASCII null-terminated string <% u0x00000000> // flags L <% u0x00070010> // flags H // XGStrategyAI.GetNumOutsiders.WGhost81 [ADD_EXPORT_ENTRY] <Core.IntProperty> <NullRef> <XGStrategyAI.GetNumOutsiders> <WGhost81> <NullRef> <% u0x00000000> // flags H <% u0x00070004> // flags L <% u40> // serial size <% u0> // serial offset <% u0> // export flags <% u0> // net objects count <% u0> // GUID1, zero if net objects count == 0 <% u0> // GUID2, zero if net objects count == 0 <% u0> // GUID3, zero if net objects count == 0 <% u0> // GUID4, zero if net objects count == 0 <% u0> // unknown, zero if net objects count == 0 OBJECT=XGStrategyAI.GetNumOutsiders.WGhost81 REL_OFFSET=4 // skip internal linker info [MODDED_CODE] <None> // empty default properties list <NullRef> // NextRef <% s1> // ArrayDim <% s0> // ElementSize <% u0x00000000> // flags L <% u0x00000000> // flags H <None> // CategoryIndex <NullRef> // ArrayEnumRef (had to add spaces after % symbol, otherwise forum engine mistakes it for some evil hacker code :smile: ) There isn't a single "raw" reference, so it is pretty safe and compatible, but to keep compatibility, one must reference new objects using pseudo-code only. Example mod file produces ready-to-use object, as linking is done automatically, i.e. new local var XGStrategyAI.GetNumOutsiders.WGhost81 was added to XGStrategyAI.GetNumOutsiders children list by the tool. Right now if name or object is already exists, PatchUPK outputs a warning and continues patching. This is good for modding purposes, but may not be so good for distributing mods. Although the case of two mods adding the exact same variable should be rare. I haven't tested it on any packages other than scripts, but I hope it will work for maps. This way Kismet scripts can be heavily modified and we could finally have hard Temple Ship mission. (Yes, I do remember how this all started. :smile: ) Edited April 20, 2014 by wghost81 Link to comment Share on other sites More sharing options...
wghost81 Posted April 22, 2014 Author Share Posted April 22, 2014 Thanks to Peasly Wellbott's bug-reports, white-spaces handling will be much better in the upcoming patcher version. Patcher will now recognize all white-space characters, not just spaces (" "). And tokens will no longer be space-sensitive, so you could do things like that:[ADD_NAME_ENTRY] <%u 9> // string length <%t "WGhost81"> // ASCII null-terminated string <%u 0x00000000> // flags L <%u // comments inside tokens! 0x00070010 // yes, you can do this now! :) > // flags H Link to comment Share on other sites More sharing options...
dubiousintent Posted April 22, 2014 Share Posted April 22, 2014 Ooo! That IS nice. But what if you need to have white-space recognized, such as in Localization, dialog, or names? Any escape characters? -Dubious- Link to comment Share on other sites More sharing options...
wghost81 Posted April 22, 2014 Author Share Posted April 22, 2014 dubiousintent, ADD_NAME_ENTRY example shows a new text (string) constant feature: <%t "WGhost81">Spaces are perfectly legal for text strings, so patcher will not "eat" them. This means, code like this <%t "some text with spaces">will be processed correctly. Furthermore, quotes are legal too: <%t "some "text" with spaces">This will result in a string some "text" with spacesAnd this <%t ""some text with spaces"">will result in "some text with spaces"It all works like this now: - Patcher extracts a next token from the stream, starting with '<' and ending with '>'. This allows for all kinds of white-space separators and comments inside tokens. - Comments are discarded while reading mod file, but spaces stay in place. After token is extracted, patcher "eats" all the white-space characters until the end of the token OR until delimiter character is encountered. For now there is one delimiter " (quotation mark). This allows to keep white-spaces in text strings intact. - If %t code is used, patcher extracts a string constant by extracting a sub-string between first occurrence of " and the last occurrence of ". This allows to keep quotation marks (") in strings intact. Link to comment Share on other sites More sharing options...
dubiousintent Posted April 22, 2014 Share Posted April 22, 2014 Excellent. Thanks for the clarification. -Dubious- Link to comment Share on other sites More sharing options...
wghost81 Posted April 23, 2014 Author Share Posted April 23, 2014 (edited) I am trying to test new objects with actual mod before a release to make sure it works properly. I'm currently working on Display XP, PsiXP and Mobility in Barracks mod for EU. It will allow me to test new variables as well as new text constants. So far so good: game's not crashing. :smile: XSHAPE works strange with expanded packages, though: it updates hashes correctly (and game runs correctly), but generates error 16 in the end. But working with new objects rises a lots of question. Especially mod distribution related. First question is: how to unistall such a mod? Obviously, deleting a new objects is a bad idea, as there might be subsequently installed mods with new objects and deleting previous objects will shift indexes and mix up all the references. And reinstalling is a bit problematic too... I've came to two possible solutions now: 1. Make a new global PERMANENT key, which will disallow uninstall info tracking and write something like "Sorry, but mod author decided that uninstall procedure is not safe for this mod." into uninstall file description. 2. Make a local PERMANENT key and allow mod authors to decide what should and what shouldn't be uninstalled. May not be safe, though, as it can result in broken packages, if author will make a mistake. With first approach one can use two files for mod distribution: pre-install file and install file. Pre-install file will make a permanent changes to game package, but no actual gameplay changes. And install file will contain actual mod changes. PS I know there are plenty of free variables to use for XP/Mobility display and final mod release will not have new objects. :smile: PPS And I just realized that adding a new object to already modified package will render all uninstall files for those previous modifications unusable, as uninstaller uses absolute package offset to write backup data. Problems, problems... But new objects are working, which is a good news anyway. :smile: Edited April 23, 2014 by wghost81 Link to comment Share on other sites More sharing options...
Recommended Posts