What's the point?
#1
Posté 07 février 2013 - 12:28
For example...
ExecuteScript("blah", OBJECT_SELF);
Blah = void main(){ AssignCommand(OBJECT_SELF, SpeakString("Blah"));}
OR
void Blah(object oSelf)
{
AssignCommand(oSelf, SpeakString("Blah"));
}
The only difference I see is that executescript is an absolute waste... Instead of simply using 1 script to handle things, you're using at minimum.. 2(and using mathematical logic, I have to assume that the computer having to only use 1 script file is cheaper then the computer having to use 2). It'd be great if executescript would transfer ownership of the script to the person it's being executed on(especially since it gives them the title of OBJECT_SELF), but it doesn't.
Does ExecuteScript do anything useful?
#2
Posté 07 février 2013 - 01:10
it does actuallyHighv Priest wrote...
It'd be great if executescript would transfer ownership of the script to the person it's being executed on(especially since it gives them the title of OBJECT_SELF), but it doesn't.
of course, it allows to change things globally, a good example of this is x2_pc_umdcheck scriptDoes ExecuteScript do anything useful?
or the script 70_spellhook thats coming with my unofficial patch - it allows to change anything in internal spellhook without need to recompile all spellscripts
#3
Posté 07 février 2013 - 01:16
#4
Posté 07 février 2013 - 01:31
hmm thats new for me, but not surprising actually. Unline signal event/assign command, delay command, the script being executed still counts towards current code block and instruction limit. To change it, a delay must be added. Then the ownership (now I know what you've meant - i thought you mean object_self) changes. Unfortunatelly with delay you lose other informations... but anyway my previous response still apply. Just instead ownership I meant caller.Highv Priest wrote...
It doesn't transfer ownership(at least for effects which are the only things that have "GetCreator" anyway). For instance if you use executescript on a PC from a module event. The effect applied is applied under the module and not the PC. The executescript as far as I can tell only sets the OBJECT_SELF to be the thing it's running on, but doesn't flag it as the owner of the script being run.
An another advantage of executecommand is when you need to change caller of the function and return value. You can't do that with assigncommand, at least not in original code block as AssignCommand is executed after the code block is ended.
#5
Posté 07 février 2013 - 01:51
Highv Priest wrote...
Ok as a standard scripter for a couple years, I have to ask... What's the difference between using ExecuteScript and using an in-script block of code?
For example...
ExecuteScript("blah", OBJECT_SELF);
Blah = void main(){ AssignCommand(OBJECT_SELF, SpeakString("Blah"));}
OR
void Blah(object oSelf)
{
AssignCommand(oSelf, SpeakString("Blah"));
}
The only difference I see is that executescript is an absolute waste... Instead of simply using 1 script to handle things, you're using at minimum.. 2(and using mathematical logic, I have to assume that the computer having to only use 1 script file is cheaper then the computer having to use 2). It'd be great if executescript would transfer ownership of the script to the person it's being executed on(especially since it gives them the title of OBJECT_SELF), but it doesn't.
Does ExecuteScript do anything useful?
All kinds of things. To transfer ownership, just AssignCommand the execution.
That aside, however, it's incredibly useful for flexibiity and flow control, and can save you a lot of duplicative scripting. In our generic modwide area entry script, for example, if we want to do area-specific things, we just ES them based on a variable set on the area:
/* execute specific onenter script if specified */ string sScript = GetLocalString(oArea, "Area_OnEnter"); if (sScript != "") ExecuteScript(sScript, oArea);
Likewise, our dynamic convo scriptset would not be possible without it:
#include "hg_inc"
#include "ac_dynconv_inc"
int StartingConditional () {
object oPC = GetPCSpeaker();
int i, nMax = GetLocalInt(oPC, "DynConv_Filter_Max");
for (i = 0; i < nMax; i++)
DeleteLocalInt(oPC, "DynConv_Filter_" + IntToString(i));
DeleteLocalInt(oPC, "DynConv_Filter_Max");
string sScript = GetLocalString(oPC, "DynConv_Script");
if (sScript == "")
return FALSE;
if (GetLocalInt(oPC, "DynConv_End")) {
DeleteLocalInt(oPC, "DynConv_End");
return FALSE;
}
/* execute script callbacks as needed */
if (GetLocalInt(oPC, "DynConv_Stage") == DYNCONV_STAGE_INIT)
ExecuteScript(sScript, oPC);
SetLocalInt(oPC, "DynConv_Stage", DYNCONV_STAGE_MENU);
ExecuteScript(sScript, oPC);
Ditto our encounter system:
void EncExecuteScripts (object oTrig, object oArea, string sType) {
struct SubString ss;
ss.rest = GetLocalString(oArea, "Enc" + sType + "Scripts");
string sScripts = GetLocalString(oTrig, "Enc" + sType + "Scripts");
if (ss.rest != "" && sScripts != "")
ss.rest += " ";
ss.rest += sScripts;
while (ss.rest != "") {
ss = GetFirstSubString(ss.rest);
ExecuteScript(ss.first, oTrig);
}
}
Our trap system:
void TrapExecuteScripts (object oTrig, object oArea, string sType) {
struct SubString ss;
ss.rest = GetLocalString(oArea, "Trap" + sType + "Scripts");
string sScripts = GetLocalString(oTrig, "Trap" + sType + "Scripts");
if (ss.rest != "" && sScripts != "")
ss.rest += " ";
ss.rest += sScripts;
while (ss.rest != "") {
ss = GetFirstSubString(ss.rest);
ExecuteScript(ss.first, oTrig);
}
}
It's also very useful for avoiding tangling includes, or for executing blocks of code you call a lot from different places - that is, it assists in modularity. We use it to call up our 'resurrection' event, for example, from all sorts of different scripts:
afx_deathcrown (23): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
afx_deathcrown (117): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
afx_deathcrown (206): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
afx_deathcrown (295): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
afx_deathcrown (323): AssignCommand(oJump, ExecuteScript("fky_deathprocess", oJump));
afx_deathcrown (354): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
afx_deathcrown (374): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
afx_deathcrown (395): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
afx_deathcrown (420): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
afx_deathcrown (436): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
ca_clr_massrez (32): AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
es_miracle (28): AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
ev_lifetransrod (34): AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
fky_chat_dm_comm (1123): AssignCommand(oDMTarget, ExecuteScript("fky_deathprocess", oDMTarget));//this includes dar, which is problematic because of crossincluding with hgll and chat
guildcontestport (48): AssignCommand(oGuilder, ExecuteScript("fky_deathprocess", oGuilder));
hell_amodeus_dth (32): AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
hg_inc (3899): AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
hg_inc (3936): AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
hg_respawn (245): AssignCommand(oArea, ExecuteScript("fky_deathprocess", oPC));
nw_s0_raisdead (119): AssignCommand(si.target, ExecuteScript("fky_deathprocess", si.target));
nw_s2_bardsong (204): AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
paragon_spell (1424): AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
randuse (65): AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
voyageskip (159): AssignCommand(oPC, ExecuteScript("fky_deathprocess", oPC));
Likewise, instead of rewriting a dozen different variations on the same code, you can generalize it, and make the similar code modular, to accept the variations. By way of example, we gave our Red Dragon Disciples a fear aura. Rather than rewriting all the special aura code we have to ensure that auras fire (they're normally very low priority), we simply route that ability through existing code:
ca_rdd_fearaura (27): AssignCommand(oPC, ExecuteScript("nw_s1_aurafear", oPC));
Likewise, our gnomish inventors use bombs that emulate spell effects:
x2_s3_bomb (61): if (GetTag(oItem) == "gi_it_bombs") { /* Gnomish Inventor Bombs - these rely on GetSpellInfo not firing until they ExecuteScript */
x2_s3_bomb (68): case GI_BOMB_CUSSER: ExecuteScript("x2_s2_cursesong", OBJECT_SELF); return;
x2_s3_bomb (69): case GI_BOMB_EASER: ExecuteScript("nw_s2_bardsong", OBJECT_SELF); return;
x2_s3_bomb (70): case GI_BOMB_BLOWER: ExecuteScript("x0_s0_gustwind", OBJECT_SELF); return;
x2_s3_bomb (71): case GI_BOMB_STICKER: ExecuteScript("x2_s0_stnehold", OBJECT_SELF); return;
x2_s3_bomb (72): case GI_BOMB_GREASER: ExecuteScript("nw_s0_grease", OBJECT_SELF); return;
x2_s3_bomb (73): case GI_BOMB_TEASER: ExecuteScript("x0_s0_laugh", OBJECT_SELF); return;
x2_s3_bomb (74): case GI_BOMB_MELTER: ExecuteScript("nw_s0_acidfog", OBJECT_SELF); return;
x2_s3_bomb (75): case GI_BOMB_RUMBLER: ExecuteScript("hgs_gen_sphere", OBJECT_SELF); return;
x2_s3_bomb (76): case GI_BOMB_NETTER: ExecuteScript("nw_s0_entangle", OBJECT_SELF); return;
x2_s3_bomb (77): case GI_BOMB_CRACKER: ExecuteScript("x2_s0_grtthdclp", OBJECT_SELF); return;
x2_s3_bomb (78): case GI_BOMB_SHOCKER: ExecuteScript("hgs_gen_sphere", OBJECT_SELF); return;
x2_s3_bomb (80): case GI_BOMB_CLAPPER: ExecuteScript("x2_s0_grtthdclp", OBJECT_SELF); return;
x2_s3_bomb (81): case GI_BOMB_SMOKER: ExecuteScript("qc_gi_smoker_aoe", OBJECT_SELF); return;
x2_s3_bomb (82): case GI_BOMB_WARPER: ExecuteScript("nw_s0_timestop", OBJECT_SELF); return;
x2_s3_bomb (83): case GI_BOMB_CRUNCHER: ExecuteScript("nw_s0_implosion", OBJECT_SELF); return;
x2_s3_bomb (84): case GI_BOMB_FUMER: ExecuteScript("nw_s0_wailbansh", OBJECT_SELF); return;
I could go on, and on, and on. It is one of THE MOST useful functions out there.
Funky
#6
Posté 07 février 2013 - 01:53
Highv Priest wrote...
It doesn't transfer ownership(at least for effects which are the only things that have "GetCreator" anyway). For instance if you use executescript on a PC from a module event. The effect applied is applied under the module and not the PC. The executescript as far as I can tell only sets the OBJECT_SELF to be the thing it's running on, but doesn't flag it as the owner of the script being run.
It does transfer ownership, Even for effects. If from a module event you execute a script on the PC and the script that is now running on the PC creates an effect, the PC will be the creator not the module.
#7
Posté 07 février 2013 - 02:16
The mod is already at 15992 resources and I'm having to delete/fix many things done by the previous owners(back when they asked me to continue work on it for their lack of desire to do it anymore) to be able to add new content. Thank you for the answer though. The global aspect of it definitely is a good purpose.
#8
Posté 07 février 2013 - 02:33
Lightfoot8 wrote...
Highv Priest wrote...
It doesn't transfer ownership(at least for effects which are the only things that have "GetCreator" anyway). For instance if you use executescript on a PC from a module event. The effect applied is applied under the module and not the PC. The executescript as far as I can tell only sets the OBJECT_SELF to be the thing it's running on, but doesn't flag it as the owner of the script being run.
It does transfer ownership, Even for effects. If from a module event you execute a script on the PC and the script that is now running on the PC creates an effect, the PC will be the creator not the module.
You must forgive me if I sound arrogant, but I know for certain that executescript does not change "GetEffectCreator" which is how I determine "ownership" of the script. Example =
if(GetLevelByclass(class_TYPE_ASSASSIN, oPC) >= 3)
{
ExecuteScript("bloodoath", oPC);
}
This script is applied both onrest and when weapons are unequipped, because we give an AC bonus for dual weilding and using large weapons(not that uncommonly). Assassins on our server receive an AC bonus relative to int mod(learned observation of combat methods and effective ability to deflect oncoming attacks based on perceived patterns is the explanation as to why they are given an AC bonus) Both events are module defined. On the weapon unequip this check is put to remove the AC bonus for weapons being removed:
while(GetIsEffectValid(eRemove))
{
if(GetEffectSubType(eRemove) == SUBTYPE_EXTRAORDINARY)
{
if(GetEffectType(eRemove) == EFFECT_TYPE_AC_INCREASE)
{
if(GetEffectDurationType(eRemove) == DURATION_TYPE_PERMANENT)
{
if(GetEffectCreator(eRemove) == oSelf) oSelf is the module here.
{
RemoveEffect(oPC,eRemove);
}
}
}
}
eRemove = GetNextEffect(oPC);
}
Now as you saw the executescript is being applied to the PC, which SHOULD transfer ownership of the effect to the PC, because the PC is defining, creating, and applying the effect. However it -doesn't-, the module is still considered the creator of the effect and between being stuck in exams and other problems I just decided to reapply the effect after weapon removal instead of figuring out what fool-proof method DOES transfer ownership. Although according to nwnlexicon(which is usually a pretty good resource) assigning an inner-include block of code with assigncommand does this, I couldn't be arsed to take the time testing it to find out until I get these real life problems out of the way.
#9
Posté 07 février 2013 - 02:44
#10
Posté 07 février 2013 - 02:57
#11
Posté 07 février 2013 - 03:04
I don't think that'd help any. ExecuteScript() pauses the current script, so it doesn't reset the TMI limit (though a DelayCommanded ExecuteScript() would). Splitting the same instructions up into multiple scripts also slows things down by working against the script cache.
#12
Posté 07 février 2013 - 03:19
My idea is to have "smart_ai_1", "smart_ai_2", "smart_ai_3", etc. All of these essentially running "highv_smart_ai" in an attempt to circumvent the TMI error being triggered from many AI triggering the same script.
#13
Posté 07 février 2013 - 03:30
// my_smart_ai.nss
void BlockOne()
{
// Do stuff
SetLocalInt(OBJECT_SELF, "AI_STATUS", 1);
}
void BlockTwo()
{
// Do more stuff
SetLocalInt(OBJECT_SELF, "AI_STATUS", 2);
}
void main()
{
switch (GetLocalInt(OBJECT_SELF, "AI_STATUS"))
{
case 0: BlockOne(); break;
case 1: BlockTwo(); break;
default:
DeleteLocalInt(OBJECT_SELF, "AI_STATUS");
return;
}
DelayCommand(0.01, ExecuteScript("my_smart_ai", OBJECT_SELF));
}
Modifié par Squatting Monk, 07 février 2013 - 03:31 .
#14
Posté 07 février 2013 - 01:56
#15
Posté 07 février 2013 - 03:42
Incorrect. Scripts fire sequentially. TMIs result from too much happening in a single script. They're also sort of beside the point, as they're easy to avoid. The larger problem is that you'll overburden your server.Highv Priest wrote...
That code actually does not avoid the problem. If you've ever done heavy work on your AI you'd know that TMI errors can be thrown out without infinite loops as a result of too many AI executing the same script at the exact same moment of time.
What are you using, custom ai, or j_ai? If j_ai, or something based on it, run it through the NWNTX compiler, or any non-standard bioware compiler. They'll pick up script errors - mostly declaration/function mismatches - that the default compiler misses. The main cause of TMIs with j_ai, however, is the execessive looping he does to optimize behavior. He made too many trade-offs of efficiency for the ability to micromanage. The more creatures you have present in combat, the more the loops iterate, and the more likely you'll get TMIs. That, not simultaneous execution, is why you see a correlation between number of spawns and TMIs.My AI is extremely heavy(spellcasting NPCs act like normal player spell casters, they know not to use spells that do nothing because you have immunity from class/armor/magical buffs, but here is the kicker! They don't have "automatic knowledge" of you being immune from items or non spell bonuses, but they do if you have immunity from spell bonuses. If you are receiving immunity from a non-magical source they will still pretend to case a spell at you to "realize" the spell doesn't work and if it's a magical buff then they know to try to strip it and if you're completely immune no matter what they do then they know to switch to something else, AI will team up on you with the leader speaking commands the players can see which adds to realism, IE = "Counterspell the cleric! Heal the bashers!").
That's because your 'fix' does nothing to address the TMIs.All of that stuff involves quick execution of many scripts and it does happen where a TMI STILL gets thrown out there at times.
[Edit] By the by, we found x2's ai to be a fair bit meaner than j_ai in many cases, though we still use a modded j_ai here and there. We had to add a lot of spell behaviors though, and not just for our custom spells.
Funky
Modifié par FunkySwerve, 07 février 2013 - 03:55 .
#16
Posté 07 février 2013 - 04:45
I know you consider me some jackass, but lets pretend for a second I've taken programming classes and know SOMETHING about nwn(though certainly not everything). The TMI errors result purely from too many of the NPCs executing the same script without regards to the script being executed. I tested this out by having 200 NPCs execute one script that simply had them count to 100(using a while loop). One of them could do it easily, 40 of them still no issue, 100 of them still not a problem, but once I reached about 150 of them doing it the system immediately put out a TMI error.
#17
Posté 07 février 2013 - 05:05
Ok, we can pretend that if you like. It doesn't change the fact that that the TMI limit is a per-script limit, or that nwn executes scripts serially, not in parallel.I know you consider me some jackass, but lets pretend for a second I've taken programming classes and know SOMETHING about nwn(though certainly not everything).
The TMI errors result purely from too many of the NPCs executing the same script without regards to the script being executed. I tested this out by having 200 NPCs execute one script that simply had them count to 100(using a while loop). One of them could do it easily, 40 of them still no issue, 100 of them still not a problem, but once I reached about 150 of them doing it the system immediately put out a TMI error.
What that test indicates is that each execution is doing something that creates more work for later executions. Could be any number of things - anything that causes loops to iterate more.
Funky
Modifié par FunkySwerve, 07 février 2013 - 05:06 .
#18
Posté 07 février 2013 - 05:47
As far as TMI could be various causes. Clearly many npc's trying to do something at the same time can cause lag, but it is not necessarily a TMI problem. I mean to say you can get a TMI with just a single individual script that simply has Too Many Instructions. I am no expert in this area, but my scripting is sufficiently poor to have dealt with a number of TMI's over the years and it never involved just the number of npc's running the script. Although it does seem resonable to suppose with almost 200 individuals running a script you will have problems. Imo the game is just not designed to have that many individuals running scripts. I had bats spawning continuously once due to overlooking having the spawning script discontinue operation if no PC was in the area. So there were around 200 bats fluttering around, lagged like Heck, but no TMI.
Regarding the facility of execute script: I suppose that question has been answered in that it is extremely useful, for any number of occassions.
In reference to your not wanting to sound arrogant. I would not worry about that too much as almost everyone here does that, and certainly they do not appologise for it.
As far as the ai goes I have done quite a bit with that. I think it is important to differentiate how the ai acts. Thus they have cowardly, ambusher, archer, stealth, etc.. though the standard ai is woefully inadequate, the approach is valid. Thus I have some monsters that are more aggressive, more intelligent, etc.. so they act differently. Actually my more intelligent monsters are less aggressive, which is logical though not always. So rather than try to the make the ai smart I merely give the more intelligent creatures more choices, which in some ways emulates intelligence as the player is less likely to be able to predict the behaviors of monsters or encounters with complete accuracy, thus making the ai seem intelligent. If you catch my meaning, if you get my drift.
Cheers!
Modifié par ffbj, 07 février 2013 - 06:03 .
#19
Posté 07 février 2013 - 05:59
No, it can't, not in the way he means. It's a very specific error put in by Bioware to halt execution of a script that exceeds 0x20000 instructions. It's an acronym for Too Many Instructions, and is meant as a last-resort block to prevent a runaway script from crashing a server. Acaos actually make a plugin for us that can lift the limit as high as 8 million, which you can find on the NWNX boards. It bears exactly zero relation to number of scripts executing at the same time, because nwn scripts cannot execute at the same time. The only thing in NWN that doesn't block is writes to bicfiles.ffbj wrote...
As far as TMI could be various causes.
People tend to treat TMI as some kind of generic 'script overload' error. It isn't, though it's certainly possible to both overload your server to the point of crashing while firing TMIs.
Funky
Modifié par FunkySwerve, 07 février 2013 - 06:10 .
#20
Posté 07 février 2013 - 06:05
Could be any number of things - anything that causes loops to iterate more.
But I think what he was saying in this specific instance reagarding the 200 creatures was that a TMI was caused because there were too many creatures, while the script(s) that where running would not cause a TMI otherwise, and I can see that happening.
Modifié par ffbj, 07 février 2013 - 06:09 .
#21
Posté 07 février 2013 - 06:06
Gotcha, thanks for the clarification.ffbj wrote...
I neant in the same way as you said this:
Could be any number of things - anything that causes loops to iterate more.
Funky
#22
Posté 07 février 2013 - 06:11
So if nwn doesn't execute scripts at the same time, why would 40 very simple heartbeats cause massive lag when 40 very slightly differently timed heartbeats would not.(the delay was between .01 to .40 based on their objecttostring ID in relation to the first).
#23
Posté 07 février 2013 - 06:14
ffbj wrote...
But I think what he was saying in this specific instance reagarding the 200 creatures was that a TMI was caused because there were too many creatures, while the script(s) that where running would not cause a TMI otherwise, and I can see that happening.
Sigh at dueling edits.
Highv Priest wrote...
If you've ever done heavy work on your
AI you'd know that TMI errors can be thrown out without infinite loops
as a result of too many AI executing the same script at the exact same
moment of time.
Funky
#24
Posté 07 février 2013 - 06:20
#include "NW_I0_GENERIC"
#include "x3_inc_string"
void main()
{
int nCreature, nNumber;
string sCreature = "";
string sMessage = (StringToRGBString("\\n AMBUSH !! \\n",STRING_COLOR_RED));
object oPC = GetEnteringObject();
object oArea = GetArea(oPC);
if (!GetIsPC(oPC))
return;
if (GetLocalInt(oPC,"Safe") == 1)
return;
if (GetLocalInt(oPC,"Ran") > 2 +d4(1))
return;//script will only run 3 times,plus d4 default would be 4
int iHd = GetHitDice(oPC);
if (d100() < 60 + (iHd))//set between 50-75. Lower means fewer spawns.
return;
//if (GetDetectMode(oPC) == DETECT_MODE_PASSIVE)//not actively searching.
//return;
object oTarget = oPC;
float fDistance = 2.0 + (iHd/2);//higher level notice things futher away
location lWP = GetRandomLocation(oArea,oTarget,fDistance);
location lTarget = GetLocation(oTarget);
//Cycle through PCs in area
object oPChp = GetFirstPC();
while (GetIsObjectValid(oPChp)||(oArea == GetArea(oPChp)))
{
if (oArea != GetArea(oPChp))
{
oPChp = GetNextPC();
}
iHd++;
iHd += GetHitDice(oPChp); //trying to add the pc's in the area hp
oPChp = GetNextPC();
}
if (iHd < 10)
SetLocalInt(oPC,"Spawn",1);
else if (iHd < 20)
SetLocalInt(oPC,"Spawn",2);
else if (iHd < 30)
SetLocalInt(oPC,"Spawn",3);
else
SetLocalInt(oPC,"Spawn",4);
if (GetIsNight())
{
SetLocalInt(oPC,"Spawn", GetLocalInt(oPC,"Spawn")+1);
}
if ( GetStealthMode( oPC ) == STEALTH_MODE_ACTIVATED )
{
SetLocalInt(oPC,"Spawn", GetLocalInt(oPC,"Spawn")-1);
}
if ((GetLocalInt(oPC,"Spawn")== 1) && (GetIsSkillSuccessful(oPC, SKILL_LISTEN, 5)))//easy
{
SendMessageToPC(oPC, "You Hear Something!");
GiveXPToCreature(oPC, 25);
switch (d4())
{
case 1: sCreature = "thugcn"; break;//resref of creature
case 2: sCreature = "madcrow"; break;
case 3: sCreature = "townperson"; break;
case 4: sCreature = "monkbd"; break;
}
for (nNumber = 0; nNumber < d3(); nNumber++)
CreateObject(OBJECT_TYPE_CREATURE, sCreature, lWP, FALSE);
object oCreature = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, lWP);
float fDistance1 = GetDistanceBetweenLocations(lWP, lTarget);
string sDistance = FloatToString(fDistance1, 2,0);
DelayCommand (3.0,SendMessageToPC(oPC, " Some noise, over there! " + sDistance + " metres away."));
DelayCommand (6.0, TurnToFaceObject(oCreature, oPC));
}
if ((GetLocalInt(oPC,"Spawn")== 2) && (GetIsSkillSuccessful(oPC, SKILL_SPOT, 15)))//harder
{
SendMessageToPC(oPC, "You Spot Something!");
GiveXPToCreature(oPC, 50);
switch (d4())//should be tougher creatures below
{
case 1: sCreature = "thugcn"; break;//resref of creature
case 2: sCreature = "monkbd"; break;
case 3: sCreature = "townperson"; break;
case 4: sCreature = "rioter003"; break;
}
//Randomly generate the number of monsters//
for (nNumber = 0; nNumber < d4(); nNumber++)//change d4 for more
CreateObject(OBJECT_TYPE_CREATURE, sCreature, lWP, FALSE);
object oCreature = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, lWP);
float fDistance1 = GetDistanceBetweenLocations(lWP, lTarget);
string sDistance = FloatToString(fDistance1, 2,0);
DelayCommand (2.5,SendMessageToPC(oPC, " Something, over there! " + sDistance + " meters away."));
DelayCommand (5.0, TurnToFaceObject(oCreature, oPC));
}
else if ((GetStealthMode(oPC) == STEALTH_MODE_DISABLED) && (GetIsNight ()) && (GetLocalInt(oPC,"Ran") < 3))
{
CreateObject(OBJECT_TYPE_CREATURE, "robber", lWP, FALSE);
DelayCommand (2.0, FloatingTextStringOnCreature(sMessage, oPC, FALSE));
}
if ((GetLocalInt(oPC,"Spawn")==3) && (GetIsSkillSuccessful(oPC, SKILL_LISTEN, 20)))
{
SendMessageToPC(oPC, "A faint sound reaches you!");
GiveXPToCreature(oPC, 100);
switch (d6())
{
case 1: sCreature = "thugcn"; break;//resref of creature
case 2: sCreature = "rioter003"; break;
case 3: sCreature = "townperson"; break;
case 4: sCreature = "youth01"; break;
case 5: sCreature = "maddog"; break;
case 6: sCreature = "monkbd"; break;
}
for (nNumber = 0; nNumber < d6(); nNumber++)
CreateObject(OBJECT_TYPE_CREATURE, sCreature, lWP, FALSE);
object oCreature = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, lWP);
float fDistance1 = GetDistanceBetweenLocations(lWP, lTarget);
string sDistance = FloatToString(fDistance1, 2,0);
DelayCommand (1.5,SendMessageToPC(oPC, " Something is moving, over there! " + sDistance + " metres away."));
DelayCommand (4.0, TurnToFaceObject(oCreature, oPC));
}
if ((GetLocalInt(oPC,"Spawn") == 4) && (GetIsSkillSuccessful(oPC, SKILL_SPOT, 25)))//etc...
{
SendMessageToPC(oPC, "Your highly attuned senses are alerted!");
GiveXPToCreature(oPC, 150);
switch (d6())//should be tougher creatures
{
case 1: sCreature = "harpy"; break;//resref of creature
case 2: sCreature = "robber"; break;
case 3: sCreature = "townperson"; break;
case 4: sCreature = "skeletondart"; break;
case 5: sCreature = "maddog"; break;
case 6: sCreature = "skeletonrapier"; break;
}
for (nNumber = 0; nNumber < d4(); nNumber++)
CreateObject(OBJECT_TYPE_CREATURE, sCreature, lWP, FALSE);
object oCreature = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, lWP);
float fDistance1 = GetDistanceBetweenLocations(lWP, lTarget);
string sDistance = FloatToString(fDistance1, 2,0);
DelayCommand (1.0,SendMessageToPC(oPC, " Some movement, over there! " + sDistance + " metres away."));
DelayCommand (4.0, TurnToFaceObject(oCreature, oPC));
}
else if ((GetStealthMode(oPC) == STEALTH_MODE_DISABLED) && (GetIsNight ()) && (GetLocalInt(oPC,"Ran") < 3))
{
CreateObject(OBJECT_TYPE_CREATURE, "robber", lWP, FALSE);
DelayCommand (2.0, FloatingTextStringOnCreature(sMessage, oPC, FALSE));
}
else if ((GetStealthMode(oPC) == STEALTH_MODE_DISABLED) && (GetIsNight ()) && (GetLocalInt(oPC,"Ran") < 3))
{
CreateObject(OBJECT_TYPE_CREATURE, "harpy", lWP, FALSE);
DelayCommand (2.0, FloatingTextStringOnCreature(sMessage, oPC, FALSE));
}
SetLocalInt(oArea,"Ran", GetLocalInt(oArea,"Ran")+1);
DelayCommand (400.0/ d4(2), ExecuteScript("ranspslistenslum",oArea));
DelayCommand (300.0, DeleteLocalInt(oArea,"Ran"));
}
I have many similar scripts that work fine but this one seems to be cranky. Maybe I just have a bracket in the wrong place. Now that I look at it maybe these lines have an uneeded bracket:
{
if (oArea != GetArea(oPChp))
//{maybe no bracket needed here.
oPChp = GetNextPC();
}
Modifié par ffbj, 07 février 2013 - 06:24 .
#25
Posté 07 février 2013 - 06:29
Sure. You can read the forums and listen to people who know. Or ask people who have worked on the engine and know. Or you could use the Omnibus to look for posts by people who put the engine together and know. You could also devise an experiment designed to execute two scripts at the exact same instant to see for yourself, but clearly your experimentation thus far has only lead you astray, so you'd have to be a little more rigorous. That's not an indirect knock at you, by the way - just yesterday I managed to convince myself that the custom SetEffectCreator NWNX function was only returning a valid creator until the end of that script - because I wasn't rigorous enough in my testing, and didn't insert enough debug code to figure out what was really going on.Highv Priest wrote...
Is there a way I could determine whether or not nwn is capable of executing scripts at the same time? \\
Because the engine can only do so much in a given amount of time. Saying that scripts execute serially is not saying you can't jam up your server with too much code - it still takes time to execute, and some individual instructions can cause massive lag spikes, like object creation, because they require a lot of other things to happen. I won't pretend much expertise when it comes to computers, but I'm absolutely certain about this, and I have neither the time nor inclination to shoot down every anecdotal scrap of evidence you've accumulated in support of your erroneous conclusion. Virusman could probably give you a more technical explanation, if you're curious - he's dealt with the game clock, among many other things.So if nwn doesn't execute scripts at the same time, why would 40 very simple heartbeats cause massive lag when 40 very slightly differently timed heartbeats would not.(the delay was between .01 to .40 based on their objecttostring ID in relation to the first).
If it's any comfort, I made the same mistake, way back when, not understanding serial execution or blocking. It grants a lot of clarity once you do, and allows you to figure out more of what's really going on. I'll see if I can hunt down GZ on the omnibus talking about it, if I can do so quickly.
Funky





Retour en haut







