jmathgun Posted January 28, 2021 Share Posted January 28, 2021 *I have updated some of the code and im just checking for errors so i might have fixed it myself* hi guys I have been looking around for an auto looting mod for new vegas and have had trouble finding one with all the features I wanted. I was hoping to find one that came up with a message in the corner telling you what you picked up otherwise I find myself constantly checking if its working or not and also not knowing what I have picked up is a pain.I also wanted it to automatically pick plants. I could not find anything with those features for new vegas. I did find auto loot enhanced (https://www.nexusmods.com/newvegas/mods/42631) but again it does not have the feature I want. So I figured if it does not have it then I will add it (the creator of the mod has stated in the comments of his mod that he is ok with anyone trying to improve it). I would like to state though that I have never created a mod or edited one before beyond changing textures in a mod, never touched coding so this is a first for me though I do know a little about coding. anyway the problem I have bumped into is that the auto harvest mod is now not collecting from npc bodies and I cannot figure out why. it collects items dropped on the floor and I managed to successfully get it to collect plants (turns out the code was in there but only one plant was added) and I also added messageex commands than it works fine. I have noticed that it will not collect items when im standing next to the bodies so it seems to be stuck trying to collect from the bodies. there is also a code that will tell you with messageex if there is a gun nearby without picking it up here is a section of the code for bodies. im pretty sure its actually a problem with all containers but bodies were the ones I was testing with and im presume if I can fix this code I can fix the others. Ref NPCR ;npc body Ref InvPos ;Inventory position in the body Ref Invcount ;number of unique items in body Ref Lootr ;current selected item Ref Lootname ;Ref I added to store the in game name of the current item selected Ref Lootcount ;Ref I added to store the amount of current item selected short XChem ;variables to indicate item is various items if >= 0 pick up item short XAlchC short XDrink short XAlch short XFood short XHunger short XMag short XAlchM short XThirst short XVeno short XEW short XExpl short XGun short XAmmoM short XBook short XEPlace short XEThrow short XCMNY short XMsc short XMscEW short XMscExpl short XMscGun short XMscC short XMscQ set NPCR to GetFirstRef 42 1 0 ;targets npc body Label 42 ;loop 42 start if IsFormValid NPCR ;validity check if (Player.GetDistance NPCR < 201) && (NPCR.GetDisabled == 0) && (NPCR.GetDead == 1) ;if player under a certain distance and body not disabled and body dead then: if ALEnhGKey ;toggle option in mcm? NPCR.RemoveAllTypedItems player 1 1 46 endif if ALEnhGNote NPCR.RemoveAllTypedItems player 1 1 49 endif if ALEnhGIMOD NPCR.RemoveAllTypedItems player 1 1 103 endif ;removes items and gives to player? set InvPos to 0 ;initial inventory position Label 210 ;loop 210 start set InvCount to NPCR.GetNumItems ;sets inv count to inv size if InvPos < InvCount ;if selected item position less than inv size then set LootR to NPCR.GetInventoryObject InvPos ;sets current selected item as the item of the current position Set Lootname to LootR.getbaseobject ;I added to get item name Set Lootcount to Lootr.getrefcount ;I added to get item amount if ALEnhGChem ;global variable to indicate mcm menu checkbox is ticked? (pick up chems)? set XChem to ListGetFormIndex ALEnhLChem LootR ;checks if loot is in the chems list else returns -1 else set XChem to -1 ;if the chems checkbox is unticked automatically sets not to pick up endif ;below is a repeat of the previous but for different lists and items if ALEnhGAlchC set XAlchC to ListGetFormIndex ALEnhLAlchC LootR else set XAlchC to -1 endif if ALEnhGDrink set XDrink to ListGetFormIndex ALEnhLDrink LootR else set XDrink to -1 endif set XAlch to ListGetFormIndex ALEnhLAlch LootR if ALEnhGFood set XFood to ListGetFormIndex ALEnhLFood LootR else set XFood to -1 endif set XMag to ListGetFormIndex ALEnhLMag LootR if ALEnhGAlchM set XAlchM to ListGetFormIndex ALEnhLAlchM LootR else set XAlchM to -1 endif if ALEnhGVenom set XVeno to ListGetFormIndex ALEnhLVenom LootR else set XVeno to -1 endif if ALEnhGEW set XEW to ListGetFormIndex ALEnhLEW LootR set XMscEW to ListGetFormIndex ALEnhLMiscEW LootR else set XEW to -1 set XMscEW to -1 endif if ALEnhGExpl set XExpl to ListGetFormIndex ALEnhLExpl LootR set XMscExpl to ListGetFormIndex ALEnhLMiscExpl LootR set XEPlace to ListGetFormIndex ALEnhLExplPlace LootR set XEThrow to ListGetFormIndex ALEnhLExplThrow LootR else set XExpl to -1 set XMscExpl to -1 set XEPlace to -1 set XEThrow to -1 endif if ALEnhGGun set XGun to ListGetFormIndex ALEnhLGun LootR set XMscGun to ListGetFormIndex ALEnhLMiscGun LootR else set XGun to -1 set XMscGun to -1 endif if ALEnhGAmmoM set XAmmoM to ListGetFormIndex ALEnhLAmmoM LootR else set XAmmoM to -1 endif set XBook to ListGetFormIndex ALEnhLBook LootR set XCMNY to ListGetFormIndex ALEnhLCMNY LootR set XMsc to ListGetFormIndex ALEnhLMisc LootR if ALEnhGMiscC set XMscC to ListGetFormIndex ALEnhLMiscC LootR else set XMscC to -1 endif if ALEnhGMiscQ set XMscQ to ListGetFormIndex ALEnhLMiscQ LootR else set XMscQ to -1 endif if ALEnhGCons set XHunger to ListGetFormIndex ALEnhLHunger LootR set XThirst to ListGetFormIndex ALEnhLThirst LootR else set XHunger to -1 set XThirst to -1 endif if ALEnhGPros if (GetType LootR == 40) && (GetWeight LootR != 0) if (ListGetFormIndex ALEnhLExplPlace LootR < 0) && (ListGetFormIndex ALEnhLExplThrow LootR < 0) && (GetValue LootR / GetWeight LootR >= ALEnhGRatio) ;this works fine, checks weapon weight and rather than pick it up it notifies that there is a weapon MessageEx "Weapon available." endif endif endif if (XChem >= 0) || (XAlchC >= 0) || (XDrink >= 0) || (XAlch >= 0) || (XFood >= 0) || (XMag >= 0) || (XAlchM >= 0) || (XVeno >= 0) || (XEW >= 0) || (XExpl >= 0) || (XGun >= 0) || (XAmmoM >= 0) || (XBook >= 0) || (XCMNY >= 0) || (XMsc >= 0) || (XMscEW >= 0) || (XMscExpl >= 0) || (XMscGun >= 0) || (XMscC >= 0) || (XMscQ >= 0) || (XEPlace >= 0) || (XEThrow >= 0) ;if the current item scored greater than -1 then NPCR.RemoveItem LootR 1 ; removes item from body Player.AddItem LootR 1 1 ;adds item to player Messageex "you took %.0f %n's" Lootcount Lootname ;I added this to indicate when picking things up elseif (XHunger >= 0) && (Player.IsHardcore == 1) && (Player.GetAV Hunger >= ALEnhGHunger) && (Player.HasMagicEffect RestoreStarvationLevel == 0) ;checks if player is in hardcore and feeds them if hunger is above certain amount NPCR.RemoveItem LootR 1 ;repeat of above Player.AddItem LootR 1 1 Player.CastImmediateOnSelf LootR ;consumes item instead messageex "you consumed %n" Lootname ;message i added to indicat consumption Player.RemoveItem LootR 1 1 ;removes item from player inventory elseif (XThirst >= 0) && (Player.IsHardcore == 1) && (Player.GetAV Dehydration >= ALEnhGThirst) && (Player.HasMagicEffect RestoreDehydrationLevel == 0) NPCR.RemoveItem LootR 1 ;repeat of above for thirst Player.AddItem LootR 1 1 Player.CastImmediateOnSelf LootR messageex "you consumed %n" Lootname Player.RemoveItem LootR 1 1 else set InvPos to InvPos + 1 ;adds one to counter (possibility of missing items as item count will change? though code repeats so may not matter) endif Goto 210 ;end loop endif endif set NPCR to Pencil01 ;out of date fix to problem according to wiki its been patched. see no need to change it as it should have no effect set NPCR to GetNextRef ; go to next body Goto 42 ;loop code again endif I added all the comments on the code as there were none before, it was very difficult to figure out exactly what everything meant. any help would be appreciated, if needed I can upload the script in so people can troubleshoot it themselves. Link to comment Share on other sites More sharing options...
dubiousintent Posted January 29, 2021 Share Posted January 29, 2021 (edited) All "Actors" (NPCs and Creatures) are actually "containers". (Unlike "clutter" which are items lying around on the ground.) Which means you have to "open" them first, and then "walk through" their inventory contents. Take a look at how "Loot Menu for FNV" handles the issues surrounding them. (Gribbleshnibit8 knows his stuff.) -Dubious- Edited January 29, 2021 by dubiousintent Link to comment Share on other sites More sharing options...
jmathgun Posted January 30, 2021 Author Share Posted January 30, 2021 All "Actors" (NPCs and Creatures) are actually "containers". (Unlike "clutter" which are items lying around on the ground.) Which means you have to "open" them first, and then "walk through" their inventory contents. Take a look at how "Loot Menu for FNV" handles the issues surrounding them. (Gribbleshnibit8 knows his stuff.) -Dubious-Ah, Thanks for the assistance. Luckily since most of the code was already written most of that was already handled, I just could not get the count to work. But knowing that now seemed to have sorted it out. I then had the problem of rather than telling me how many items it was picking up it was counting down from the amount instead. Luckily that was just a IF function loop problem so it was a matter of ensuring it was in the right place in the loop. I have since managed to also add a Weight/Value ratio so now it will pick up any item that matches the setting you can set in the mcm, all i gotta do now is actually put details of what each option is in the mcm because the original author only posted the details on the mod comments. Link to comment Share on other sites More sharing options...
jmathgun Posted January 30, 2021 Author Share Posted January 30, 2021 ok so now I have a new problem with a small section of code.... if ALEnhgItemval && (lootr.gettype == 24) || (lootr.gettype == 25) || (lootr.gettype == 26) || (lootr.gettype == 29) || (lootr.gettype == 31) || (lootr.gettype == 40) || (lootr.gettype == 41) || (lootr.gettype == 47) || (lootr.gettype == 52) || (lootr.gettype == 103) ;This is the bit thats broken. set itemcheck to listgetformindex ALEnhbanneditems LootR If Itemcheck <= 0 If (GetValue LootR / GetWeight LootR >= ALEnhGRatioitems) Set XItemval to 1 else Set XItemval to -1 endif else set Xitemval to -1 endif endif A couple of notes.ALEnhgItemval is a mcm option so it will always be 1 in this caseLootR is the item in the containerItemCheck was put in to ensure the item was one the player was supposed to have and ALEnhbanneditems is the list that it checks against (I had a moment earlier where I stole ED-e's electric zap)and the itemvalue stuff already works by itself When I added the lootr.gettype section it just stopped items from being picked, I know the script is looking at the items as I put in a rudimentary debug to print to console each time it selected a different item.in this particular case it refused to pick up a fission battery and a hat (cant remember which type) from two different containers) even though it had before I put the code in. I was hoping to put in something that would check if the item was one that would usually be picked up because it had picked up something called technical armor 1, and im pretty sure it should not have, though feel free to correct me if im wrong. so all of those are the form types of regular items24, 0x18:Armor25, 0x19:Book26, 0x1A:Clothing29, 0x1D:Ingredient40, 0x28:Weapon41, 0x29:Ammo47, 0x2F:Ingestible103, 0x67:Weapon ModsIf any of these should not be there please say as that would be a great help. Link to comment Share on other sites More sharing options...
dubiousintent Posted January 31, 2021 Share Posted January 31, 2021 (edited) Compound conditionals get tricky to debug. I would restructure that code to have the "gettype" function return to a new variable on a separate line preceding the block (much more efficient) and everything after the "ALEnhgItemval" condition to be on separate lines comparing that new variable to the desired values, at least while debugging. The way it is now is not going to make that "and" condition apply to all the other "or" checks unless you group them together in parens: e.g. "ALEnhgItemval" condition AND (all the "OR" conditions). Your other "or" conditions are determining which items get "set Itemcheck to listgetformindex ALEnhbanneditems LootR" applied. And then everything else only applies if "Itemcheck" is "not set" (meaning not in the "excluded" list). It's more efficient and clearer logic to find matches in the list and "drop out" of the condition block (as in "do nothing") when they are to be excluded. Why does the remainder need to then be nested under the "or" determination condition block? Making it it's own conditional block at the same level once the exclusion determination takes place makes it easier to debug. -Dubious- Edited January 31, 2021 by dubiousintent Link to comment Share on other sites More sharing options...
jmathgun Posted February 1, 2021 Author Share Posted February 1, 2021 Well I should probably explain that. The preceding code does exactly as you say, there are various lists with items that are to be picked up so each item gets checked against that and then results in a variable to state whether any of those applies if (XChem >= 0) || (XAlchC >= 0) || (XDrink >= 0) || ect.... This is the check that is made at that point on, so if the item is a chemical in the chems list Xchem gets checked and then picked up. The section of code I place in is basically to pick up things that are not in those lists based on a value/weight slider, so while it is more efficient to add things to a list to pick up I instead want this to check every item against the form type. So the or block there is checking against each accepted form type, essentially using the formtype as the list to find matches in. I already looked up as many non player items that need to be on the banned list as I can and the Print to console bit that I mentioned allows me to spot things that need to be added as i playtest it.I should also probably say that I was experimenting alot with the if function as im not really used to coding so I was just trying to see what works. So I apologise if it is not done very well or is difficult to understand. Link to comment Share on other sites More sharing options...
dubiousintent Posted February 3, 2021 Share Posted February 3, 2021 "Efficiency" is something you learn, and not expected of anyone new to the process. But having it pointed out early makes it easier to develop the proper habits. A simple comparison operator (e.g. "<", "==") is more efficient than a compound operator (i.e. "<=", meaning LT "OR" EQ). Almost any comparison can be recast from needing a compound operator to a simple operator. Ex: "< 1" instead of "<= 0" (when dealing with booleans or integers). Also, it is a better practice to place constants on the left hand side of the equation, as in "(1 > variable)", though this is not really a concern in GECK scripting. (I'll admit to being more used to placing the variable first.) "Pseudo-code" is a way of expressing code that is not "syntax specific" to a particular language. It's a way of discussing code logic in abstract terms, without worrying about details of implementation. You just have to maintain an internal consistency to your terminology in that instance. So basically you are checking: gettype of current "item" If (itemtype in exclusion list) Then Don't do anything (or set flag 'XItemval' to 0) and exit from this process block to get next "item" Else ; not in exclusions, so "everything else" If (formtype1 matches itemtype) Then Do something generic like place in a container (or set flag 'XItemval' to 1) ElseIf (formtype2 matches itemtype) Then ; because it can only match one type Do the same generic thing ElseIf (formtype3 matches itemtype) Then Repeat the same generic thing ; repeat ElseIf condition as needed Else ; no formtype match to itemtype Do whatever (such as set flag 'XItemval' to -1) but at least spit out a debug message. EndIf EndIf If (XItemval > 0) Then Do 'matched' processing Else Do 'not matched' processing EndIf ; get next "item" Rather than repeating the "generic thing" line(s) for each conditional test, set a "flag variable" and after the IF block make another that just checks if the "flag is set and then performs that "generic thing". (Which is what you are doing; just pointing it out for others.) Any processing specific to a particular type should be done once that type has been identified in the "Then" portion. This way you are taking advantage of the list comparison early, and only when that fails are you progressing to the more labor intensive checking of particular formtypes for "everything else". The separate "IF/ELSEIF" tests are doing the same thing as the "OR" statements, but now it is easier to determine exactly which one is having a problem. "Checking everything" is very inefficient and can cause your script to become a bottleneck in the game if it runs too often (i.e. in "gamemode" blocks). But "IF/ELSEIF" tests between constant values and a variable are the most efficient "logical" thing the script does. A compound statement has to be completely evaluated (from left to right) before it determines if the result is "true". When each condition consists of a function call (e.g. "gettype") then each call adds to the overhead, slowing things down even more and introducing another potential point of "unexpected result". As for your "experiments" with conditional blocks: suggest you read over the "Best Practices" ad other genral tips under the scripting section of the wiki "Getting started creating mods using GECK" article. -Dubious- Link to comment Share on other sites More sharing options...
Recommended Posts