Difference between revisions of "Chapter 3"

From SphereWiki
Jump to: navigation, search
m (NPC Evolution: Correct a logical mistake in coherence with the explanation of brain_beserk)
 
(6 intermediate revisions by 3 users not shown)
Line 1: Line 1:
'''''(incomplete)'''''
+
{{Languages|Chapter_3}}
  
 
==NPC Evolution==
 
==NPC Evolution==
Line 181: Line 181:
 
BRAIN_THIEF 9              // Thief: no effect right now<br />
 
BRAIN_THIEF 9              // Thief: no effect right now<br />
 
BRAIN_MONSTER 10          // Evil: attack all players we see<br />
 
BRAIN_MONSTER 10          // Evil: attack all players we see<br />
BRAIN_BESERK 11            // Crazy: attack anything we see<br />
+
BRAIN_BERSERK 11            // Crazy: attack anything we see<br />
 
BRAIN_UNDEAD 12            // Undead: same as evil, just used for identification<br />
 
BRAIN_UNDEAD 12            // Undead: same as evil, just used for identification<br />
 
BRAIN_DRAGON 13            // Dragon: breathes fire (set this on a rabbit)<br />
 
BRAIN_DRAGON 13            // Dragon: breathes fire (set this on a rabbit)<br />
Line 208: Line 208:
  
 
Now that you know how to make a decent NPC, let's explore ways to make unique items to put on him as loot. In the next section, we're going to make a SUPER DUPER BOW OF FIRE AND BRIMSTONE! *trumpet fanfare*
 
Now that you know how to make a decent NPC, let's explore ways to make unique items to put on him as loot. In the next section, we're going to make a SUPER DUPER BOW OF FIRE AND BRIMSTONE! *trumpet fanfare*
 
  
 
==Advanced Item Scripting==
 
==Advanced Item Scripting==
Line 351: Line 350:
  
  
==TYPEs and Values==
+
==TYPEs==
How to use TYPE and ATTR for your items
 
  
 +
This section explains how you can use [[TYPEDEF|built-in item types]], how to override the built-in types, and how you can make your own.
  
Actually, most of what I'm writing here is a duplicate of what Daleth has already written in his SPHERE Reference Project.  I don't know the link for it, since Paigelore seems to be down, but I'm sure he'd be willing to provide it if you ask him on the SPHERE message boards.
+
If you want to override a built-in typedef, that is indeed possible, just define its new behavior it in a script and since the scripts are loaded after the server starts, your new definition will take precedence.
  
 +
A TYPEDEF is essentially a collection of triggers, and can be written to reference other aspects of the ITEMDEF, CHARDEF, or REGION that it is assigned to.  To assign a TYPEDEF to an item, you can simply set TYPE=t_mytype in the ITEMDEF (Note: An item can only have one TYPE.)
  
This is by far NOT all of the types.  This is simply the types I believe you will use in your scripts.  If someone tells me another they have used, I will add it to the list.
+
Here is an example TYPEDEF:
  
{|  border="1" width="100%"
+
  [TYPEDEF t_horseshoes]
!  width="15%" height="19" | Name
+
  ON=@DClick
!  width="15%" height="19" | DEFNAME
+
    TARGET What animal needs this item?
!  width="70%" height="19" | Other properties and what they do
+
    RETURN 1
|-
+
  ON=@Targon_Char
| width="15%" | Un-typed
+
    IF (<SRC.TARG.DEX> > 100)
|  width="15%" | t_normal (0)
+
      SRC.SYSMESSAGE @032 That animal does not need this item.
| width="70%" | No particular properties here
+
      RETURN 1
|-
+
    ENDIF
|  width="15%" | Container
+
    IF (<SRC.TARG.OBODY>==(c_horse_pack|c_llama_pack|c_horse_gray|c_horse_brown_dk|c_horse_brown_lt|c_llama))
|  width="15%" | t_container (1)
+
      SRC.SYSMESSAGE @032 Now the animal is faster.
|  width="70%" | MORE = UID of this container's key<sup>1</sup> if it has one<br>
+
      SRC.TARG.MODDEX += <MORE1>
LINK = UID of the key also
+
      SRC.EFFECT=3,0374a,6,15,1
|-
+
      REMOVE
|  width="15%" | Locked Container
+
    ELSE
|  width="15%" | t_container_locked (2)
+
      SRC.SYSMESSAGE @032 That animal can not wear this item.
|  width="70%" | MORE = UID of this container's key<sup>1</sup><br>
+
    ENDIF
LINK=UID of the key<sup>1</sup>
+
    RETURN 1
|-
+
 
|  width="15%" | Door
+
Here is an example item that uses the t_horseshoes TYPEDEF shown above:
|  width="25%" | t_door
 
|  width="70%" | MORE = UID of the key<sup>1</sup>
 
|-
 
|  width="15%" | Locked Door
 
| width="15%" | t_door_locked
 
|  width="70%" | MORE = UID of the key<sup>1</sup>
 
|-
 
|  width="15%" | Key
 
|  width="15%" | t_key
 
|  width="70%" | MORE = UID of the item this key can unlock<br>
 
LINK = Usually the UID of a multi (house), etc, but can also be the UID of a door
 
|-
 
|  width="15%" | Light Source
 
|  width="15%" | t_light_lit
 
|  width="70%" | MOREY = number of charges before it disappears<br>
 
MOREZ = type of light sphere
 
|-
 
|  width="15%" | Unlit Light Source
 
|  width="15%" | t_light_out
 
|  width="70%" | MOREY = number of charges before it disappears<br>
 
MOREZ = type of light sphere
 
|-
 
|  width="15%" | Food
 
|  width="15%" | t_food
 
|  width="70%" | MORE = ID of the item it makes when cooked (i_unused
 
if none)
 
|-
 
|  width="15%" | Raw Food
 
|  width="15%" | t_food_raw
 
|  width="70%" | MORE = ID of the item it makes when cooked (i_unused
 
if none)
 
|-
 
|  width="15%" | Armor
 
|  width="15%" | t_armor
 
|  width="70%" | MORE1L = max hitpoints<br>
 
MORE1H = current hitpoints<br>
 
MOREY = armor bonus (percentage) if ATTR & attr_magic
 
|-
 
|  width="15%" | Mace Weapon
 
|  width="15%" | t_weapon_mace_smith
 
|  width="70%" | MORE1L = max hitpoints<br>
 
MORE1H = current hitpoints<br>
 
MOREY = attack bonus (percentage) if ATTR & attr_magic
 
|-
 
|  width="15%" | Mace Weapon
 
|  width="15%" | t_weapon_mace_sharp
 
|  width="70%" | MORE1L = max hitpoints<br>
 
MORE1H = current hitpoints<br>
 
MOREY = attack bonus (percentage) if ATTR & attr_magic
 
|-
 
|  width="15%" | Sword
 
| width="15%" | t_weapon_sword
 
| width="70%" | MORE1L = max hitpoints<br>
 
MORE1H = current hitpoints<br>
 
MOREY = attack bonus (percentage) if ATTR & attr_magic
 
|-
 
|  width="15%" | Fencing Weapon
 
|  width="15%" | t_weapon_fence
 
|  width="70%" | MORE1L = max hitpoints<br>
 
MORE1H = current hitpoints<br>
 
MOREY = attack bonus (percentage) if ATTR & attr_magic
 
|-
 
|  width="15%" height="21" | Bow Weapon
 
|  width="15%" height="21" | t_weapon_bow
 
|  width="70%" height="21" | MORE1L = max hitpoints<br>
 
MORE1H = current hitpoints<br>
 
MOREY = attack bonus (percentage) if ATTR & attr_magic<br>
 
TDATA3 = ID of arrow item (what does it consume on a shot?)<br>
 
TDATA4 = ID of the arrow animation (usually i_arrow_x)
 
|-
 
|  width="15%" height="21" | Wand
 
|  width="15%" height="21" | t_wand
 
|  width="70%" height="21" | MORE1L = max hitpoints<br>
 
MORE1H = current hitpoints<br>
 
MORE2 = max charges<br>
 
MOREX = spell to cast when double-clicked<br>
 
MOREY = skill with which to cast the spell (100.0 = 1000)
 
|-
 
|  width="15%" height="21" | Telepad
 
|  width="15%" height="21" | t_telepad
 
|  width="70%" height="21" | MOREP = coordinates of the point to which you will teleport when you step on the item
 
|-
 
|  width="15%" height="21" | Switch
 
|  width="15%" height="21" | t_switch
 
|  width="70%" height="21" | LINK = UID of item to trigger<br>
 
(When you double-click the switch item, it will also pretend like you double-clicked the LINK item. If you link it to a door, it will open the door.)
 
|-
 
|  width="15%" height="22" | Painful Fire
 
|  width="15%" height="22" | t_fire
 
|  width="70%" height="22" | Will burn you when stepped on<br>
 
TIMER = time until it decays
 
|-
 
|  width="15%" height="21" | Scroll
 
|  width="15%" height="21" | t_scroll
 
|  width="70%" height="21" | MOREX = spell to cast when double-clicked
 
|-
 
|  width="15%" height="21" | Shrine
 
|  width="15%" height="21" | t_shrine (38)
 
|  width="70%" height="21" | Will resurrect a ghost when double-clicked
 
|-
 
|  width="15%" height="21" | Moongate
 
|  width="15%" height="21" | t_moongate (39)
 
|  width="70%" height="21" | Sets up a link to the moongate cycle defined in <font color="#0000FF">spheremap.scp</font>
 
|-
 
|  width="15%" height="21" | Ore
 
|  width="15%" height="21" | t_ore
 
|  width="70%" height="21" | Can be smelted<br>
 
TDATA1 = ID of item created when the ore is smelted (usually an ingot)
 
|-
 
|  width="15%" height="21" | Tree
 
|  width="15%" height="21" | t_tree
 
|  width="70%" height="21" | Can be chopped for wood<br>
 
FRUIT = item gathered if double-clicked
 
|-
 
|  width="15%" height="20" | Advance Gate
 
|  width="15%" height="20" | t_advance_gate (59)
 
|  width="70%" height="20" | (When stepped on, you will transform into the character set in MORE. See IDs 2000+ in <font color="#0000FF">spherechar_misc.scp</font>)<br>
 
MORE = ID of character to change into
 
|-
 
|  width="15%" height="21" | Deed
 
|  width="15%" height="21" | t_deed
 
|  width="70%" height="21" | MORE = multi ID to create when double-clicked (<font color="#0000FF">sphereitem_multis.scp</font>)
 
|-
 
|  width="15%" height="21" | Equippable Script Item
 
|  width="15%" height="21" | t_eq_script
 
|  width="70%" height="21" | * THIS ITEM CAN HAVE TAGS AND IS EQUIPPABLE *
 
|-
 
|  width="15%" height="21" | Script Item
 
|  width="15%" height="21" | t_script
 
|  width="70%" height="21" | * THIS ITEM CAN HAVE TAGS AND IS NOT EQUIPPABLE *
 
|}
 
  
<sup>1</sup>''Keys and doors are very odd. If both a key and a door contain the same multi UID in either MORE or LINK, the key will open the door. This is how there can be multiple doors in one house using a single key. You can also have different UIDs stored in MORE and LINK so a single key will open more than one door. If a key is not linked to a door or a multi, it will disappear on worldsave.''
+
[ITEMDEF i_horse_shoes_magic]
 +
ID=0fb6
 +
NAME=magic horseshoes
 +
TYPE=t_horseshoes
 +
VALUE=35
 +
WEIGHT=8.0
 +
RESOURCES=8 i_ingot_iron
 +
SKILLMAKE=Blacksmithing 30.0
 +
CATEGORY=Items by Professions
 +
SUBSECTION=Blacksmiths
 +
DESCRIPTION=Magic Horse Shoes
 +
ON=@Create
 +
    MORE1={10 15}
 +
    ATTR=attr_magic
  
 +
==ATTRs==
  
 
This is a list of the ATTR flags available and what they do. I pulled it right out of <font color="darkblue">spheredefs.scp</font>
 
This is a list of the ATTR flags available and what they do. I pulled it right out of <font color="darkblue">spheredefs.scp</font>
Line 594: Line 477:
  
 
If you have a @Timer script on an item, you must have an attr_decay on that item.  Otherwise you will get scary errors.  You can always RETURN 1 from the @Timer script to prevent decay, but the flag must still be there.
 
If you have a @Timer script on an item, you must have an attr_decay on that item.  Otherwise you will get scary errors.  You can always RETURN 1 from the @Timer script to prevent decay, but the flag must still be there.
 
  
 
==Cool Commands==
 
==Cool Commands==
Line 643: Line 525:
  
  
<font color="darkred">Extra:</font> If you want to respawn all your npcs you gotta create some function to do that, here's an example:
+
<font color="darkred">Extra:</font> If you want to respawn all of your npcs across all maps you need to create a function to do that, here's an example:
  
  
Line 651: Line 533:
 
&nbsp;&nbsp;&nbsp;&nbsp;MAP = <LOCAL._FOR> //set the map<br />
 
&nbsp;&nbsp;&nbsp;&nbsp;MAP = <LOCAL._FOR> //set the map<br />
 
&nbsp;&nbsp;&nbsp;&nbsp;FORCHARS 8000 //loop through all chars in the world (unless EA makes a map bigger than 8000x8000 squares)<br />
 
&nbsp;&nbsp;&nbsp;&nbsp;FORCHARS 8000 //loop through all chars in the world (unless EA makes a map bigger than 8000x8000 squares)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OBJ=<MEMORYFINDTYPE.memory_ispawned.LINK> //set OBJ to the spawngem of that npc<br />
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REF1 = <MEMORYFINDTYPE.memory_ispawned.LINK> //set REF1 to the spawngem of that npc<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF (<OBJ>) //checks if the npc has the spawn memory<br />
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF (<REF1>) //checks if the npc has the spawn memory<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OBJ.TIMER = <EVAL {<OBJ.MOREX> <OBJ.MOREY>}*60> //set the spawn memory timer to the values specified when creating it<br />
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REF1.TIMER = <EVAL {<REF1.MOREX> <REF1.MOREY>} * 60> //set the spawn memory timer to the values specified when creating it<br />
 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENDIF<br />
 
&nbsp;&nbsp;&nbsp;&nbsp;ENDFOR<br />
 
&nbsp;&nbsp;&nbsp;&nbsp;ENDFOR<br />
 
ENDFOR<br /></font></tt>
 
ENDFOR<br /></font></tt>
 +
 +
[[Category:Tutorials]]

Latest revision as of 15:08, 30 May 2013

Help
Available languages


NPC Evolution

Remember in Chapter 1 when we looked at that basic NPC script? It was a generic script to create a naked man (or a naked player). And it looked something like this:


[CHARDEF 0190]
DEFNAME=c_man
Name=Man
ICON=i_pet_MAN
CAN=MT_EQUIP|MT_WALK|MT_RUN|MT_USEHANDS
RESOURCES=i_flesh_head, i_flesh_torso, i_flesh_right_arm, i_flesh_left_arm
FOODTYPE=15 t_food, t_fruit
DESIRES=i_gold,e_notoriety
AVERSIONS=t_TRAP,t_eerie_stuff
SHELTER=r_house
BLOODCOLOR=0

TSPEECH=spk_human_prime
TSPEECH=spk_human_default
TEVENTS=e_Human_HearUnk
DESCRIPTION=Man
SUBSECTION=Miscellaneous
CATEGORY=Civilized


As you can see, this is a rather incomplete script. It's actually one of the least complete of any of the scripts available in the spherechar_*.scp files. Here is a more complete example of an NPC script:


[CHARDEF 0490]
DEFNAME=C_H_ALCHEMIST
NAME=#NAMES_HUMANMALE the Alchemist
ID=C_MAN

DESIRES=i_gold,e_notoriety,t_magic
AVERSIONS=t_TRAP,t_eerie_stuff

TSPEECH=spk_human_prime
TSPEECH=jobalchemist
TSPEECH=spk_shopkeep
TSPEECH=spk_needs
TSPEECH=spk_rehello
TSPEECH=spk_human_default

TEVENTS=e_Human_HearUnk
TEVENTS=e_Human_ConvInit
TEVENTS=e_Human_Greet
TEVENTS=e_Human_Space
TEVENTS=e_Human_Needs
TEVENTS=e_Human_Refuse
TEVENTS=e_Human_Environ

CATEGORY=Civilized
SUBSECTION=Tradesmen
DESCRIPTION=Alchemist (male)

ON=@Create

NPC=brain_vendor
COLOR=colors_skin
STR={36 50}
DEX={36 50}
INT={51 65}


ALCHEMY={55.0 78.0}
TASTEID={55.0 78.0}
WRESTLING={15.0 38.0}
MAGICRESISTANCE={25.0 48.0}
TACTICS={15.0 38.0}
POISONING={35.0 55.0}


ITEMNEWBIE=random_male_hair
COLOR=colors_hair
ITEMNEWBIE=random_facial_hair
COLOR=match_hair


ON=@NPCRestock

ITEM=i_expcoin,3


ITEM=i_shirt_plain
COLOR=colors_all
ITEM=random_pants
COLOR=colors_all
ITEM=i_robe
COLOR=colors_red
ITEM=random_shoes
COLOR=colors_neutral
ITEM=random_coin_purse


SELL=VENDOR_S_ALCHEMIST
BUY=VENDOR_B_ALCHEMIST


[CHARDEF 0490] We've seen this before. It says "Hey SPHERE! Everything after this line until the next header is going to define a character!" What is this character going to be? Well, right now we have no idea, it's just 0490 to SPHERE. The 0490 also shows the client what anim to show (except for monsters with the ID field, which will show the ID field anim). You can also use the char defname in the [CHARDEF x] field instead of a number (which is better for new npcs), for example: [CHARDEF c_new_monster]


DEFNAME=C_H_ALCHEMIST This is the defname for this script, obviously. We've seen things like this so many times, I don't believe I need to go over it. But now at least we have a more memorable name for this script. It's obviously a character (C), a human (H), and an alchemist (C_H_ALCHEMIST). Try to make your DEFNAMEs make sense based on what the character is. Calling this c_robed_man would have absolutely no memorable qualities.  :)


NAME=#NAMES_HUMANMALE the Alchemist This is where SPHERE does some funky stuff. First of all, if you remember from the SPHERE_NAME.SCP lesson in Chapter 2, it is going to replace #NAMES_HUMANMALE with an actual name for this NPC, such as "Fritz", "Bob" or the ever popular "Roderick". The second thing it is going to do is divide this name into a NAME and a TITLE. Where does it do this division? At the word "the". So writing this line is equivalent to:


NAME=#NAMES_HUMANMALE
TITLE=the Alchemist


ID=C_MAN Here is where we actually tell SPHERE what this thing is. What is C_MAN? It's a DEFNAME obviously, but for what? Look up toward the top of this file, and you'll see the definition of the C_MAN character.


And so on. As you can see, we're just duplicating what we've written in the previous section. But with the newer versions of SPHERE we don't need to do that. Our character 0490 automatically gets everything that comes default on a C_MAN, including abilities, icons, and sounds, UNLESS WE SAY OTHERWISE. In programming, this is called inheritance. The new, more specific character inherits the properties of the less specific one.


You'll notice that we respecify DESIRES and AVERSIONS. Why do we do this if C_MAN has already told us what this type of character wants and doesn't want? Well I'm not sure in the case of AVERSIONS, because, well, they're the same. But the DESIRES of an alchemist are different than the DESIRES of a generic man, so we tell SPHERE, "Hey, replace the C_MAN desires with our new ones!"


TSPEECH= What do you suppose those cryptic names are following this statement? Of course, they're DEFNAMEs, but for what? If you look through your files, chances are you won't find those defined anywhere.. But what's this? We have a folder called speech that comes preconstructed in the zip file. Looking through those files reveals a wealth of [SPEECH] block definitions. The default ones can be found at the SPEECH folder on your scripts folder.


We'll look at a very simple speech script right now. I am not taking this from any file.


[SPEECH spk_human_test]
ON=*hello*
SAY Cheese!


In our script, if we were to write TSPEECH=spk_human_test, our NPC would respond with "Cheese!" any time we said "hello" to him. You might be wondering why I have surrounded this word with stars (*). In programming lingo, a star means "ANYTHING". So you could say "I want to eat you hello goodbye" and the NPC would still respond with "Cheese!", because the word "hello" was present.


Of course, SPEECH is much more complicated than that and we'll look at it again when we reach the chapter on basic event scripting. Just know for now that you can have as many TSPEECH lines as you wish in a CHARDEF section.


TEVENTS= We've already covered this in a very very tiny amount of detail in Chapter 1. This is where events for the creature are defined. As you can see, this creature contains a great deal of events. They define everything from what he says when he hears an unknown word ("Huh?"), to what he does when he sees a new player. We'll look at an event script in Chapter 8. You should learn the basics of item scripting before you try NPC event scripting. For now just know that you can retrieve all the TEVENTS of a npc by using <[REF].TEVENTS>.


ON=@Create Actually, I lied. @Create is an event, and we're going to talk about it right now. But it's a special event, as is the next one we're going to discuss. Basically, @Create causes every line after it to be processed (the entire section highlighted in red) when an object is Created. Creative eh? (Ha, ha.) In this case, I'm not going to concentrate on most of the lines following, as they should all make sense to you now. All you need to know at this point about @Create is that things you can change IN GAME go under this section. This includes stats, skills, unlootable items, colors, brain types, and TAGs (Although tags can be defined on CHARDEF too, it's a great way to set a tag to all npcs with that chardef without needing to do a restock or change one by one) (You don't know what a TAG is? Good, I haven't taught you yet.).


ALCHEMY={55.0 77.0} This line is very deceiving, and the reason for the deception is the way that SPHERE processes numbers. SPHERE cannot, ever, read a decimal number. 55.0 means nothing to SPHERE, and it simply strips out the decimal point. Now, isn't it convenient that internally, skills are stored as big numbers? Look at your skills menu in-game right now. Find a skill that isn't zero, obviously, and look at the value.


It looks like this: 42.0


Now, in-game again, type this command: .set [skillname] 42 (Of course, replacing [skillname] with the skill of your choice. Refer to spheretables.scp if the name you're typing doesn't work.) What happened? Your skill suddenly went to 4.2!! Is this an error in the game? No, actually it's because skills are stored by removing the decimal point. If you have 100.0 in blacksmithing, your skill is actually set to 1000. If you have 75.2 in a skill, that skill is 752.


This may seem like a simple concept, but it also applies to the REST of scripting as well. Any time you type a number like 55.0, SPHERE eliminates the decimal. So our example line above is actually this:


ALCHEMY={550 770}


Isn't that sneaky?


One of the times you might want to remember this is later, if you are multiplying numbers:


4 * 0.5


Sphere translates this as "4 times 5" and you get 20, rather than the 2 you were expecting. As you can see, this may cause serious problems. I'll show in later chapters how to get around this problem. I just wanted to point out here that it exists. (Look back at the resource tables in sphereregion.scp for another example of where sneaky decimal points are used.)


NPC=brain_vendor Ok, so I'm out of order. Deal with it.


All NPCs in the game are controlled by specific intelligences, which direct the way they act in certain situations. For instance, this alchemist is a brain_vendor, which means he responds to commands like "buy" and "sell" by opening up a trade window. It also means that he is allowed to have extra storage space for information dealing with the items he can buy and sell. (Actually they are additional containers stored on the vendor, but we shall see that later.) Here is a list of the other intelligences available (I bet you can't guess which file I pulled this from):


[DEFNAME brains]
BRAIN_NONE 0 // Players: No brain. Convenient eh?  :)
BRAIN_ANIMAL 1 // Animals: wander, attack only if attacked
BRAIN_HUMAN 2 // Human: wander and speak
BRAIN_HEALER 3 // Healer: heal ghosts in proximity
BRAIN_GUARD 4 // Guard: attack bad guys I see
BRAIN_BANKER 5 // Banker: you can access your bank through him
BRAIN_VENDOR 6 // Vendor: buys and sells things
BRAIN_BEGGAR 7 // Beggar: follows players around asking irritating questions
BRAIN_ANIMAL_TRAINER 8 // Trainer: can stable animals
BRAIN_THIEF 9 // Thief: no effect right now
BRAIN_MONSTER 10 // Evil: attack all players we see
BRAIN_BERSERK 11 // Crazy: attack anything we see
BRAIN_UNDEAD 12 // Undead: same as evil, just used for identification
BRAIN_DRAGON 13 // Dragon: breathes fire (set this on a rabbit)
BRAIN_VENDOR_OFFDUTY 14 // No idea what the difference is here
BRAIN_TOWNCRIER 2 // Same number as brain_human, same effect
brain_beserk brain_berserk //Same thing as brain_berserk, just to avoid some errors by typos


ITEMNEWBIE= This creates the specified item with the attr_newbie on the char.


ON=@NPCRestock I lied twice! This is the SECOND event you're going to learn in this script. This event is triggered when a "restock" happens in-game. This occurs once every few real-time hours, or if a staff member types ".sector.restock". What you should put here is anything lootable from this NPC, along with the definitions of things they buy and sell. Once again, this is just a template in most cases, so you should know how to deal with it. I'm going to examine two lines though:


SELL=VENDOR_S_ALCHEMIST
BUY=VENDOR_B_ALCHEMIST

This defines what the vendor buys and sells? But where are these mysterious lists of items coming from? Actually, they're templates, in the file spheretemp_vend.scp. (Templates for vendors. Those developers are so creative.) Actually it's a good thing to name files after what's inside of them.  :)


Price is not defined anywhere on these BUY and SELL lines. Price is defined in a VALUE= line in an individual item script. If an item script does not have a VALUE= line, price is determined by multiplying the value of the resources in that item by the number of resources required. For example, if an item takes 8 iron ingots to make, and each ingot has a VALUE of 8 gold pieces, the entire item is going to be worth 64 gold. By default, things sell for half of the price you can buy them for.


I think that's all you need to know for now about scripting a new NPC. Right now, with your abilities, you can create new vendors, new monsters, and new animals that wander your world. But they don't do anything unique yet. They just behave like stronger or weaker versions of the same monsters. And they're probably pretty colors, too, judging from the recent use of my hues.mul file for colors 077a and 07a1. (I really should release a DEFNAME script for those.)


Now that you know how to make a decent NPC, let's explore ways to make unique items to put on him as loot. In the next section, we're going to make a SUPER DUPER BOW OF FIRE AND BRIMSTONE! *trumpet fanfare*

Advanced Item Scripting

The Super Duper Wand of Fire and Brimstone!

[ITEMDEF i_wand_sdwfb]
NAME=Super Duper Wand of Fire and Brimstone
ID=i_wand_1
TYPE=t_wand
RESOURCES=i_wand,10 i_scroll_flamestrike

ON=@Create

ATTR=attr_magic
MOREX=s_flamestrike
MOREY=50.0
MORE2=10


I tricked you that time! We STARTED with the script. No funny introductions. No livening up the article. Just a script. And a very interesting script it is too. You won't find it in any of your files. (In case you're wondering, SDBFB stands for "Super Duper Wand of Fire and Brimstone").


Now, what does this thing do? Well it's one of those handy predefined types that makes it do what it's supposed to do. Actually, it's not the only thing here that makes it do what it's supposed to do, but we'll see that in a moment!


[ITEMDEF i_wand_sdwfb] You should be able to tell me what this does by now. We're making a new item with DEFNAME i_wand_sdwfb.

Notice that we don't explicitly declare the DEFNAME, but put it in the ITEMDEF. It's the same thing.


NAME=

Duh.  :)


ID=i_wand_1

Once again, we're inheriting some properties here, including animation, skill type (macefighting oddly enough), etc from the definition of i_wand_1.


TYPE=t_wand

Remember in our NPC script, I said that the different brain types caused the NPCs to act different ways in certain situations. Well, in items, TYPE does the same thing. Only there are more of them. A lot more. Here are the specifications of the "t_wand" type. As you can see, we use all of them in the @Create section. Note: this line wouldn't be necessary since we're getting type=t_wand from the itemdef i_wand_1 too.


MOREX = the spell this wand will cast MOREY = the skill with which the spell will be cast MORE2 = the number of charges this wand has left


Every item does something different with the MOREs. Actually this is a good time to go through the variables available to you on an item. In a simple list:


  • MORE1 (or MORE)
  • MORE2
  • MOREP
  • COLOR
  • TYPE
  • CREATE
  • LAYER
  • ATTR
  • LINK
  • CONT
  • TOPOBJ
  • LINK

As we'll see, a few of these have special functions that will allow us to do a lot more. But that doesn't come until advanced scripting. And there are also a lot more things which you'll know in future chapters.


One of these properties (MOREP) has the weirdness that it can hold a coordinate of the form (x, y, z, m). Which means that it can be broken down into MOREX, MOREY, MOREZ, and MOREM. For example, if you write this line:


MOREP=1,2,3,4


It is exactly the same as writing:


MOREX=1
MOREY=2
MOREZ=3
MOREM=4


This is what you call in C++ programming a "union", basically meaning there are going to be restrictions on the amount of data you can store in each of these variables. MOREX and MOREY can both hold numbers up to 0FFFF. MOREZ can hold numbers from -128 to 127, and is always displayed in decimal. MOREM can hold numbers from 0 to 255, and is also always displayed in decimal.


Be sure that when you're writing a script, or an item, you don't use both MOREP and one of the other MOREP pieces (MOREX, etc). It won't work together, since one will overwrite the other.


MOREP=10,42,51,53
MOREX=78
MOREY=89
MOREM=56


MOREP now is equal to 78,89,51,56.


So you see, it doesn't work to use these together.


Another strangeness of SPHERE is that they have given us the properties MORE1L, MORE1H, MORE2L, and MORE2H. These are not entirely visible to you, but just know that they are pieces of the MORE1 and MORE2 properties. As such, you should not be using both MORE1 and either of the MORE1 properties, or the same for the MORE2 properties, on a single item.


MORE1=0FFFFFFFF
MORE1L=01234
MORE1H=0F0


Now MORE1 is 000F01234. Which would totally screw up any script you were writing involving the MORE1 property. So don't use both in the same script. (If you don't understand where that number came from, don't worry about it. I've never used MORE1L and MORE1H in a script, and chances are neither will you.)


We'll also see later how to use the ATTR property to give your item special properties (like being unmovable, or magical, or blessed). I'll put that in my massive chart that's going in the next section, which lists all the TYPEs and all of the ATTR values.


From what I've just explained to you, the rest of the item script, after the @Create event, should be obvious. We're setting the pieces of MOREP to be what we need them to be so our wand functions properly. And if you create this item in the game, and double-click it, you'll get a target to cast Flamestrike. That's all you need to do.


By the way, you could just as easily have written:


MOREP=s_flamestrike,50.0
MORE2L=10


Think about it.  :)


(Anyone know why the developers decided to have 10 variables named MORE? Standing for "MORE information about an item" perhaps?)


Understanding the @Create trigger

You're probably wandering why I didn't set the item properties (such as the mores) directly on the itemdef, that's because not everything can be set there, only general properties for the items with that id.

"But hey, I can set different names for an item with the same id"

Yes you can, but mostly you won't, another thing that can be set there but you can also change are TAGs (you'll see more on other chapters).

Things that you can't change for example are WEIGHT, VALUE, RESOURCES and of course the DEFNAME. There are more, but just to make you get the idea.


TYPEs

This section explains how you can use built-in item types, how to override the built-in types, and how you can make your own.

If you want to override a built-in typedef, that is indeed possible, just define its new behavior it in a script and since the scripts are loaded after the server starts, your new definition will take precedence.

A TYPEDEF is essentially a collection of triggers, and can be written to reference other aspects of the ITEMDEF, CHARDEF, or REGION that it is assigned to. To assign a TYPEDEF to an item, you can simply set TYPE=t_mytype in the ITEMDEF (Note: An item can only have one TYPE.)

Here is an example TYPEDEF:

[TYPEDEF t_horseshoes]
ON=@DClick
   TARGET What animal needs this item?
   RETURN 1
ON=@Targon_Char
   IF (<SRC.TARG.DEX> > 100)
      SRC.SYSMESSAGE @032 That animal does not need this item.
      RETURN 1
   ENDIF
   IF (<SRC.TARG.OBODY>==(c_horse_pack|c_llama_pack|c_horse_gray|c_horse_brown_dk|c_horse_brown_lt|c_llama))
      SRC.SYSMESSAGE @032 Now the animal is faster.
      SRC.TARG.MODDEX += <MORE1>
      SRC.EFFECT=3,0374a,6,15,1
      REMOVE
   ELSE
      SRC.SYSMESSAGE @032 That animal can not wear this item.
   ENDIF
   RETURN 1

Here is an example item that uses the t_horseshoes TYPEDEF shown above:

[ITEMDEF i_horse_shoes_magic]
ID=0fb6
NAME=magic horseshoes
TYPE=t_horseshoes
VALUE=35
WEIGHT=8.0
RESOURCES=8 i_ingot_iron
SKILLMAKE=Blacksmithing 30.0
CATEGORY=Items by Professions
SUBSECTION=Blacksmiths
DESCRIPTION=Magic Horse Shoes
ON=@Create
   MORE1={10 15}
   ATTR=attr_magic

ATTRs

This is a list of the ATTR flags available and what they do. I pulled it right out of spheredefs.scp

Value DEFNAME Description
01 attr_identified Someone has used the Item ID skill on this item so it will display the full magic name "+7 Sword of Ruin of Flamestrike".
02 attr_decay The item will decay when the internal decay timer, or the item's TIMER reaches zero.
04 attr_newbie The item will not be placed in a corpse upon death.
08 attr_move_always Anyone can pick this up, even if they shouldn't be able to normally. The item will not decay unless the decay flag is also set.
010 attr_move_never Locked down. Probably the one you'll use most often. It will never decay, even if the decay flag is set.
020 attr_magic This item has been enchanted
040 attr_owned This is owned by the town, and trying to pick it up will count as stealing. You will be flagged criminal if you try to use the Stealing skill on this item. It will never decay.
080 attr_invis Invisible to non-GM clients
0100 attr_cursed Cursed item, casts curse on the wearer while it's equipped
0200 attr_cursed2 I have no idea what the difference is.. strength maybe?
0400 attr_blessed Casts bless on the person who is equipping it (stat gain)
0800 attr_blessed2  ?
01000 attr_forsale In a vendor's sell-box or buy-box.
02000 attr_stolen This item has been stolen (from the town probably)
04000 attr_can_decay I think this is used to get rid of those irritating errors "TIMER has expired without decay flag".
08000 attr_static Makes it so an item doesn't highlight when a player passes the mouse over it. (Items will still highlight for GMs no matter what.)

You can, of course, have multiple ATTRs on a single item like this:


ATTR=attr_magic|attr_decay|attr_move_never


If you have a @Timer script on an item, you must have an attr_decay on that item. Otherwise you will get scary errors. You can always RETURN 1 from the @Timer script to prevent decay, but the flag must still be there.

Cool Commands

Or, how to make a huge number of NPCs die at once


There are a few often overlooked commands in the SPHERE scripting language, and the in-game command set. These are:

  • .nuke
  • .nukechar
  • .region.sectors restock

You may not understand the format of the last command yet, but I will tell you how to use it anyway.


One thing that make SPHERE scripters do not realize is that the .nuke and .nukechar commands can take parameters, and that those parameters will be applied to any items within the targetted area.


Type .nuke and target a box. All the items disappear.


Now type .nuke color 02 and target a box. All the items in the box turn blue.


.nuke dupe is an interesting command that creates a duplicate of any item in the box.

.nukechar works the same way:

.nukechar kill will kill any NPC you target inside of the box.


Note: BOX can mean the world too, but if you target the ground it'll ask for a second targetting and will peform the actions in all chars/items in the area you selected)


Now, after you have spawned your world, if you make massive changes to your Vendor files, the changes WILL NOT take effect on already-spawned NPCs. And I'm sure you don't want to go around the world resetting every single vendor. But there's an easier way. Do these two commands in order:


.go 11 11 .region.sectors restock or just .region.restock

(since from 56b region.X will automatically access all the sectors of this region too)


Magically, all your Vendors will be restocked!


NOTE TO VETERANS: NEVER, EVER TYPE .region.restock all!!! It will freeze the server!


Extra: If you want to respawn all of your npcs across all maps you need to create a function to do that, here's an example:


[FUNCTION redospawns]
GO 1,1
FOR 0 4 //make loop through all 5 maps
    MAP = <LOCAL._FOR> //set the map
    FORCHARS 8000 //loop through all chars in the world (unless EA makes a map bigger than 8000x8000 squares)
        REF1 = <MEMORYFINDTYPE.memory_ispawned.LINK> //set REF1 to the spawngem of that npc
        IF (<REF1>) //checks if the npc has the spawn memory
            REF1.TIMER = <EVAL {<REF1.MOREX> <REF1.MOREY>} * 60> //set the spawn memory timer to the values specified when creating it
        ENDIF
    ENDFOR
ENDFOR