wolfNPC
Wolf Territoriesinteger wolfNPC(string command, string value)
Controls the WolfNPC this script is in (a resident's own NPC made with the WolfNPC window: a WolfAvatars body brought to life by the region). command is one of AI, BEHAVIOUR, WANDER, GOTO, FOLLOW, SAY, ANIM, ANIM_LOOP, ANIM_STOP, SOUND, HOME, STOP, PAUSE, NAME, SPECIES, TAG, TAGS, PACK, LEADER, GROUP, INDOORS, SHY, VISITORS, SPEED, HUNTABLE, HEALTH, RESPAWN, HUNT, SIGHT, DAMAGE, ATTACK_COOLDOWN, GIVE_UP, CHASE_SPEED, JOB, ROUTINE, PLACE, SIT, VOICE, DAILY_LIMIT, NPC_TALK, WHEN, UNWHEN, DRIVE, ROUTE, PARK, EXIT, PASSENGER; value is its setting as text, e.g. wolfNPC("AI", "I am a wolf who likes to bite people...") or wolfNPC("WHEN", "near|name:Luke Coda|10|anim:dance;sound:luke tune;once=visit"). AI talk and voice use the NPC owner's Wolf Credits. Only works from a script inside the NPC. Returns 1, or 0 with wolfGetLastError saying why. Defined on Wolf_Api.wolfNPC / WolfNPCModule.
Gives your WolfNPC a script of its own. A WolfNPC is one of your WolfAvatars people or animals that you have put on your land as a living character with Wolf World > WolfNPC in WolfViewer or WolfStorm; edit it and drop the script into its Contents like any object. Everything the WolfNPC window sets, a script can set too. Some commands are what it does now: SAY, ANIM, ANIM_LOOP, ANIM_STOP, SOUND, GOTO, FOLLOW, SIT, STOP, BREATH (dragons only), HOME "go" and PARK. All the others change its kept settings, saved on the NPC exactly as if you had pressed Save in the window and checked by the same rules. Only a script inside the NPC that belongs to the NPC's owner is obeyed, and kept settings also need you still to own the region, be one of its estate managers, or own the parcel under its home. Commands are not case-sensitive. Numbers are written as text ("10"), positions as "x,y,z" in region coordinates ((string) of a vector works too), and on/off settings take "1" or "0" (on/off, yes/no and true/false work too). WHEN rules make it react by itself: wolfNPC("WHEN", "<near or leave>|<who>|<metres>|<what to do>"). near fires when someone comes within the distance (1 to 96 m), leave when they go beyond it again. Who: * or anyone (any avatar), npc (any NPC), anything (either), owner (you), group (an avatar in the NPC's group), friend (one of your friends), stranger (someone it has not seen for 30 days), player or notplayer (playing the region's game or not), attacker (hit it in the last 5 minutes), name:<name> (an avatar's or NPC's name, any case, with * and ? as wildcards; a name on its own works too), key:<key>, and for NPCs kind:<a species such as wolf, or animal or person>, pack:<name>, group:<name> and tag:<tag>. Several, split by commas, means any of them; not: in front of one leaves those out ("not:owner" is everyone but you). What to do, up to 6, split by semicolons: anim:<name> (once), loop:<name>, stop:<name>, sound:<name or key> (add :0.5 for half volume), say:<words>, face, follow, approach, flee, ai:<an instruction for its AI, such as greet them warmly> and intent:<roam, follow, rest, approach, flee, hunt, goto, circle, howl, guard, sit, talk, work or home>, and for a dragon intent:breathe fire or intent:breathe ice (at the person it reacts to). Then, if you like: once=visit (once each visit; a visit ends when they have been away for gap minutes), once=day, once=ever, cooldown=<seconds between two firings for the same person>, gap=<minutes, 1 to 1440, 10 if not given> and id=<a short name for the rule>. The words after say: cannot contain ; or |. Give every rule an id: a rule with the same id replaces the old one, so a script that sets its rules again in state_entry does not pile them up (an NPC has at most 16 rules). wolfNPC("UNWHEN", "<id>") removes one rule, "all" removes them all. It remembers whom it has greeted across region restarts. Its own scripts hear what happens through link_message with num WOLF_NPC_EVENT: str is "near|<rule id>|<name>" or "leave|<rule id>|<name>" when a rule fires (after its actions), "touch|<name>" when someone clicks it, "choice|<dialogue>|<node>|<label>" when someone picks a dialogue choice, "quest|<quest id>|<player name>" when a player finishes one of its quests, "skill|<skill id>|<name>" when it starts a skill, "event|<event id>|start" and "event|<event id>|end", "hurt|game|<name>" and "dead|game|<name>" when it is hit or defeated in the region's game, "respawn|game|" when it comes back at home, and for a dragon "breath|fire|<name>" or "breath|ice|<name>" when it starts breathing (at that avatar, or straight ahead when the name is empty) and "breath|end|" when it stops; id is the key of the avatar or NPC (its own key for event and respawn). The game commands (flags, opinions, quests, trading, giving game items or money) only work when the region's game belongs to the NPC's owner and the avatar is playing it (Game Mode on); for anyone else they are skipped, while talk, dialogue text, sounds, animations and handouts still work. Only a player's own click in a dialogue or a shop can ever take items or money from them. Authority: you, the region's owner and its estate managers, and the owner of the parcel under its home can also tell it by chat (its name and "follow me", "stay", "stay here", "go home", "stop" or "come here", free, no AI), and with AI on can change some of its settings by asking; visitors cannot. A new AI personality or skill text is checked first (nothing sexual, for anyone): the command still returns 1, the change is made only once the check has passed, and a refusal shows in the WolfNPC window as "Not changed" with the reason. Hunting and fighting (hunt and circle) only ever go for players of the region's game, or someone who attacked it, and only the NPCs of the game's owner hunt at all. AI talk and a voice (AI, VOICE) spend the NPC owner's Wolf Credits, never the speaker's: it answers people who say its name in local chat within 20 m, or who talk to it standing within 4 m, and it spends nothing while no real person is near. It sleeps while nobody is within 96 m (its rules wait till someone comes), and a paused NPC does not react at all. Returns 1, or 0 with wolfGetLastError saying why. Regions take it up as they restart onto the new release.
Parameters
| Type | Name | What it does |
|---|---|---|
| string | command | What to do or change (see the lists under the example). Not case-sensitive. |
| string | value | Its setting, as text: words, a number, "x,y,z", "1"/"0", a key or a name. "" where none is needed (STOP, PARK, EXIT). |
How players use it, and more examples: the WolfNPC guide.
Example
// Grey, a wolf with a personality - Wolf Territories, wolfNPC / wolfNPCInfo / WOLF_NPC_EVENT.
//
// Make a wolf (or any animal) in WolfAvatars, put it on your land with Wolf World > WolfNPC,
// then edit the wolf and drop this script into its Contents. Grey then:
// - roams up to 25 m round its home and talks as itself with its own AI personality: people who
// say "Grey" in local chat within 20 m, or talk to it standing right beside it, get an answer.
// That spends YOUR Wolf Credits (at most 50 a day here). Set AI_ON to FALSE for a wolf that
// never talks;
// - greets Luke Coda once each visit: turns to him, howls and says hello;
// - turns to look at strangers once a day, and sits down to watch you leave;
// - and this script hears every one of those, so it can do more: here it counts Luke's visits
// and tells you about strangers.
// Touch it (owner only) to hear what it is doing.
//
// Rules the grid keeps: only a script owned by the NPC's owner, inside the NPC, is obeyed; its
// kept settings also need you still to own the region, be an estate manager there, or own the
// parcel under its home. Every rule has an id=, so setting them again after a reset replaces them.
integer AI_ON = TRUE;
integer lukeVisits; // kept until the script is reset
npc(string command, string value)
{
if (!wolfNPC(command, value))
llOwnerSay(command + " refused: " + wolfGetLastError());
}
default
{
state_entry()
{
npc("NAME", "Grey");
npc("BEHAVIOUR", "roam"); // animals: roam, stay, guard, follow, predator
npc("WANDER", "25"); // metres round its home
npc("VISITORS", "friendly");
if (AI_ON)
{
npc("AI", "You are Grey, an old grey wolf who has lived in this forest all your life. "
+ "You are gruff with strangers but loyal to your friends, you love the full moon, "
+ "and you answer in one or two short sentences, sometimes with a growl.");
npc("DAILY_LIMIT", "50"); // Wolf Credits a day for this wolf
}
else
npc("AI", "off");
// when | who | metres | what to do ; options
npc("WHEN", "near|name:Luke Coda|10|face;anim:wolfnpc_howl;say:Luke! The forest missed you.;once=visit;id=luke");
npc("WHEN", "near|stranger,not:owner|15|face;once=day;id=stranger");
npc("WHEN", "leave|owner|20|anim:animal_sit;id=bye");
}
link_message(integer sender, integer num, string str, key id)
{
if (num != WOLF_NPC_EVENT)
return;
list f = llParseStringKeepNulls(str, ["|"], []);
string what = llList2String(f, 0); // near, leave, hurt, dead or respawn
string rule = llList2String(f, 1); // the rule's id, or "game"
string name = llList2String(f, 2); // who it was about (id is their key)
if (what == "near" && rule == "luke")
{
++lukeVisits;
if (lukeVisits % 10 == 0)
npc("SAY", "That is " + (string)lukeVisits + " visits, Luke. You are one of the pack now.");
}
else if (what == "near" && rule == "stranger")
llOwnerSay("Grey has met a stranger: " + name);
else if (what == "leave" && rule == "bye")
npc("SAY", "*watches you go*");
// Only when Grey can be hunted in the region's game (the WolfNPC window, Game):
else if (what == "hurt")
llOwnerSay(name + " hurt Grey. " + wolfNPCInfo("STATE"));
else if (what == "dead")
llOwnerSay(name + " defeated Grey. It comes back at home after its respawn time.");
else if (what == "respawn")
npc("SAY", "*shakes itself and trots home*");
}
touch_start(integer n)
{
if (llDetectedKey(0) != llGetOwner())
return;
// STATE is "what it is doing|awake or asleep|alive or dead|health/max"
list s = llParseStringKeepNulls(wolfNPCInfo("STATE"), ["|"], []);
llOwnerSay("Grey - doing: " + wolfNPCInfo("INTENT") + "; " + llList2String(s, 1) + ", "
+ llList2String(s, 2) + ", health " + llList2String(s, 3));
}
}What it does now (any script of yours inside it)
wolfNPC("SAY", "Welcome to the forest.");
wolfNPC("ANIM", "wolfnpc_howl"); // once: an animation in its Contents, or a standard one such as "DANCE1"
wolfNPC("ANIM_LOOP", "animal_sit"); // over and over (layered over its walking)
wolfNPC("ANIM_STOP", "animal_sit"); // "" stops them all
wolfNPC("SOUND", "howl"); // a sound in its Contents, or a sound's key
wolfNPC("GOTO", "128,128,25"); // or the name of one of its places (PLACE)
wolfNPC("FOLLOW", "Luke Coda"); // an avatar or NPC on this region, by name or key; "" stops
wolfNPC("SIT", (string)seat); // the key of a prim with a sit target; "" stands up
wolfNPC("STOP", ""); // stand still and forget what it was doing
wolfNPC("HOME", "go"); // walk home (and get out of any vehicle)
wolfNPC("BREATH", "fire|3"); // a dragon breathes fire for 3 s ("ice|5", "stop"; 0.5 to 20 s, none = 3)How it lives (kept settings)
wolfNPC("BEHAVIOUR", "stroll"); // animals: roam, stay, guard, follow, predator; people: stroll, stay, guard, follow, work, zombie
wolfNPC("WANDER", "20"); // up to 20 m round its home (2 to 128); "0" = stays put
wolfNPC("HOME", "here"); // where it stands now becomes home, or "x,y,z"
wolfNPC("NAME", "Grey"); // 1 to 48 characters
wolfNPC("SPECIES", "wolf"); // one word
wolfNPC("TAG", "moonfang"); // adds a tag; TAGS sets them all: "moonfang,elder" (up to 8)
wolfNPC("PACK", "moonfang"); // your NPCs with the same pack (people: GROUP) name go about together
wolfNPC("LEADER", "1"); // this one leads its pack
wolfNPC("INDOORS", "never"); // never, allowed, or area (only inside its area)
wolfNPC("SHY", "0.3"); // 0 bold to 1 timid
wolfNPC("VISITORS", "wary"); // friendly, ignore, wary or hostile
wolfNPC("SPEED", "1.5"); // walking speed in m/s, 0 to 10 (0 = its own)
wolfNPC("PAUSE", "1"); // stands still and does nothing; "0" carries onPeople: a job, places and a daily routine (grid time, the clock in your viewer)
wolfNPC("JOB", "bartender"); // shopkeeper, guard, bartender, dancer, musician, wanderer; "bartender|x,y,z" for its spot
wolfNPC("PLACE", "market|here"); // a named place (up to 16): "name|x,y,z" or "name|here"
wolfNPC("ROUTINE", "08:00 market; 12:00 work; 18:00 tavern; 23:00 home"); // a place name, or home, work, roam, rest, sit (up to 12)Talk and AI (on the NPC owner's Wolf Credits)
wolfNPC("AI", "You are Mags, the harbour master. Brisk, kind, loves boats."); // sets its personality and turns AI on (up to 1000 characters)
wolfNPC("AI", "off"); // "on" turns it back on with the same personality
wolfNPC("VOICE", "off"); // or a voice from the WolfNPC window: it speaks its replies aloud (costs more)
wolfNPC("DAILY_LIMIT", "100"); // at most this many credits a day for this NPC; "0" = no limit
wolfNPC("NPC_TALK", "1"); // may chat with other NPCs while a real person is within 20 mThe region's game (only for NPCs of the game's owner)
wolfNPC("HUNTABLE", "1"); // players can hunt it
wolfNPC("HEALTH", "200"); // 1 to 10000
wolfNPC("RESPAWN", "300"); // seconds after it is defeated until it is back at home (10 to 86400)
wolfNPC("HUNT", "1"); // hunts the game's players (predator and zombie turn it on)
wolfNPC("SIGHT", "20"); // metres it sees players from (2 to 64)
wolfNPC("DAMAGE", "health:5;strength:2"); // per hit, up to 4 of the game's stats (1 to 1000 each)
wolfNPC("ATTACK_COOLDOWN", "2"); // seconds between hits (0.5 to 30)
wolfNPC("GIVE_UP", "40"); // stops chasing this far from home (5 to 128 m)
wolfNPC("CHASE_SPEED", "5.5"); // m/s, 0 to 12 (0 = its own)
wolfNPC("XP", "25"); // XP for the player who defeats it, if the game has an xp stat
wolfNPC("LOOT", "wolf pelt:1"); // "item:how many" (1 to 1000), a game item for that playerRules: react by itself
wolfNPC("WHEN", "near|kind:wolf|15|anim:wolfnpc_howl;once=day;id=howl"); // another wolf NPC comes near
wolfNPC("WHEN", "near|not:owner|20|say:Who goes there?;cooldown=300;id=who");
wolfNPC("WHEN", "near|player|12|intent:flee;id=run"); // runs from the game's players
wolfNPC("WHEN", "near|friend|8|approach;ai:greet them like an old friend;once=visit;id=pal");
wolfNPC("UNWHEN", "who"); // or "all"
// Who, for game players only: flag:<flag>, rep:<faction or me><op><n> (op >=, <=, >, < or =; n -100 to 100),
// quest:<id> (has it now), done:<id> (has finished it), e.g. "player,not:flag:met_martha" or "rep:me>=50".
// More things to do (game ones only for players): flag:<f>, unflag:<f>, rep:<faction or me>:<+n or -n>,
// give:<item>:<how many>, money:<+n>, xp:<n>, quest:<id> (offer it), accept:<id>, advance:<id>, drop:<id>,
// dialog:<id>, shop, handout:<name>, event:<id>, endevent:<id>, goto:<place>, skill:<id>.
// take: and money:-n only work in a dialogue choice or a shop (the player's own click).
wolfNPC("WHEN", "near|player,not:flag:met_martha|8|face;dialog:intro;flag:met_martha;id=meet");Vehicles (the bus driver example is on wolfNPCInfo)
wolfNPC("DRIVE", (string)car + "|x,y,z;x,y,z;x,y,z;loop"); // drives your car round the points; ";back" = there and back
wolfNPC("DRIVE", (string)car + "|roads"); // wanders the region's roads, if it has a road network
wolfNPC("ROUTE", "x,y,z;x,y,z;back"); // a new route (2 to 64 points); a driver takes it at once, from the point nearest the car
wolfNPC("PARK", ""); // stops where it is; PARK "0" drives on
wolfNPC("EXIT", ""); // gets out and walks again
wolfNPC("PASSENGER", (string)car); // rides in a free seat that is not the driver'sThe game: players, quests, dialogue and trading (the region's game must be the NPC owner's)
wolfNPC("FLAG", (string)avatar + "|met_martha"); // a flag on that player (letters, digits, _ and -, up to 24); UNFLAG clears it
wolfNPC("REP", (string)avatar + "|me|+5"); // their standing with this NPC (or a faction's name), changed by 1 to 200; kept in -100 to 100
wolfNPC("DIALOG", "intro|" + (string)avatar); // opens one of its dialogues with an avatar on the region
wolfNPC("QUEST", "martha_bread|" + (string)avatar); // offers a quest; QUEST_ACCEPT, QUEST_ADVANCE (finish the current step), QUEST_DROP
wolfNPC("SHOP", (string)avatar); // opens its shop for that player
wolfNPC("HANDOUT", "Welcome notecard|" + (string)avatar); // anyone: a notecard, texture or landmark from its root prim (once in 10 minutes each)
wolfNPC("EVENT", "zombies"); // starts one of its events now; EVENT_END ends it
wolfNPC("CFG", "{\"faction\":\"moonfang\"}"); // any of its settings as JSON, as the WolfNPC window saves them:
// dialogues, quests, shop, events and skills merge by id ({"id": null} removes one)
wolfNPC("GAME_ONLY", "1"); // only people playing the game (Game Mode on) get anything from it; "0" = everyone
wolfNPC("PET", (string)petKey); // becomes one of your pets in the region's game and follows you; "" unlinksSkills and tools (things it uses)
// Skills are kept in its settings (the WolfNPC window, or CFG): up to 12, each with a name, up to 4 chat
// keywords and up to 12 steps. Visitors can only set off a skill whose steps are all visitor-safe (say, emote,
// anim, face, wave, wait, walking within its area, handing out an item with wolfnpc-handout in its description).
wolfNPC("SKILL", "serve_drink"); // runs one of its skills now, with your authority
wolfNPC("SKILL", "serve_drink|" + (string)avatar); // ... for that avatar
// Tools: up to 8 of YOUR objects, each with a role name it can walk to, sit on or use like a place:
// whiteboard, seat, counter, vehicle, dispenser or place. Setting "tools" replaces the whole list.
wolfNPC("CFG", "{\"tools\":[{\"type\":\"dispenser\",\"id\":\"" + (string)tap + "\",\"role\":\"tap\"}]}");
// A skill step {"do":"use","role":"tap"} walks it within 2 m and tells every script in the tap:
link_message(integer sender, integer num, string str, key id) // in the tap's own script
{
if (num == WOLF_NPC_TOOL) // str = "use|<role>|<npc name>", id = the NPC's key
llSay(0, llList2String(llParseString2List(str, ["|"], []), 2) + " pulls a pint.");
}The whiteboard: BOARD steps (a whiteboard tool first; "role" can be left out when it has only one)
wolfNPC("BOARD", "{\"do\":\"board_clear\"}");
wolfNPC("BOARD", "{\"do\":\"board_write\",\"text\":\"Hello class\",\"x\":0.05,\"y\":0.1,\"size\":2,\"colour\":\"navy\"}");
wolfNPC("BOARD", "{\"do\":\"board_equation\",\"text\":\"x^2 + 2x = 15\",\"x\":0.1,\"y\":0.4,\"size\":3}"); // ^2 ^3 sqrt pi >= <= != * +- as maths signs
wolfNPC("BOARD", "{\"do\":\"board_draw\",\"shapes\":[{\"kind\":\"arrow\",\"from\":[0.1,0.8],\"to\":[0.4,0.8]},{\"kind\":\"circle\",\"centre\":[0.7,0.5],\"r\":0.1}],\"colour\":\"red\"}");
wolfNPC("BOARD", "{\"do\":\"board_highlight\",\"from\":[0.05,0.35],\"to\":[0.6,0.5]}");
// x and y are 0 to 1 from the top left of the board; size 1 to 5 (2 reads well at 10 m on a 2 m board);
// text up to 300 characters, wrapped; colours black, navy, blue, red, green, purple, orange; shapes are line,
// arrow, box, circle and graph (2 to 32 points, 0 to 1 inside its from-to box, upwards, drawn with axes), up to
// 12 a step. At most 40 things on a board (the oldest go). Everyone sees it, in any viewer; the board is redrawn
// at most every 2 seconds and again after a region restart.Example: a teacher who writes a lesson on her whiteboard when someone touches her
// Put this in a person NPC standing by a board of yours called "Whiteboard" (within 20 m).
string BOARD_NAME = "Whiteboard";
board(string step)
{
if (!wolfNPC("BOARD", step))
llOwnerSay("BOARD refused: " + wolfGetLastError());
}
default
{
state_entry()
{
llSensor(BOARD_NAME, NULL_KEY, ACTIVE | PASSIVE | SCRIPTED, 20.0, PI);
}
sensor(integer n)
{
// Link the board as her one whiteboard (face 0 of its prim; -1 = every face).
if (!wolfNPC("CFG", "{\"tools\":[{\"type\":\"whiteboard\",\"id\":\"" + (string)llDetectedKey(0)
+ "\",\"role\":\"board\",\"face\":0}]}"))
llOwnerSay("Cannot use the board: " + wolfGetLastError());
}
link_message(integer sender, integer num, string str, key id)
{
if (num != WOLF_NPC_EVENT || llGetSubString(str, 0, 5) != "touch|")
return;
board("{\"do\":\"board_clear\"}");
board("{\"do\":\"board_write\",\"text\":\"Today: quadratic equations\",\"x\":0.05,\"y\":0.05,\"size\":2,\"colour\":\"navy\"}");
board("{\"do\":\"board_equation\",\"text\":\"x^2 + 2x - 15 = 0\",\"x\":0.05,\"y\":0.3,\"size\":3}");
board("{\"do\":\"board_equation\",\"text\":\"(x + 5)(x - 3) = 0\",\"x\":0.05,\"y\":0.5,\"size\":3}");
board("{\"do\":\"board_highlight\",\"from\":[0.04,0.7],\"to\":[0.5,0.85]}");
board("{\"do\":\"board_write\",\"text\":\"x = 3 or x = -5\",\"x\":0.05,\"y\":0.72,\"size\":3,\"colour\":\"red\"}");
board("{\"do\":\"board_draw\",\"shapes\":[{\"kind\":\"graph\",\"from\":[0.6,0.3],\"to\":[0.95,0.9],"
+ "\"points\":[[0,0.9],[0.25,0.3],[0.5,0.05],[0.75,0.3],[1,0.9]]}],\"colour\":\"blue\"}");
wolfNPC("SAY", "Good morning, " + llList2String(llParseString2List(str, ["|"], []), 1)
+ ". Bring everything to one side, factorise, then set each bracket to nought.");
}
}Ours alone. Grid features you will not find on any other OpenSimulator grid.