Array command questions

Post » Thu Feb 17, 2011 12:19 am

Need some serious help understanding Arrays and the use of the array commands.

Scruggsywuggsy the ferret told me to PM him this thread LINK so he could help here instead of on the OBSE 19 thread.
But I may not PM him because I would like to see if anyone else can help on this as he is really swamped right now with the beta OBSE 19 and I feel bad about taking up his time on this.

This script will be included in an object script that I already am giving to all NPC that are classified as magic specialization.
This script is intended to change all the base spells it can find to multiply the elemental attacks by a modifier (in this test it will be 5).
For this test I am only trying to change the fire damage spells.


Ok what follows is a BOAT LOAD OF GUESSING on my part. I understand about 65% of this, but this is my first time trying to do OBSE arrays. But it is time for me to try to catch up with the new OBSE language anyway. What in the following will prevent the script from running?

array_var AdjustedSpellsshort indexshort countref ActorReflong damageshort DoonceBegin gamemodeif doonce == 0 set actorRef to getcontainer;---- This is not really going to be here as I already do this in the beginning of the rest of the script. But I left this in so that I would not confuse anyone.set doonce to 1  if ActorRef.isactor == 1    if AcrotRef.ismovingforward == 1;---------------- This is a little trick I came up with to test if the NPC is alive, not parallelized, not unconscious, not      let AdjustedSpells := ActorRef.GetSpells;     disabled, not stuck and is valid all in ONE check! IT tastes great and is less filling!    endif;                                          Works 99% of the time thus I only use it in cases where if it does not work it is not harmful just if not a little inconvenient.   endifendifif eval (ar_Size AdjustedSpells) > 0  ForEach index < ar_Size AdjustedSpells;-------------   Loop through all spells in the list    if CompareName "{}" SpellRef != 1;--------------------  check to see if the spell has already been processed once before.      set count to GetMagicItemEffectCount SpellRef       while (count)       set count to count - 1            if GetNthEICode spellRef count == FIDG               set Damage to ( GetNthEIMagnitude SpellRef count * 5 );-------------   multiply the magnitude by 5 to make spells 5 times normal damage.               SetNthEIMagnitude Damage SpellRef count                     if CompareName "{}" SpellRef != 1.                          AppendToName " {}" spellRef;-------------   append the name of the spell with the symbol {} so players and the script knows the spell has been processed once                     endif                 loop           endif     Set index to index + 1     endifendifend

User avatar
RaeAnne
 
Posts: 3427
Joined: Sat Jun 24, 2006 6:40 pm

Post » Wed Feb 16, 2011 2:38 pm

GetSpells returns an Array with the spells, that would look like:
[0] - Spell A FormID
[1] - Spell B FormID
. . .
[n] - Spell Z FormID

When you iterate the array with ForEach, at each iteration it returns a StringMap with the key and value of the corresponding entry. So, the first time, the returned StringMap would look like:
["key"] = 0
["value"] = Spell A FormID

Therefore the first parameter of the ForEach function must be an array_var:
Array_var Entry
ForEach Entry < AdjustedSpells
_ _ Let SpellRef := Entry["value"] ; could also be *Entry
_ _ . . .
Loop
User avatar
Kyra
 
Posts: 3365
Joined: Mon Jan 29, 2007 8:24 am

Post » Wed Feb 16, 2011 2:34 pm

ummm.... mmmm

I am not exactly following you.

so a string map is this: [0] spellref a formid

I l know what a formid is but what is the A,B, C, ....Z stuff?

I am assuming [0] is the number (the KEY) in the count just like with get "nth" stuff. I am lost when you say "Therefore the first parameter of the ForEach function must be an array_var:" When you say parameter do you mean the "first step I need to do"?

Why are we checking to see if " ForEach Entry" is less than AdjustedSpells? How can anything be less then a reference? Are we checking to see if the ref variable is empty?

What is " *Entry " ?
Is ENTRY a command to say "look to the reference at location [0, 1 2 or what ever] in the array?" But what is the " * " for ?

Here is my next guess based on your post (is this right?):

array_var AdjustedSpells
short index
short count
ref ActorRef
long damage
short Doonce


Begin gamemode

if doonce == 0
set actorRef to getcontainer;---- This is not really going to be here as I already do this in the beginning of the rest of the script. But I left this in so that I would not confuse anyone.
set doonce to 1
if ActorRef.isactor == 1
if AcrotRef.ismovingforward == 1;---------------- This is a little trick I came up with to test if the NPC is alive, not parallelized, not unconscious, not
let AdjustedSpells := ActorRef.GetSpells; disabled, not stuck and is valid all in ONE check! IT tastes great and is less filling!
endif; Works 99% of the time thus I only use it in cases where if it does not work it is not harmful just if not a little inconvenient.
endif
endif


if eval (ar_Size AdjustedSpells) > 0

Array_var Entry
ForEach Entry < AdjustedSpells
Let SpellRef := Entry["value"]

if CompareName "{}" SpellRef != 1;-------------------- check to see if the spell has already been processed once before.
set count to GetMagicItemEffectCount SpellRef
while (count)
set count to count - 1
if GetNthEICode spellRef count == FIDG
set Damage to ( GetNthEIMagnitude SpellRef count * 5 );------------- multiply the magnitude by 5 to make spells 5 times normal damage.
SetNthEIMagnitude Damage SpellRef count
if CompareName "{}" SpellRef != 1.
AppendToName " {}" spellRef;------------- append the name of the spell with the symbol {} so players and the script knows the spell has been processed once
endif
loop
endif
Set index to index + 1
endif
endif

end
User avatar
Nicole Kraus
 
Posts: 3432
Joined: Sat Apr 14, 2007 11:34 pm

Post » Wed Feb 16, 2011 9:38 pm

Your updated script is pretty close.
Foreach uses "<-", not "<":
foreach entry <- adjustedSpells

Your while loop will use count when count is -1, do this instead:
set count to GetMagicItemEffectCount spellRefwhile (count > 0)  set count to count - 1  ; etc...loop

This line:
set Damage to (GetNthEIMagnitude SpellRef count * 5)

may need to be split up into two in order to get the correct result:
set damage to GetNthEIMagnitude SpellRef countset damage to damage * 5

Alternatively use let:
let damage := (GetNthEIMagnitude SpellRef count) * 5

The line set index to index + 1 can be removed as "index" is not used anywhere else.

You seem to have it pretty well figured out (you even indented your script - thanks! :D)
That said, I'm not sure this is the best way to accomplish what you're trying to accomplish. The script processes an actor's spell list every frame, even though it's unlikely that an actor's spell list will *ever* change. Do you plan to stop the script after processing the spell list once?

You might consider an alternative way of doing it: keep a master array of all processed spells in a quest script.
Each time the player enters a new cell, use GetFirst/NextRef to scan for actors.
Go through each actor's spell list once - for each spell found, if it is not in your master list, adjust its magnitude and add it to your master list.
You might then add an unplayable, unscripted token to the inventory of each actor. When scanning for actors, you can check for the token to know which actors don't need their spell lists processed because they have been already.
Additionally, since the player is unique in that his spell list will change frequently, have your quest script do something like this at infrequent intervals:
short curPlayerSpellCount...if getPlayerSpellCount > curPlayerSpellCount  ; process player's spell listendifset curPlayerSpellCount to getPlayerSpellCount

It's just a suggestion - but in any case, cutting down on the number of times you process an actor's spell list, and in particular avoiding re-processing spell lists, would be a good idea.
User avatar
Dalley hussain
 
Posts: 3480
Joined: Sun Jun 18, 2006 2:45 am

Post » Thu Feb 17, 2011 12:58 am

Thanks for your help! I think I moved from "grok" of 65% to 80% now.
Right, this is just a test. not the full script I will be doing. My full script already uses a token to give the NPC other game mechanics and then checks for this token so as to not repeat on the same NPC.

The following given me an error: Invalid loop block structure.

let AdjustedSpells := NextNPC.GetSpellsif eval (ar_Size AdjustedSpells) > 0 ForEach Entry <- AdjustedSpells Let SpellRef := Entry["value"]        if CompareName "{}" SpellRef != 1;-------------------- check to see if the spell has already been processed once before.        set count to GetMagicItemEffectCount spellRef              while (count > 0)              set count to count - 1                       if GetNthEICode spellRef count == FIDG                       let damage := (GetNthEIMagnitude SpellRef count) * 5;------------- multiply the magnitude by 5 to make spells 5 times normal damage.                        SetNthEIMagnitude Damage SpellRef count                                 if CompareName "{}" SpellRef != 1.                                 AppendToName " {}" spellRef;------------- append the name of the spell with the symbol {} so players and the script knows the spell has been processed once                                 endif                                              endif                                     loop        endifendif



It's just a suggestion - but in any case, cutting down on the number of times you process an actor's spell list, and in particular avoiding re-processing spell lists, would be a good idea.

User avatar
Chantel Hopkin
 
Posts: 3533
Joined: Sun Dec 03, 2006 9:41 am

Post » Wed Feb 16, 2011 9:54 pm

It is better to indent AFTER the IF, so the whole block between IF and ENDIF is indented and you can easily identify which ENDIF relates to which IF;

Same goes for ForEach+Loop and While+Loop.

In your case, there is something missing.
You can easily find it yourself with he right indentation, as the number of indentations must match the number of un-indentations.

let AdjustedSpells := NextNPC.GetSpellsif eval (ar_Size AdjustedSpells) > 0      ForEach Entry <- AdjustedSpells           Let SpellRef := Entry["value"]           if CompareName "{}" SpellRef != 1;-------------------- check to see if the spell has already been processed once before.                set count to GetMagicItemEffectCount spellRef               while (count > 0)                    set count to count - 1                    if GetNthEICode spellRef count == FIDG                         let damage := (GetNthEIMagnitude SpellRef count) * 5;------------- multiply the magnitude by 5 to make spells 5 times normal damage.                          SetNthEIMagnitude Damage SpellRef count                          if CompareName "{}" SpellRef != 1.                               AppendToName " {}" spellRef;------------- append the name of the spell with the symbol {} so players and the script knows the spell has been processed once                          endif                                           endif                                      loop           endifendif


As for your previous questions:

I l know what a formid is but what is the A,B, C, ....Z stuff?

Just a way to say they are different spells. I should have written "Spell #1, Spell #2, etc)

Why are we checking to see if " ForEach Entry" is less than AdjustedSpells? How can anything be less than a reference? Are we checking to see if the ref variable is empty?

My bad. Did not notice there was no "-"
Should be "ForEach Entry <- AdjustedSpells"

What is " *Entry " ?
Is ENTRY a command to say "look to the reference at location [0, 1 2 or what ever] in the array?" But what is the " * " for ?

*Entry is just a short way of writing Entry["value"]
From the doc:
Dereferences an array. If the array is a StringMap with a "value" key, returns the value associated with that key. Otherwise returns the value of the first element.

I am writing an "Introduction to OBSE arrays" article for the WIKI. Check it out in a couple of days.
User avatar
Mark Hepworth
 
Posts: 3490
Joined: Wed Jul 11, 2007 1:51 pm

Post » Wed Feb 16, 2011 6:08 pm

Thanks QQuix
I will be all over that Wikki article both to learn from you and to add notes from the "complete ignorance " point of view!

Now the bad news, it was not the indents that was the problem, I just did not know from any of the docs (or my lack of comprehension) that ForEach was the same as IF and needed an "endif". However adding that to the script I still get the same error!


Thanks QQuix I will be all over that Wikki article both to learn from you and to add notes from the "complete ignorance " point of view!Now the bad news, it was not the indents that was the problem, I just did not know from any of the docs (or my lack of comprehension) that ForEach was the same as IF and needed an "endif". However adding that to the script I still get the same error!let AdjustedSpells := NextNPC.GetSpellsif eval (ar_Size AdjustedSpells) > 0      ForEach Entry <- AdjustedSpells           Let SpellRef := Entry["value"]           if CompareName "{}" SpellRef != 1;-------------------- check to see if the spell has already been processed once before.                set count to GetMagicItemEffectCount spellRef               while (count > 0)                    set count to count - 1                    if GetNthEICode spellRef count == FIDG                         let damage := (GetNthEIMagnitude SpellRef count) * 5;------------- multiply the magnitude by 5 to make spells 5 times normal damage.                          SetNthEIMagnitude Damage SpellRef count                          if CompareName "{}" SpellRef != 1.                               AppendToName " {}" spellRef;------------- append the name of the spell with the symbol {} so players and the script knows the spell has been processed once                          endif                    endif                                      loop          endif                            endifendif

User avatar
Roddy
 
Posts: 3564
Joined: Fri Jun 15, 2007 11:50 pm

Post » Wed Feb 16, 2011 11:06 am

Strange, im getting old cache or something(i read some thing different before), try this

let AdjustedSpells := NextNPC.GetSpellsif eval (ar_Size AdjustedSpells) > 0      ForEach Entry <- AdjustedSpells           Let SpellRef := Entry["value"]           if CompareName "{}" SpellRef != 1;-------------------- check to see if the spell has already been processed once before.                set count to GetMagicItemEffectCount spellRef               while (count > 0)                    set count to count - 1                    if GetNthEICode spellRef count == FIDG                         let damage := (GetNthEIMagnitude SpellRef count) * 5;------------- multiply the magnitude by 5 to make spells 5 times normal damage.                          SetNthEIMagnitude Damage SpellRef count                          if CompareName "{}" SpellRef != 1.                               AppendToName " {}" spellRef;------------- append the name of the spell with the symbol {} so players and the script knows the spell has been processed once                          endif                                           endif                                      loop           endif      loop endif

User avatar
Sian Ennis
 
Posts: 3362
Joined: Wed Nov 08, 2006 11:46 am

Post » Wed Feb 16, 2011 11:11 pm

OOOOHHH! it needs a "loop" not an endif! ha! thanks! Now this error I was getting makes more sense! YES it compiles now! Hope it works in game as well! Cross fingers....


Strange, im getting old cache or something(i read some thing different before), try this

let AdjustedSpells := NextNPC.GetSpellsif eval (ar_Size AdjustedSpells) > 0      ForEach Entry <- AdjustedSpells           Let SpellRef := Entry["value"]           if CompareName "{}" SpellRef != 1;-------------------- check to see if the spell has already been processed once before.                set count to GetMagicItemEffectCount spellRef               while (count > 0)                    set count to count - 1                    if GetNthEICode spellRef count == FIDG                         let damage := (GetNthEIMagnitude SpellRef count) * 5;------------- multiply the magnitude by 5 to make spells 5 times normal damage.                          SetNthEIMagnitude Damage SpellRef count                          if CompareName "{}" SpellRef != 1.                               AppendToName " {}" spellRef;------------- append the name of the spell with the symbol {} so players and the script knows the spell has been processed once                          endif                                           endif                                      loop           endif      loop endif


User avatar
Laura Tempel
 
Posts: 3484
Joined: Wed Oct 04, 2006 4:53 pm

Post » Wed Feb 16, 2011 6:26 pm

Yes.
Both "ForEach" and "While" are 'closed' with a "Loop" statement, not EndIf.
"Endif" is used only to close an "If" block.
User avatar
Leilene Nessel
 
Posts: 3428
Joined: Sun Apr 15, 2007 2:11 am

Post » Wed Feb 16, 2011 7:14 pm

After a few hours of testing I have this to report. Although it compiles just fine I do not think it is doing the intended job.
The spells are not changing and I do not see the message box I put in for the test.


if getPlayerSpellCount > curPlayerSpellCountlet AdjustedSpells := player.GetSpellsif eval (ar_Size AdjustedSpells) > 0     ForEach Entry <- AdjustedSpells           Let SpellRef := Entry["value"]           if CompareName "{}" SpellRef == 0               set count to GetMagicItemEffectCount spellRef               while (count > 0)  <-----------------------------------------------works up to here as I checked with another message box in another test.                    set count to count - 1                    if GetNthEICode spellRef count == FIDG || GetNthEICode spellRef count == SHDG || GetNthEICode spellRef count == FRDG || GetNthEICode spellRef count == DGHE || GetNthEICode spellRef count == DRHE || GetNthEICode spellRef count == DIWE                         let damage := (GetNthEIMagnitude SpellRef count) * 5                         SetNthEIMagnitude Damage SpellRef count                           messagebox"spell adjusted" <---------------------------------------  but I never see this message and the spells are not changed in the game.                         if CompareName "{}" SpellRef != 1.                               AppendToName " {}" spellRef                         endif                                           endif                                      loop           endif      loop endifset curPlayerSpellCount to getPlayerSpellCount

User avatar
Sun of Sammy
 
Posts: 3442
Joined: Mon Oct 22, 2007 3:38 pm

Post » Wed Feb 16, 2011 11:03 pm

Hi Spooky,

I know the "real" scriptors might cut me down as being wrong about this (but you never know, I may be right):


messagebox"spell adjusted" ;; you lack a space between the word "messagebox" and the first quote...could this cause issues?
if CompareName "{}" SpellRef != 1.
AppendToName " {}" spellRef ;; similar to above, you added a space between the first quote and the {} part..could this cause issues?

I mention this, because I heard from the wiki somewhere that indentation and unsymmetrical spacing in scripts can cause scripts to not work, though they compile fine...then again, I also heard that this doesn't affect anything... :shrug:

Koniption

EDIT:

Ah, found it ("Spaces and Tabs" section at very bottom of page):

http://cs.elderscrolls.com/constwiki/index.php/If
User avatar
Jeneene Hunte
 
Posts: 3478
Joined: Mon Sep 11, 2006 3:18 pm

Post » Wed Feb 16, 2011 6:49 pm

Thanks for trying to help!
I do appreciate it, but in this case that is not the issue. :nope: I use both (message box without a space and the {} with a space) in my combat archery mod and they work just fine. In fact I used it in this scrip up to the "if CompareName "{}" SpellRef == 0" line in my script and it worked upt to that line. I am sure it is not my message call but rather that the spell is not being changed for some reaseon as I do not see the spell hit any harder either.

The space is needed so the spell name look like this: Magic FireBall {}

not like this: Magic FireBall{}.



Hi Spooky,

I know the "real" scriptors might cut me down as being wrong about this (but you never know, I may be right):

messagebox"spell adjusted" ;; you lack a space between the word "messagebox" and the first quote...could this cause issues?
if CompareName "{}" SpellRef != 1.
AppendToName " {}" spellRef ;; similar to above, you added a space between the first quote and the {} part..could this cause issues?

I mention this, because I heard from the wiki somewhere that indentation and unsymmetrical spacing in scripts can cause scripts to not work, though they compile fine...then again, I also heard that this doesn't affect anything... :shrug:
Koniption

EDIT:
Ah, found it ("Spaces and Tabs" section at very bottom of page):
http://cs.elderscrolls.com/constwiki/index.php/If

User avatar
alyssa ALYSSA
 
Posts: 3382
Joined: Mon Sep 25, 2006 8:36 pm

Post » Wed Feb 16, 2011 8:41 pm

Anyone have any other idea why I am not seeing the test message?
User avatar
lisa nuttall
 
Posts: 3277
Joined: Tue Jun 20, 2006 1:33 pm

Post » Wed Feb 16, 2011 5:47 pm

Please include variable declarations and script name etc when posting.
This works:
Spoiler
scn UDUNspookyfxSCRarray_var AdjustedSpellsarray_var Entryshort curPlayerSpellCountshort countref SpellReflong effectcodefloat damagebegin GameModeif getPlayerSpellCount > curPlayerSpellCount	printc "getPlayerSpellCount > curPlayerSpellCount"	let AdjustedSpells := player.GetSpells	ar_Dump AdjustedSpells	if eval(ar_Size AdjustedSpells) > 0		printc "eval(ar_Size AdjustedSpells) > 0"		ForEach Entry <- AdjustedSpells			Let SpellRef := Entry["value"]			printc "spell %i : adjusting" SpellRef			if CompareName "{}" SpellRef == 0				printc "CompareName {} %i == 0" SpellRef				set count to GetMagicItemEffectCount spellRef				printc "count = %.0f" count				while (count > 0)						set count to count - 1						let effectcode := GetNthEICode spellRef count						printc "effectcode for spell %i == %.0f" SpellRef effectcode						if  (effectcode == getMagicEffectCode FIDG || effectcode == getMagicEffectCode SHDG || effectcode == getMagicEffectCode FRDG || effectcode == getMagicEffectCode DGHE || effectcode == getMagicEffectCode DRHE || effectcode == getMagicEffectCode DIWE)							printc "damaging !~"							let damage := (GetNthEIMagnitude SpellRef count) * 5							SetNthEIMagnitude Damage SpellRef count							printc "spell %i : adjusted" SpellRef							if CompareName "{}" SpellRef != 1.								AppendToName " {}" spellRef							endif							; set damage to 0						endif				loop			endif		loop	endifendifset curPlayerSpellCount to getPlayerSpellCountend

Console (thanks ShadeMe) :
Spoiler
===============================================Game Instance : 1 | Time : 09-21-2010 18-24-37===============================================getPlayerSpellCount > curPlayerSpellCount** Dumping Array #1 **Refs: 1 Owner 01: UDUNdamageTest.esp[ 0.000000 ] : Absorb Health (000A9367)[ 1.000000 ] : Flare (000A97DF)[ 2.000000 ] : Heal Minor Wounds (00000136)[ 3.000000 ] : Minor Dispel (0008D1E9)[ 4.000000 ] : Minor Life Detection (000A97DC)[ 5.000000 ] : Open Very Easy Lock (000A97FE)[ 6.000000 ] : Protect (000A97A7)[ 7.000000 ] : Soothing Touch (000A97C9)[ 8.000000 ] : Starlight (000A9825)[ 9.000000 ] : Summon Skeleton (000AA05F)[ 10.000000 ] : Turn Undead (000AA068)[ 11.000000 ] : High Elf Disease Resistance (00047AD7)[ 12.000000 ] : High Elf Elemental Weakness (00014D52)[ 13.000000 ] : High Elf Enhanced Magicka (00047ADC)[ 14.000000 ] : Mage Birthsign (00022A31)eval(ar_Size AdjustedSpells) > 0spell 000A9367 : adjustingCompareName {} 000A9367 == 0count = 1effectcode for spell 000A9367 == 1162363457spell 000A97DF : adjustingCompareName {} 000A97DF == 0count = 1effectcode for spell 000A97DF == 1195657542damaging !~spell 000A97DF : adjustedspell 00000136 : adjustingCompareName {} 00000136 == 0count = 1effectcode for spell 00000136 == 1162364242spell 0008D1E9 : adjustingCompareName {} 0008D1E9 == 0count = 1effectcode for spell 0008D1E9 == 1280332612spell 000A97DC : adjustingCompareName {} 000A97DC == 0count = 1effectcode for spell 000A97DC == 1413698628spell 000A97FE : adjustingCompareName {} 000A97FE == 0count = 1effectcode for spell 000A97FE == 1313165391spell 000A97A7 : adjustingCompareName {} 000A97A7 == 0count = 1effectcode for spell 000A97A7 == 1145849939spell 000A97C9 : adjustingCompareName {} 000A97C9 == 0count = 1effectcode for spell 000A97C9 == 1296843075spell 000A9825 : adjustingCompareName {} 000A9825 == 0count = 1effectcode for spell 000A9825 == 1414022988spell 000AA05F : adjustingCompareName {} 000AA05F == 0count = 1effectcode for spell 000AA05F == 1162564442spell 000AA068 : adjustingCompareName {} 000AA068 == 0count = 1effectcode for spell 000AA068 == 1314018644spell 00047AD7 : adjustingCompareName {} 00047AD7 == 0count = 1effectcode for spell 00047AD7 == 1229214546spell 00014D52 : adjustingCompareName {} 00014D52 == 0count = 3effectcode for spell 00014D52 == 1213418327effectcode for spell 00014D52 == 1380338519effectcode for spell 00014D52 == 1229343575spell 00047ADC : adjustingCompareName {} 00047ADC == 0count = 1effectcode for spell 00047ADC == 1347637062spell 00022A31 : adjustingCompareName {} 00022A31 == 0count = 1effectcode for spell 00022A31 == 1347637062

Turned out the syntax in your if was wrong - not sure the one I used is the best alternative - never used GetNthEffectItemCode before
Apparently == XXXX does not work
A messagebox in a loop (which runs in a single frame) sounds like a bad idea - use printcS - the way I use them is full-proof debugging friendly.
Use an editor like Notepad++
HTH
User avatar
Motionsharp
 
Posts: 3437
Joined: Sun Aug 06, 2006 1:33 am

Post » Thu Feb 17, 2011 12:02 am

OK I do not understand any of the "print to console" stuff, I never use that. So far (for me anyway) the message box has never been the reason a script would not work. And yes I did try it this time as you wrote it in your script but I saw no message on my screen. Could be I need to open the console? But anyway lets forget that part as I want to stick to the basic premise of my question.

You did hit the bullseye on exactly why the script was not working, so the following works perfectly now (I think I only tested it a few times) :

scn aadpTestarray_var AdjustedSpellsarray_var Entryshort curPlayerSpellCountshort countref SpellReflong effectcodefloat damageif getPlayerSpellCount > curPlayerSpellCount	let AdjustedSpells := player.GetSpells	ar_Dump AdjustedSpells	if eval(ar_Size AdjustedSpells) > 0		ForEach Entry <- AdjustedSpells			Let SpellRef := Entry["value"]			if CompareName "{}" SpellRef == 0				set count to GetMagicItemEffectCount spellRef				while (count > 0)						set count to count - 1						let effectcode := GetNthEICode spellRef count						if  (effectcode == getMagicEffectCode FIDG || effectcode == getMagicEffectCode SHDG || effectcode == getMagicEffectCode FRDG || effectcode == getMagicEffectCode DGHE || effectcode == getMagicEffectCode DRHE || effectcode == getMagicEffectCode DIWE)							let damage := (GetNthEIMagnitude SpellRef count) * 5							SetNthEIMagnitude Damage SpellRef count							if CompareName "{}" SpellRef != 1                                                              messagebox"worked";<-----------------------   I now get this messagebox and the spell is changed with the name and magnitude.							   AppendToName " {}" spellRef							endif						endif				loop			endif		loop	endifendifset curPlayerSpellCount to getPlayerSpellCount



So thank you so very very much!
(Normally it is "fun" for me when this kind of thing is worked out but this one was just a big "relief", not fun.)


It was this: let effectcode := GetNthEICode spellRef count


That was it, nothing else, just that...so a var needed to be set then used with the OBSE command. The command would not work "directly"?
But, Is there any rhyme or reason to this? I mean how does one know when to do this and when it is not needed? Just trial and error?
It is not needed wiht MOST OBSE commnads. Just a few particular ones, is there a list of these few particular OBSE commands someplace?

(I hope I am not sounding un appreciative, I just had my wisdom teeth pulled a few hours ago and my jaw feels like I was hit with a warhammer "the size of a small child.")
User avatar
Miguel
 
Posts: 3364
Joined: Sat Jul 14, 2007 9:32 am

Post » Thu Feb 17, 2011 4:32 am

It was this: let effectcode := GetNthEICode spellRef count

That was it, nothing else, just that...so a var needed to be set then used with the OBSE command. The command would not work "directly"?

That wasn't the only change; the change that fixed it was the use of GetMagicEffectCode instead of trying to compare the return value from GetNthEICode to the objectIDs FIDG, SHDG, etc.
FIDG et al are objectIDs, not effect codes.
User avatar
Michelle Smith
 
Posts: 3417
Joined: Wed Nov 15, 2006 2:03 am

Post » Thu Feb 17, 2011 4:41 am

oh, yes I missed that, utumno's working script is doing this:

let effectcode := GetNthEICode spellRef count
if (effectcode == getMagicEffectCode FIDG ||.....

where I was doing tis before:

if GetNthEICode spellRef count == FIDG || GetNthEICode spellRef count == SHDG ||....

So the real problem was that: GetNthEICode spellRef count WILL NEVER EQUAL FIDG

Right? It only equals a number like 3454 or what ever. Why did I think it would be FIDG? Is there another command that returns the magic effect in this form ( FIDG) ? Is there a list of the codes like 3454 = FIDG?
User avatar
Josephine Gowing
 
Posts: 3545
Joined: Fri Jun 30, 2006 12:41 pm

Post » Thu Feb 17, 2011 6:16 am

OK I do not understand any of the "print to console" stuff, I never use that [...]Could be I need to open the console?
Do learn bout printc otherwise I will never reply again :nono: :D
Seriously now - yes, you have to open the console or much much better download ShadeMe's Conscribe OBSE pluggin which logs everything that's written in the console to a text file (enable per session in the ini)
Do yourself a favor and do it now.
I know not the answers to your questions above - I wonder myself as I never used those functions before - I just posted a question in the OBSE thread. I searched the forum an found a script by HeyYou that put me in the right direction - this and the printcS :whistling:
As for the fix it was indeed as Scruggsy said the getMagicEffectCode. This would work:
let damage := ( GetNthEICode spellRef count == getMagicEffectCode FIDG || GetNthEICode spellRef count == getMagicEffectCode SHDG || GetNthEICode spellRef count == getMagicEffectCode FRDG || GetNthEICode spellRef count == getMagicEffectCode DGHE || GetNthEICode spellRef count == getMagicEffectCode DRHE || GetNthEICode spellRef count == getMagicEffectCode DIWE )						if damage ; adjust spell

But I think the effectcode variable is needed to avoid computing the effect code 5 more times - and probably the getMagicEffectCode FRDG etc should be put in a doOnce if block

Glad to be of use :)
User avatar
clelia vega
 
Posts: 3433
Joined: Wed Mar 21, 2007 6:04 pm

Post » Thu Feb 17, 2011 6:36 am

So the real problem was that: GetNthEICode spellRef count WILL NEVER EQUAL FIDG

Right? It only equals a number like 3454 or what ever. Why did I think it would be FIDG? Is there another command that returns the magic effect in this form ( FIDG) ? Is there a list of the codes like 3454 = FIDG?

Yeah, exactly.
Using FIDG in a script is just like using Gold001 or Arrow1Iron - it's an editorID for an object.
Commands that are documented in the obse docs as returning (magicEffect:ref) return objects like FIDG, e.g.:
if MagicEffectFromCode someEffectCode == FIDG

converts from an effect code to a magic effect object so here the comparison is fine.

One thing to note about magic effects though: they sometimes will have a formID of 00000000. This is why OBSE cmds tend to use effect codes instead. If you edit such an effect in a mod then it will be assigned a formID by the game.
User avatar
Ryan Lutz
 
Posts: 3465
Joined: Sun Sep 09, 2007 12:39 pm

Post » Wed Feb 16, 2011 6:49 pm

Sorry to hijack this thread, but since I'm trying to manipulate an array in a similar fashion, I figured it may be better than to start another thread.

I'm trying to force an actor to equip a weapon, ranged or melee, depending on how far his combat target is from him. This is to fix an issue I, and I believe many others, even in vanilla, have with goblins not correctly switching between their melee and ranged weapons and ending up fighting with only their hands. My script is assigned to a token item in the actor's inventory. I want to force the actor to equip his melee or ranged weapon when his target is nearer or further than the distances for switching weapons defined by his combat style. I get his weapons into an array , iterate through it with another, and check what kind they are with getWeaponType.

Spoiler

scn zzDeadlyCreatureTokenOSref selfref targetref styleref weaponref equippedfloat farfloat neararray_var itemsarray_var weaponsBegin gameModeset self to GetContainer...If self.GetIsCreature && self.GetNumItems > 0 && self.IsInCombat	let target := self.GetCombatTarget	let style := self.GetCombatStyle	if style == 0		let near := 250		;default switch distances for default combat behaviour		let far := 1000	else		let near := GetCombatStyleSwitchDistMelee style		let far := GetCombatStyleSwitchDistRanged style	endif	let equipped := self.GetEquippedObject 16	let items := self.GetItems 33	;only weapons	If ((equipped == 0 || equipped.GetWeaponType == 5) && target.GetDistance self <= near) || ((equipped == 0 || equipped.GetWeaponType < 4) && target.GetDistance self >= far)		ForEach weapons <-  items			let weapon := weapons["value"]			If (weapon.GetWeaponType < 4 && target.GetDistance self <= near) || (weapon.GetWeaponType == 5 && target.GetDistance self >= far)				self.EquipItem2NS weapon				PrintC "%n equipped %n" self weapon				self.StopCombat				self.StartCombat target		;this fixes animations, else he will try to melee you with his bow			EndIf		loop	EndIfEndIf



The console output states that the actor equips all his weapons at the same time, my best guess is that the ForEach loop runs so quick that it equips both weapons in a frame. Frankly enough, I don't even know what the
ForEach weapons <-  items	let weapon := weapons["value"]

does, I just figured it was what I should use from looking here (thank you Duke). So, any advice? I'm really at a loss, since I guess I don't really know how arrays work and only people with some basis in computer science really do.
User avatar
Angela
 
Posts: 3492
Joined: Mon Mar 05, 2007 8:33 am

Post » Thu Feb 17, 2011 1:42 am

Sorry to hijack this thread, but since I'm trying to manipulate an array in a similar fashion, I figured it may be better than to start another thread.

I'm trying to force an actor to equip a weapon, ranged or melee, depending on how far his combat target is from him. This is to fix an issue I, and I believe many others, even in vanilla, have with goblins not correctly switching between their melee and ranged weapons and ending up fighting with only their hands. My script is assigned to a token item in the actor's inventory. I want to force the actor to equip his melee or ranged weapon when his target is nearer or further than the distances for switching weapons defined by his combat style. I get his weapons into an array , iterate through it with another, and check what kind they are with getWeaponType.

The console output states that the actor equips all his weapons at the same time, my best guess is that the ForEach loop runs so quick that it equips both weapons in a frame. Frankly enough, I don't even know what the
ForEach weapons <-  items	let weapon := weapons["value"]

does, I just figured it was what I should use from looking here (thank you Duke). So, any advice? I'm really at a loss, since I guess I don't really know how arrays work and only people with some basis in computer science really do.



Spoiler
scn zzDeadlyCreatureTokenOSref selfref targetref styleref weaponref equippedfloat farfloat neararray_var itemsarray_var weaponsBegin gameModeset self to GetContainer...If self.GetIsCreature && self.GetNumItems > 0 && self.IsInCombat	let target := self.GetCombatTarget	let style := self.GetCombatStyle	if style == 0		let near := 250		;default switch distances for default combat behaviour		let far := 1000	else		let near := GetCombatStyleSwitchDistMelee style		let far := GetCombatStyleSwitchDistRanged style	endif	let equipped := self.GetEquippedObject 16	let items := self.GetItems 33	;only weapons	If ((equipped == 0 || equipped.GetWeaponType == 5) && target.GetDistance self <= near) || ((equipped == 0 || equipped.GetWeaponType < 4) && target.GetDistance self >= far)		ForEach weapons <-  items			let weapon := weapons["value"]			If (weapon.GetWeaponType < 4 && target.GetDistance self <= near) || (weapon.GetWeaponType == 5 && target.GetDistance self >= far)				self.EquipItem2NS weapon				PrintC "%n equipped %n" self weapon				self.StopCombat				self.StartCombat target		;this fixes animations, else he will try to melee you with his bow				BREAK ; foreach is a loop - add this for the loop to stop when a suitable (but not necessarily the best) weapon is found			EndIf		loop	EndIfEndIf

User avatar
Add Me
 
Posts: 3486
Joined: Thu Jul 05, 2007 8:21 am

Post » Wed Feb 16, 2011 11:33 pm

Sorry for the thread necromancy, but I'd rather not start a new one for the same stuff.

I'm trying to identify if a thing matches what can be found in an array, and process it accordingly if not. I read about ar_Find, and supposedly for things that are not in the array it returns -99999 for numeric arrays (formIDs?) or a null string (what is that like?) for string arrays (like when using StringMap?)
the script is like:
Spoiler
array_var spellsarray_var spellsIterref actorref spellshort spellIterlet spells := actor.GetSpellsForEach spellsIter <- spells	If eval (spellIter <= (ar_Size spells))		let spell := spellsIter["value"]		let spellIter += 1		PrintD "Checking spell " + $spell		If eval (ar_Find spell aaBirthsignNPCQ.Birthsign)!= -99999.0;aaBirthsignNPCQ.Birthsign is an array with the birthsign spells, initialized in another script. Maybe I should carry it over here as another array_var?			PrintD $spell + " is birthsign spell in " + $actor + ", skipping"			actor.AddItemNS aaBirthsignNPCTokenSkip 1			RemoveMe		EndIf	Else		PrintD $actor + " got all spells iterated, none matches a birthsign"		let spellIter := 0		Break	Endif; goes on to add the birthsign's spells if aaBirthsignNPCTokenSkip was not addedLoop

I tried with and without the != -99999.0, and I can't get the effect I want. Without it, any spell found on the actor is assumed to be in the birthsign array, whether that is true or not, and thus the actor gets none. With it, the opposite happens, the actor gets birthsign spells even if he already has them.
How does one use ar_Find for comparing something to what is stored in an array then?
User avatar
NAkeshIa BENNETT
 
Posts: 3519
Joined: Fri Jun 16, 2006 12:23 pm

Post » Thu Feb 17, 2011 2:31 am

Because this thread got resurrected I re-read it all the way through just out of curiosity.
Back at that time I started this thread I see that I came to a working understanding of commands discussed in this thread.

but now... :(

Almost all of it did not stick in my brain. I just am not taking to the array language the way I did the original Oblivion scripting language. That means spending time learning it again over and over each time I need to use it (and risking annoying people that have already explained it before to me) instead of having fun working out the script logic I will be struggling with the language.
That really svcks eggs.

I guess it in part has to do with not using it on a daily basses, I am not sure how I would go about doing that (using the array language on a daily basses.)

Have any tutorials made it to the wikki on these yet?
User avatar
kristy dunn
 
Posts: 3410
Joined: Thu Mar 01, 2007 2:08 am

Post » Wed Feb 16, 2011 11:36 pm

There aren't any CS tutorials, but if you get more comfortable with arrays in any programming language, you won't have a problem with OBSE arrays. I would suggest looking up java arrays. There should be lots of material on how they work and how you access them. The language will be similar enough that you'll be able to transfer it to OBSE arrays. Another possibility is PHP. PHP even has foreach loops which are pretty similar to OBSE's. In fact I notice that if you search for foreach, Wikipedia has a page that talks about the general construct in various languages!
User avatar
Jonathan Montero
 
Posts: 3487
Joined: Tue Aug 14, 2007 3:22 am

Next

Return to IV - Oblivion