PDA

View Full Version : Auto hide weapons?


oscarksp74
09-18-2006, 03:10 PM
Just curious if there is a mod that "puts away" weapons when not in use for an extended period of time, in particular lightsabers (single hilt and short) and blasters? The only that I could find in searches had to do with cut scenes. Thanks in advance.

goldberry
09-18-2006, 04:46 PM
How I do it is that I don't use a second set of weapons. I hold a saber in my hands, and then while not in battle, i press X to swap weapon sets.

Darkkender
09-18-2006, 05:53 PM
To directly answer your question oscar no there isn't. The standard method is the same as is mentioned by goldberry above.

HouseOfAmon
09-18-2006, 11:49 PM
I think I got a way to do it...

NOTE: I am not going to bother looking up actual functions, or do it perfect, this is just a rough example.. So some code is real, some is just a place holder for the real functions I was too lazy to look up ;) ...

Also this is going to assume you will use a certain weapon for simplicity, you could probably make it with all weapons, but the code could be HUGE depending on the available functions, data types, etc....

===================

First make a new global number. call it WepTimer or something...

You will have to edit the K_Hen_heartbeat(or something like this its called) its the main heartbeat script with a similar code to the following..

The heartbeat runs every 6 seconds, so if you want to have the weapons put away after say 30 seconds, Set the multiplier variable(below) to 5, ie 5x6=30

Edit.. You might just wanna make your own script, then use the function ExecuteScript("myscript") in the Heartbeat.. Rather than putting the code directly into the heartbeat...

void main()
{

oPC=GetFirstPC;
Timer=GetGlobalNumber("WepTimer");
Timer2=0;
Multiplier=5;
Do1=0;
Fight=0;
ResetF=0;

If (GetIsInCombat(oPC, False)
{
SetGlobalNumber("WepTimer", 0);
Fight=Fight + 1;
}
else
{
Fight=ResetF;
EquipPC=Lightsaber <-- Use the real function here..
}

if (Do1=0)
{
DelayCommand(SomeFunction, 1.0)
Timer2=Timer2 + 1
Timer2=Timer2 * Multiplier;
SetGlobalNumber("WepTimer", Timer2);
}


if (Fight == 0)
{

if (WepTimer >= 30)
{
Do1=Do1 + 1;
UnequpPC("Lightsaber");
SetGlobalNumber("WepTimer", 0);
}

}

Something similar to this should make it work, but as I said, to make it work with all weapons might be really hard, but I havent really worked with equp/unequip functions, so I don't really know what data types they can store, etc.. So you might just have to poke around in nwscript.nss to find out..

if you can find a function that returns the name of the weapon, you could probably store it in a global string, then it would be somewhat easier..

Anyways, good luck. I offer the code to any who might want it, its partial, but should work, with just a little tidying up..

Peace...

stoffe
09-19-2006, 12:29 AM
I think I got a way to do it...
NOTE: I am not going to bother looking up actual functions, or do it perfect, this is just a rough example.. So some code is real, some is just a place holder for the real functions I was too lazy to look up ;) ...


The bigger part of the problem is not making the weapon go away though (which you can do by using DelayCommand() instead of a homemade timer, and GetItemInSlot() to get equipped weapons to remove), it's making it reappear the instant you enter combat without having to go to the inventory screen and re-equip the weapons for your party members by hand every time, which would become extremely annoying rather quick, IMHO.

Since there are no persistant object variables in the game (any more) there is, as far as I know, no way of storing which weapon the character had equipped before it was unequipped, so it can later be re-equipped. You could keep track of the tag but those don't need to be unique. So if the player has more than one weapon with the same tag in their inventory (which is fairly common) there is no guarantee the game would equip the correct one (with the proper upgrades in etc).

It's probably easier to use some mod that just disables the weapon visibility for non-combat idle and run/walk animations, though then the weapons would disappear as soon as you leave combat mode and not after a while.


The heartbeat runs every 6 seconds


As far as I can tell heartbeats run roughly every 3 seconds in the KotOR games, though it can vary a bit with a few tenths of a second depending on how busy the game is with other things, so it's not very precise to rely on using heartbeat count as a timer.

HouseOfAmon
09-19-2006, 06:35 AM
Well thats why I suggested using it for a unique weapon, just like a plain saber, because I figured tracking it might be problematic, that way it wouldnt matter if it used the right one, because if you only have one, thats the only one it can equip.. :)

And I thought this function did equp the item, "void ActionEquipItem(object oItem, int nInventorySlot, int bInstant=FALSE);)" doesnt it? So I dont see why that wouldnt work, but maybe I am confused on how it works.. Never tried it personally.. Though it would seem at least from the title, and description of the function that is what it does.. :)

As for the timer, I was just going by what I have been told, I thought scripts that ran for more than a few seconds terminated, so trying to use delaycommand 30.0 wouldnt work if thats true, which is why I attached a counter using the >= 30.. So it would keep rough track, of longer periods of time.. Though the multiplier would need to be 10, if it is every 3 seconds, I could of swore it was 6, but maybe that was NWN....

As for inventing a system, well in this case it seems you are right, since it doesnt keep a unique tag, so usually this will work, but in this case it does look pretty bad at least as far as making a glitch free fully functional version of this mod goes... Though you could use the tag, and link it to a global string in the script.. But it would as you said, not equip the correct one if you have more than one of the same weapon..

object Weapon=GetItemInslot();
string Wep=GetTag(Weapon)

SetGlobalString("SomeGlobal", Wep);

Or something similar...

Another thought is using the ai function that switches weapons with my code, just swap that function in instead of equipping/unequipping functions, just have them switch weapons to bare hands, it would be similar to the method goldberry mentioned only automated..

Anyways, Its not something I personally want, I just saw the post and thought it might be somewhat possible.. So feel free to correct any misconceptions above, I am just theorising here, won't hurt my feelings none... :D

Well always informative talking to you Stoffe,..

Peace

stoffe
09-19-2006, 07:14 AM
As for the timer, I was just going by what I have been told, I thought scripts that ran for more than a few seconds terminated, so trying to use delaycommand 30.0 wouldnt work if thats true, which is why I attached a counter using the >= 30.. So it would keep rough track, of longer periods of time.. Though the multiplier would need to be 10, if it is every 3 seconds, I could of swore it was 6, but maybe that was NWN....


Scripts usually only take a few milliseconds to execute, and if it takes longer than roughly 2 seconds the game engine assumes the script is stuck in an infinite loop and terminates it. The script executes, runs each line of code and then terminates immediately.

This has nothing to do with the working of the DelayCommand() function though, since what it does (AFAIK) is to place a scripting command on the stack with a timestamp for when it should be executed, effectively decoupling that scripting command from the script it belongs to. The DelayCommand() is not a loop, it returns almost immediately and allows the script to move to the next instruction regardless of how long the delay is. I.e. the script terminates, but any commands on the script command stack (placed there by any scripts) are executed when instructed.

This can lead to some odd bugs if you aren't careful in how you use DelayCommand(). For example, consider this line of code in a force power impact script:

DelayCommand(30.0, SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId()));


This will compile and run fine, but not yield the result you might expect. This line of code would be extremely unreliable since you have no way of knowing if the return value of GetSpellId() is the same after the 30 second delay as it is when the script running this line executes. If the character uses another forcepower in the meanwhile the return value of that function would change. Thus you'd need to keep in mind to do it like...

int iSpell = GetSpellId();
DelayCommand(30.0, SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, iSpell));

...which would save the return value of the function in a variable at script execution and then pass that value as parameter instead. Functions used to supply parameter values for other functions are executed when the delayed function executes, not when the original script runs.

For the same reason calling effect constructor functions directly in delayed ApplyEffectToObject() function calls might cause trouble with duration effects since they are decoupled from the force power since the effects technically aren't created in the impact script, making it undetectable by functions like GetHasSpellEffect() and GetEffectSpellId().

(There are a few similar pitfalls you have to keep in mind when using ExecuteScript() and AssignCommand(), but that's another topic. :))


Another thought is using the ai function that switches weapons with my code, just swap that function in instead of equipping/unequipping functions, just have them switch weapons to bare hands, it would be similar to the method goldberry mentioned only automated..


Switching active weapon slots work as long as you only need one of the slots while playing normally and don't have backup/fallback weapons for your party members. And only if this is for K2:TSL since KotOR1 does not have two sets of weapon slots. The original poster did not mention which game this was for. It would still be a bit ugly with the switching back part though unless you rely on the player to manually switch back to the secondary weapon slot, since there would be some delay involved in having a script do it, leaving the characters fighting barehanded during the first combat round.

HouseOfAmon
09-19-2006, 03:51 PM
So, it is possible for TSL at least, it would just be a little bit sloppy..

I really wish they had used a global scripting system like morrowind, I love scripting for that game, its very versatile.. If only we had that sorta control here..

It's very interesting how the delay command works btw, I did not know that, in fact, that opens a whole new line of thought for me, I could do some interesting things with that.. :)

Are there any limits to this? Can I set it to look for things over say a 2 minute period, or something ridiculous like that..What about area transitions, will it persist, and can I use multiple DelayCommand's over that time period, etc.

Could I have it check a variable, if my condition returns true, then have it, lets say execute a script? You could do some cool things if so..

Anyways thanks for the info Stoffe, its always a pleasure talking to you, and I always learn something new.. :D

Peace..

stoffe
09-19-2006, 04:41 PM
I really wish they had used a global scripting system like morrowind, I love scripting for that game, its very versatile.. If only we had that sorta control here..


NWScript and the Morrowind/Oblivion scripting language are very different. Overall you can do a lot more complex things with NWScript in regard to some things, while it's completely unable to do some things that are easy to do in Morrowind's script language. Overall I find the Morrowind/Oblivion language to be a lot more primitive and limiting though (but I suppose it depends what you want to use it for). :) But unfortunately NWScript was dumbed down considerably in the KotOR games compared to in Neverwinter Nights. Persistent variables were a lot easier and more powerful to work with in NWN. :(

NWScript is essentially event/trigger driven where something in the game runs a script, that script runs to the end and then stops, unlike the frame-based scripting in morrowind where scripts are run continually over and over until explicitly stopped, and one script for each object should handle everything.


Are there any limits to this? Can I set it to look for things over say a 2 minute period, or something ridiculous like that..What about area transitions, will it persist, and can I use multiple DelayCommand's over that time period, etc.


You can delay commands for as long as you wish, just keep in mind that they will stay on the script stack until they run and it is possible to fill up the script stack if you spam a lot of delayed commands.

Also note that the script stack, like most other game data, is loaded for a module. I.e. if you transition to another module the script stack is cleared and any delayed commands on it are never executed. The script stack is kept in savegames though, so if you reload a savegame any delayed script commands queued in the active module will be executed as they should.



Could I have it check a variable, if my condition returns true, then have it, lets say execute a script? You could do some cool things if so..


You can do that by declaring your own function which does the check and executes the script, and then delay that function call. For example, to run the script "st_cleanup" after 2 minutes if the global boolean variable "ST_DO_CLEANUP" is true, or otherwise retry after another 2 minutes, you could make a script like:

// ST: Forward-declaration of custom function.
void ST_DelayedCleanup(float fRetry);

// ST: Main function of the script...
void main() {
// ST: Run the ST_DelayedCleanup() function after 120 seconds.
DelayCommand(120.0, ST_DelayedCleanup(120.0));
}

// ST: Custom function to run after the delay.
void ST_DelayedCleanup(float fRetry) {
if (GetGlobalBoolean("ST_DO_CLEANUP")) {
// ST: Variable was set, run st_cleanup.ncs.
ExecuteScript("st_cleanup", OBJECT_SELF);
}
else {
// ST: Variable not set, run this function again after fRetry seconds.
DelayCommand(fRetry, ST_DelayedCleanup(fRetry));
}
}

HouseOfAmon
09-19-2006, 06:43 PM
NWScript and the Morrowind/Oblivion scripting language are very different. Overall you can do a lot more complex things with NWScript in regard to some things, while it's completely unable to do some things that are easy to do in Morrowind's script language. Overall I find the Morrowind/Oblivion language to be a lot more primitive and limiting though (but I suppose it depends what you want to use it for). :) But unfortunately NWScript was dumbed down considerably in the KotOR games compared to in Neverwinter Nights. Persistent variables were a lot easier and more powerful to work with in NWN. :(

NWScript is essentially event/trigger driven where something in the game runs a script, that script runs to the end and then stops, unlike the frame-based scripting in morrowind where scripts are run continually over and over until explicitly stopped, and one script for each object should handle everything.


Yeah, I agree, NWScript is very clearly a C++ styled language, and has a lot more functionality, and it is definetely the more complex language, but its implementation.. Well, sucks in a lot ways, if you added the morrowind global scripting aspects to a more complex language like this, the modding capabilities would be endless, though really they are anyways, never the less, I would like to be able to do some of things I could do in morrowind here..


You can delay commands for as long as you wish, just keep in mind that they will stay on the script stack until they run and it is possible to fill up the script stack if you spam a lot of delayed commands.

Also note that the script stack, like most other game data, is loaded for a module. I.e. if you transition to another module the script stack is cleared and any delayed commands on it are never executed. The script stack is kept in savegames though, so if you reload a savegame any delayed script commands queued in the active module will be executed as they should.

You can do that by declaring your own function which does the check and executes the script, and then delay that function call. For example, to run the script "st_cleanup" after 2 minutes if the global boolean variable "ST_DO_CLEANUP" is true, or otherwise retry after another 2 minutes..


Now this is very intriguing, I wish I had known this before, I am sure this will prove very usefull in the future..

Thank you for taking the time to answer my questions, I really do appreciate it, and I am adding all this information to my stack of mini tutorials I have gotten from you, I use them all the time as references whenever I am making mods that use the functions they pertain to.

Well, I will stop bothering you. For now.. hehe.. :)

Peace..