Leaderboard


Popular Content

Showing content with the highest reputation on 05/21/2021 in all areas

  1. 1 point
    Hey all So I wanted to place an invisible placeable on an enemy with his OnDeath script. So that I may have you loot him normally, but have another script fire after you've looted him and gotten the part to the quest. here's what I could think of... void main() { if ((GetJournalEntry("ache_saber") == 20)) { CreateObject(64, "ache_lens_cont", GetLocation(GetObjectByTag("infernal_sith", 0)), 0); } ExecuteScript("k_def_death01", OBJECT_SELF); } So the placeable is invisible and holds the part. Then dings the quest entry. Would this work or what am I forgetting/not doing right? I appreciate any help. EDIT: Hey nevermind. What I was doing worked. I just forgot to include the script that jumps the quest entry up. So then i moved the other items he drops to the invisible placeable so there's only one "Remains". Then looting that puts the quest up a notch. Woot. i did it!
  2. 1 point
    Sometimes, I learn more from mistakes than I do from getting it right the first time... My last post mentioned bug fixes. In an earlier post I described the structure of an NCS subroutine: Step 1 - The code that does the stuff you want Step 2 - Placing a return value on the stack Step 3 - Destroying local variables and temporaries on the stack Step 4 - Destroying arguments on the stack None of these steps are required, I'm almost certain I've seen an empty subroutine that simply returned. That means a missing step cannot impede the analysis of successive steps. So, how do we analyze the following? Subroutine 1601 1601 CONSTI 0 1607 CPTOPSP -3 1 1615 CPTOPSP -3 1 1623 JSR 298 1629 MOVSP -2 1635 RETN There is a single path through the code, that is there are no jumps so the ops execute in sequence. (Technically, the JSR is a jump. However, subroutine calls return to the op from which they were called and proceed to the next op in the sequence.) So, how does the stack change? The first three ops each add a value to the stack. The fourth op, a subroutine call, removes those three values from the stack. The subroutine returns void, i.e. nothing, so no return value is placed on the stack. And yet, the fifth op removes values from the empty stack... This tells us a few things: The fourth op is the last in Step 1 Subroutine 1601 does not place a value onto the stack after Step 1, so there is no Step 2 There are no local variables and no temporary values on the stack, so there is no Step 3 Therefore, the fifth op must be Step 4 Subroutine 1601 takes two arguments and returns void, i.e. void Sub1601(Arg0, Arg1) Let's look at a more complicated example: Subroutine 87299 87299 CPTOPSP -1 1 87307 CPTOPBP -171 1 87315 EQUALxx 87317 JZ 89610 CONSTx "NO COMBO SELECTED" 89631 CPDOWNSP -3 1 89639 MOVSP -1 89657 MOVSP -1 The first two ops each place a value onto the stack. The third removes those two values, and replaces them with a boolean (actually, an integer) result. The fourth removes the result, then performs a conditional jump. To simplify things, I've removed the conditional code branches. At this point, the stack is empty. The fifth op places a string onto the stack. The sixth copies the string down three positions from the top of the stack. However, there is only one value on the stack so this may be a return... The seventh op clears the stack. The eighth tries to remove a value from the empty stack. So, what does this tell us? The fourth op is the last in Part 1 Ops five and six may be Part 2 The seventh op is Part 3 The eighth and final op is Part 4 You'll notice the repeated use of "may". We should not assume all writes outside of the subroutine's stack are returns. Subroutine arguments also exist outside of the subroutine's stack, and this turned out to be the source of the bug. One of the subroutines analyzed wrote to its argument, and this was mistakenly marked as a return value. Thus, a subroutine that returned void, i.e. nothing, but also modified an argument messed up the analysis of any other subroutine that called it. The fix was simple enough: record the last write outside of the stack, along with the difference between the negation of destination and size of the stack. In the example above, the destination is -3 and the stack size is 1: -(-3) - 1 yields 2. When analyzing Part 4, the destruction of subroutine arguments, we compare the result to the size of the negation of number of arguments being destroyed: 2 vs -(-1), or 2 > 1. This tells us the final write is to a position greater than the furthest argument, thus it must be a return value. Subroutine 87299 takes one argument and returns one value. In short, we have to analyze Part 4 before we can analyze Part 2. Fixing bugs wasn't the only benefit. It's removed from the example, but there is an unconditional jump after the first MOVSP that transfers execution to the second MOVSP. This jump bypasses an op, creating dead code. I seem to have finally discovered the source of dead code: return statements. This also solves a different problem: I now know how to identify return statements in different parts of the subroutine. More in a future update!
  3. 1 point
    I want to keep the two versions identical as much as possible, so I won't be adding anything that already exists in TSL. Heartstopper Combo's probably the closest you're gonna get.
  4. 1 point
    So I just installed this a little while ago and think it's great. The feats seem very well done and very in line with the game in general and I love that they add uses for skills that often feel underutilized in K1. The only thing is, for some reason now I can't use medpacs from the inventory screen while in combat. Is that a thing that can happen with this mod and is there a way to fix it?