AmanoJyaku

Members
  • Content Count

    140
  • Joined

  • Last visited

  • Days Won

    6

AmanoJyaku last won the day on October 3

AmanoJyaku had the most liked content!

Community Reputation

93 Jedi Grand Master

1 Follower

About AmanoJyaku

  • Rank
    Jedi Knight

Recent Profile Visitors

1,037 profile views
  1. Sorry, I wasn't clear. You are correct about the compiler substituting defaults into the bytecode, the engine does not substitute at runtime. (I'm preparing a post to better explain NCS in case someone wants to port this to a different language, or make a better decompiler.) This is a silly example. But, it demonstrates the impossibility of identifying the type and value of an unused parameter from inside a function. I can't say I've seen this in practice. There are 2,500 files, I'm not looking at them all that closely. But I have to code for the possibility, or risk corrupting the stack.
  2. Sorry that this is taking longer than I wanted. I was lucky enough to get some contracts, but that also means very little free time. While a decompiler is an all-or-nothing program (hence the reason there won't be a beta), I can show off some sample output: It's not much, but you can see following: It identifies the NCS as a Kotor2 file, which is reliant on the code including K2 engine functions There are six subroutines _start(), which is automatically included by the compiler void main() void DamagingExplosion( object oCreature, int nDelay, int nDamage ) int GR_GetGrenadeDC(object oTarget) void NonDamagingExplosion(object oCreature, int nDelay) void KillCreature(object oCreature, int nDelay ) The types of return values are found by examining the called subroutine The types of parameters must be found by examining caller subroutines (strange as it may seem, there's no guarantee a parameter is used) The local variables are listed in the order in which they are created As simple as this may seem, it's been hell trying to figure out how NCS works due to limited documentation, time, and mental capacity (ðŸĪŠ). That said, I think I now know everything there is to know about NCS. Even how to deal with recursion (it took less than an hour), identifying vectors and structs (they do disappear in the bytecode, but there are code patterns to look out for), and handling certain errors in the game's code. So, the two major tasks left are: Including block scopes, e.g. if-else and while statements (I can identify them, I just haven't put them in among the locals) Handling expressions, commonly known as operator precedence and associativity, e.g. int d = (a + b) * c
  3. You attack the Sith throughout the game with Bastila in your party, and none of them says "Lord Malak wants her captured alive!" Malak surely wouldn't prioritize a soldier or officer over Bastila, it's obviously game mechanics. So, the limited game mechanic means Sith should attack Bastila on sight. OTOH, the Sith officers and soldiers are often stupid...
  4. It's time for a monthly update, and I said I might have a beta ready by now. Well, there won't be a beta. Will have more news next week.
  5. @Salk I preferred your version! Your accent is great, and the professional seemed lifeless. Did he view the scene in-game to see what was happening? @Sith Holocron Nice job!
  6. I thought Adrenas' excuse was an interesting one. I never considered the possibility that a human/near-human species would have grown up in a region speaking something other than Galactic Basic. I wish this was expanded on since he says he can speak Galactic Basic, just with a thick accent. It's understandable that he doesn't since he'd be made fun of, which would be a sign of weakness among the Sith.
  7. I considered that, but the differences are obvious and the detection simple. Are you aware of any pitfalls, or are you just being cautious? This is a beta release, there's plenty of time to change functionality. Given the fact that one file out of 2,500 has a do-while loop, it's low priority. I'll get around to it after more pressing matters are dealt with. Thanks, I thought as much. I first saw it in use destroying two elements of a vector, so I figured its purpose was for destroying unused elements of aggregates. I just need to identify which elements are preserved.
  8. @JCarter426 Thanks! I'll look at them later just to be sure I haven't missed anything. I was supposed to do it earlier, I just forgot about it until I was Force Persuaded to. 😋
  9. No, there isn't. That's why I had to write a detection algorithm.
  10. Sometimes, I learn more from failure than from success... I spent two weeks troubleshooting an algorithm that didn't always work. So, I added some functionality to assist in diagnosing the problem. Which lead to a few features updates! Directory Mode Now, when you supply a path the type is detected as either a file or directory. If it's a directory, all subdirectories are scanned and all files are processed! Version Detection The algorithm was fine, the problem was the input. I was using K2 function definitions, some of which had changed from K1. Now, NCS files are identified as K1 or K2! Conditional Input Detection The algorithm in question was alluded to in the September 4 post section about control structures. You will often see code like this: This is a pain to parse. The programmer sees one if statement, but the NCS file has 15 potential if statements! Seven of those appear to be extra, I haven't tested the logic to see if I can safely remove them from the compiled code. Still, that leaves us with eight potential if statements [e.g. if (sModule == "851NIH") { /*do stuff*/ }], which must be evaluated to see if they can be combined. That's what the algorithm does. And now that K1 and K2 functions are correctly identified, the algorithm correctly combines them as input to the actual if statement! To Do That leaves the following tasks: Evaluation of switch statements I haven't done this yet because ignoring them doesn't change the way the rest of an NCS file is processed, and my time is better spent on other tasks Evaluation of for and while loops They look identical, with the only potential difference being an incremented or decremented value at the end of a for loop Now that the algorithm described above has been completed, it should be easy to determine the rest of the code that makes a for loop unique I've temporarily given up on do-while loops because only one file has one, and I'm not entirely certain it's in the compiled NCS file Merging the algorithm with the virtual stack Once all control structures have been correctly identified, it will be necessary to identify variables created and destroyed inside scopes This will allow for the identification of subroutine input parameters and return values I've avoided using the virtual stack since I believe this is what has caused problems working with recursive functions for other decompilers Evaluating subroutines This is a big one, because callee input parameters and return values affect the caller subroutines I've been hard-coding both as a shortcut, but that only works for the files I'm currently testing Figuring out the DESTRUCT op code I've seen this used to destroy variables on the stack that aren't necessary, but prevent the top-of-stack behavior used by NCS Although this shouldn't be necessary, since the desired variable could just be copied to the top of the stack using the CPTOPSP op code... I should clarify that the algorithm does more than detect conditional input. It combines NCS op codes that make up NWScript statements. For example: RSADDS CPTOPSP -8 4 string IntToString(int) CPDOWNSP -8 4 MOVSP -4 Is correctly grouped as: string String = IntToString(Int);
  11. Notorious RBG

  12. The short answer is we'll never know because the game was unfinished. It was supposed to be larger. MUCH larger. But LucasArts wanted the game released in time for Christmas, so the game's development was cut short by almost a year. The budget was cut, too. The reason is shortly before TSL came out, LucasArts was restructured and a lot of their game development was canceled. Even before the restructuring, BioWare saw trouble and passed on developing the sequel. They recommended Obsidian, who had worked with them in the past. Unfortunately for Obsidian, plotting of TSL was started BEFORE KoTOR was finished and LucasArts refused to allow Obsidian access to the developing game. When KoTOR finally came out Obsidian had to go back and redo material that didn't fit with the original game's story. They had to start over, giving them even less time to write the story. This is the reason for so many plot holes and unfinished content, which is why modders have been working to restore whatever they could find. KoTOR and TSL are examples of what happens when a company (LucasArts) has crappy management. A whole book was written about it, in fact.
  13. @DarthParametric I did say I will not fix the game scripts, right? When I'm done with the decompiler, I will look into each script to determine what, if anything, needs to be fixed. It's entirely possible that the NCS files are different from the NSS files, such as k_trp_generic which has a bit of dead code. Of course, with 2,500+ files I'm in no rush to try and fix things. Especially since I haven't even completed the decompiler. Which now has a name, btw: FEANCS. You get a cookie if you can figure out the origin.
  14. Yes, because identification of the mine level occurs inside the if block. The problem is the if condition to get to that block always evaluates to "true". int TRAP_BASE_TYPE_POISON_GAS_MINOR = 9; int TRAP_BASE_TYPE_POISON_GAS_AVERAGE = 10; int TRAP_BASE_TYPE_POISON_GAS_DEADLY = 11; nTrapID == TRAP_BASE_TYPE_POISON_GAS_MINOR || TRAP_BASE_TYPE_POISON_GAS_AVERAGE || TRAP_BASE_TYPE_POISON_GAS_DEADLY (nTrapID == 9) || 10 || 11 (true or false) || true || true In practice, this isn't a problem because it's the last statement in the chain of if-else statements. By this point, the only mine type that hasn't been checked is poison gas. The condition isn't even necessary, since it must be a poison gas mine. However, if the poison gas test was ahead of any other mine type test then all subsequent types would be treated as poison gas. //FLASH STUN MINE if( nTrapID == TRAP_BASE_TYPE_FLASH_STUN_MINOR || nTrapID == TRAP_BASE_TYPE_FLASH_STUN_AVERAGE || nTrapID == TRAP_BASE_TYPE_FLASH_STUN_DEADLY ) {} //GAS POISON TRAP //BAD!!! else if(nTrapID == TRAP_BASE_TYPE_POISON_GAS_MINOR || TRAP_BASE_TYPE_POISON_GAS_AVERAGE || TRAP_BASE_TYPE_POISON_GAS_DEADLY) {} //FRAGMENTATION MINE else if(nTrapID == TRAP_BASE_TYPE_FRAGMENTATION_MINE_MINOR || nTrapID == TRAP_BASE_TYPE_FRAGMENTATION_MINE_AVERAGE || nTrapID == TRAP_BASE_TYPE_FRAGMENTATION_MINE_DEADLY) {} //LASER SLICING TRAP - THIS IS NOW THE PLASMA MINE else if(nTrapID == TRAP_BASE_TYPE_LASER_SLICING_MINOR || nTrapID == TRAP_BASE_TYPE_LASER_SLICING_AVERAGE || nTrapID == TRAP_BASE_TYPE_LASER_SLICING_DEADLY ) {} I'm being a nitpick, because the game is unlikely to be modified to add new mine types. But, with things like Xoreos it's not impossible.
  15. You're saying that they aren't attacking you like they're supposed to? It could be they didn't see you, you have to be in their line of sight I think. You could force the issue by killing Saquesh and turn everyone hostile. 😁