Building & Scripting > Scripting Board
Trigger of the .... something
erwin:
This will be a post out of three posts, introducing functions, in order to achieve the goal of replacing characters of a sentence.
For example, given a string (of words, not sausages):
It was the best of times, it was the worst of times
and you want to replace the second letter of the tenth word by a u, eg to
It was the best of times, it was the wurst of times
how can you do so?
While this doesn't seem very useful from the sound of it, inventive scripters can script games (eg a game of battleship), by doing something like:
set grid .......... .......... .......... .......... .......... .......... .......... .......... .......... ..........
and if they want to fire at a position, and denote the fired position as an *, then the challenge is to convert
.......... .......... .......... .......... .......... .......... .......... .......... .......... ..........
into
.......... .......... .......... .......... .......... .......... ...*...... .......... .......... ..........
for example.
Also, the best part about functions is that they can be reused again and again, and they just need to be called in the script. One idea is to have a zone full of (useful) functions, so all builders can call them (without taking up trigger vnums in their own zone), plus it gives some kind of signal to coders :P about which functions are useful to be added into the dg code.
As an aside, functions are very useful for doing the same things over and over again. If you have a main quest in a zone where the quest reward is only given when six side quests are done, you don't want to write the same script six times - to check if the main quest reward should be given when any of the six side quests have been completed.
So today's trigger of the day will focus on counting the number of "objects / words / items" in a variable. We will use this function in the next two posts to achieve our goal.
Input: findnumwords
Output: num
findnumwords will be the variable we are interested in finding the number of words of, and num the number of words.
Here is the function.
--- Code: ---Name: 'function to check num words', VNum: [33785], RNum: [ 2182]
Trigger Intended Assignment: Objects
Trigger Type: FUNCTION, Numeric Arg: 100, Arg list: None
Commands:
if !%findnumwords%
%echo% We do not have any inputs!
%echo% The input variable should be named findnumwords
halt
endif
set stopping_criteria 1
set start 1
while %stopping_criteria% != stop
extract num %start% %findnumwords%
if !%num%
eval num %start% - 1
set stopping_criteria stop
endif
eval start %start% + 1
done
--- End code ---
So to use the function, we just need to do this:
--- Code: ---set findnumwords I want to be a pirate
function 33785
%echo% We have %num% of words
--- End code ---
Of course, we can always do
--- Code: ---set findnumwords %actor.thisvariable%
--- End code ---
etc
The next post will be functions on replacing words in a sentence, and replacing characters in a word, before building up to the final post!
erwin:
Here is part 2, and it will be on function triggers to replace a word in a sentence, as well as to replace a character in a word.
Both function triggers are similar in execution, so hopefully it counts as one trigger of the day.
Some possibilities of these triggers (along with some modifications):
1. Make a mob rhyme with you (could replace / add on characters to the last word you say)
2. Dynamic passwords to go through a zone: (eg the second word of the password is always the day of the week)
3. Script a lot of (multi-player) games which rely on grids.
Anyway, here are these triggers!
The first trigger replaces a word in a sentence, as shown below.
--- Code: ---Name: 'Replace word in sentence', VNum: [33783], RNum: [ 2181]
Trigger Intended Assignment: Objects
Trigger Type: FUNCTION, Numeric Arg: 100, Arg list: None
Commands:
if !%sentence%
%echo% Need a sentence to replace words.
halt
endif
If !%word%
%echo% Need a word to replace a word in the sentence.
halt
endif
if !%replacenum%
%echo% Need the position of the word to replace
halt
endif
*First, find out how long the sentence is
*Recall our previous function took in the input findnumwords
set findnumwords %sentence%
function 33785
*We now have %num%, which is the length of the sentence
*Now we build up the sentence from the original sentence
if %replacenum% > 1
extract newsentence 1 %sentence%
set h 2
while %h% < %replacenum%
extract buildsentence %h% %sentence%
set newsentence %newsentence% %buildsentence%
eval h %h% + 1
done
set newsentence %newsentence% %word%
eval h %h% + 1
elseif %replacenum% == 1
set newsentence %word%
set h 2
endif
while %h% <= %num%
extract buildsentence %h% %sentence%
set newsentence %newsentence% %buildsentence%
eval h %h% + 1
done
--- End code ---
This trigger takes in the inputs: sentence, replacenum, word.
sentence - Should be set to the sentence you are looking at
replacenum - The position number of the word you want to replace
word - The new word
The trigger gives the output: newsentence
So for example, suppose you have the phrase:
I am at the bottom of the world
and you want to replace the fifth word with the word top.
Then, you would do something like:
--- Code: ---set sentence I am at the bottom of the world.
set word top
set replacenum 5
function 33783
%echo% %newsentence%
--- End code ---
and you get your new sentence to be: I am at the top of the world
The second trigger replaces a character in a word.
--- Code: ---Name: 'Replace character in word', VNum: [33782], RNum: [ 2180]
Trigger Intended Assignment: Objects
Trigger Type: FUNCTION, Numeric Arg: 100, Arg list: None
Commands:
if !%word%
%echo% Need a word to replace characters.
halt
endif
If !%character%
%echo% Need a character to replace a character in the sentence.
halt
endif
if !%replacenum%
%echo% Need the position of the word to replace
halt
endif
set len %word.strlen%
*We now have %len%, which is the length of the word
*Now we build up the word from the original word
if %replacenum% > 1
dg_letter newword 1 %word%
set h 2
while %h% < %replacenum%
dg_letter buildword %h% %word%
set newword %newword%%buildword%
eval h %h% + 1
done
set newword %newword%%character%
eval h %h% + 1
elseif %replacenum% == 1
set newword %character%
set h 2
endif
while %h% <= %len%
dg_letter buildword %h% %word%
set newword %newword%%buildword%
eval h %h% + 1
done
--- End code ---
This trigger takes in the following inputs: word, replacenum, character.
word - Should be set to the word you are looking at
replacenum - The position number of the character you want to replace
character - The new character
The trigger gives the output: newword
So for example, if you have the word
Candyland
and want something a bit more R rated, you could do the following:
--- Code: ---set word Candyland
set character R
set replacenum 1
function 33782
%echo% newword
--- End code ---
Kvetch:
I got this script from a visitor from TBA that was asked to help out on another zone. I've left in all of her comments on it even before the script because it all sounded like valuable information when dealing with the script. This should be able to be adapted for any cooking anyone wants to do. So, from Parnassus:
I've tried this on TBA and it seems to work. First, you need to decide where to put it. If you put it on a room, such as a kitchen, or a mob, such as a cooking teacher, Numeric Arg is 100. If you put it on something like a pot or a skillet, Numeric Arg is 2 (in inventory) or a heatsource, such as a stove should be 4 (in the same room).
Next, set the vnums. Each ingredient and each food needs a vnum. On TBA, I just used various foods that seemed similar, just for experimenting with.
If it works the way you wanted it, create the items. I've set up recipes for various dishes with an explanation of the bonus of each dish. Wisdom is missing since I couldn't think of anything but the dishes I have probably don't seem connected either, such as Mario's mushrooms for a constitutional boost. I'd have liked a nice dish of brains but I don't think that's an ingredient on 4d. Of course though, the trigger is extremely expandable by inserting new ingredients in one section and recipes in two sections.
If you need any changes, let me know. If it isn't what you were looking for at all, let me know that too. I can think of places to use it so it won't be wasted if you can't use it. One change might be to add a list of missing ingredients. I was thinking of that but it would add about 3 to 5 lines to each recipe as well as another 5 to 10 lines in the error section.
If you try to /fi this, it won't format. I think this is because of the mix of ifs/ends and switches/breaks. I've tried to pre-format it in sections for easier reading.
1) Name : Cooking
2) Intended for : Objects
3) Trigger types: Command
4) Numeric Arg : 2
5) Arguments : cook
6) Commands:
* Prep work - ingredients
* Insert proper vnums here.
set ing_almonds
set ing_cocoa
set ing_carrots
set ing_cheese
set ing_eggs
set ing_fish
set ing_flour
set ing_garlic
set ing_lemon
set ing_mushroom
set ing_potato
set ing_spinach
set ing_sugar
* Prep work - finished dishes
*Insert proper vnums here.
set dish_quiche
set dish_pancake
set dish_fish
set dish_mushroom
set dish_cake
set dish_fritter
* Prep work - recipes
set quiche _spinach _quiche
if %quiche.contains(_%arg%)%
set food spinach quiche
set quan a
end
set pancake _potato _pancakes
if %pancake.contains(_%arg%)%
set food potato pancakes
set quan some
end
set fish _fish _almondine
if %fish.contains(_%arg%)%
set food fish almondine
set quan some
end
set mushrooms _stuffed _mushrooms
if %mushrooms.contains(_%arg%)%
set food stuffed mushrooms
set quan some
end
set cake _chocolate _cake
if %cake.contains(_%arg%)%
set food chocolate cake
set quan a
end
set fritter _carrot _fritters
if %fritter.contains(_%arg%)%
set food carrot fritters
set quan some
end
** Start of Heatsource check
* If the trigger is on a room or a heatsource, delete this section.
* If the trigger is on an object, verify numeric arg.
* Numeric Arg 2 is in inventory, such as a pot. Numeric Arg 4 is in the same room, such as a stove.
set heatsource 0
eval inroom %self.room%
eval obj %inroom.contents%
* find the first object in the room
while %obj%
set next_obj %obj.next_in_list%
set objlist %obj.name%
if %objlist.contains(fire)% || %objlist.contains(stove)% || %objlist.contains(oven)%
eval heatsource heatsource + 1
end
* find the next object for the while to loop
set obj %next_obj%
done
if %heatsource% == 0
%send% %actor% You can't find any heat to cook with.
halt
end
** End of Heatsource check
switch %food%
case spinach quiche
* Strength - spinach quiche - eggs spinach cheese
set ing1 %ing_cheese%
set ing2 %ing_eggs%
set ing3 %ing_spinach%
set dishvnum %dish_quiche%
break
case potato pancakes
* Dexterity - potato pancakes - potato eggs flour
set ing1 %ing_eggs%
set ing2 %ing_flour%
set ing3 %ing_potato%
set dishvnum %dish_pancake%
break
case fish almondine
* Intelligence - fish almondine - fish almonds lemon
set ing1 %ing_almonds%
set ing2 %ing_fish%
set ing3 %ing_lemon%
set dishvnum %dish_fish%
break
case stuffed mushrooms
* Constitution - stuffed mushrooms - mushrooms garlic cheese
set ing1 %ing_cheese%
set ing2 %ing_garlic%
set ing3 %ing_mushroom%
set dishvnum %dish_mushroom%
break
case chocolate cake
* Charisma - chocolate cake - flour sugar cocao
set ing1 %ing_cocoa%
set ing2 %ing_flour%
set ing3 %ing_sugar%
set dishvnum %dish_cake%
break
case carrot fritters
* Night vision - carrot fritters - carrots flour eggs
set ing1 %ing_carrots%
set ing2 %ing_eggs%
set ing3 %ing_flour%
set dishvnum %dish_fritter%
break
default
%send% %actor% You don't seem to know how to cook that.
halt
break
done
if %actor.has_item(%ing1%)% && %actor.has_item(%ing2%)% && %actor.has_item(%ing3%)%
%send% %actor% You cook up %quan% %food%.
%echoaround% %actor% %actor.name% cooks up %quan% %food%.
%purge% %actor.inventory(%ing1%)%
%purge% %actor.inventory(%ing2%)%
%purge% %actor.inventory(%ing3%)%
%load% obj %ing1%
%load% obj %ing2%
%load% obj %ing3%
%load% obj %dishvnum% %actor% inv
else
%send% %actor% You don't have what you need to make %quan% %food%.
halt
end
erwin:
A nice way of repeating (mostly) similar stuff. For example, suppose you have a zone that echoes similar stuff like:
The flight to <random country> leaves at Gate <random number>. You could do something like switching cases. But a cooler way would be to do something like
--- Code: ---set vec1 Heathrow Moscow Edinburgh Frankfurt Dublin Paris Newark LAX Minneapolis Georgia Hell Amsterdam Sydney Salzburg Bratislava Japan Toronto
eval randnum1 %random.20%
eval randnum2 %random.17%
extract place %randnum2% %vec1% *we're extracting a random city from the above vector
%echo% The flight to %place% leaves from Gate %randnum2%.
--- End code ---
Tada! And you don't need to create 17 different cases for a minor change!
erwin:
What happens if we want to script a quest which went like this:
1. Give me grapes from Ancient Greece
2. Give me a laser gun
3. Give me a game
Well, most quests are specific, eg: "Give me grapes from Imbros, give me a 4D laser gun, give me a Battleship game." But what if we wanted to make sure ALL possible items are valid? Well, we could add in if statements. However, this gets tricky when more and more zones are built, and thus more items are valid?
We show how we can do this with one quest array, and how builders can copy and paste the entire script below and adapt it to any such quest.
Let the questarray be an array with 4 variables. First 3 are yes/no variables, and the last denoting whether the quest has been completed before or not.
Here are examples of some arrays
--- Code: ---* Example of quest not done
myquestvar: no no no incomplete
* Example of quest where first item and third item has been found, but player hasn't completed it
myquestvar: yes no yes incomplete
* Example of quest where player has completed it at least once before, and is trying again and he only gave the second item
myquestvar: no yes no complete
--- End code ---
Now, here is the grand script.
--- Code: ---**** CANDIDATE LIST
**** This quest accepts multiple possible items, so update this list
**** accordingly. For example, if someone typos that another item
**** might fit, then add in the new vnum to the array. This is the only
**** change you need! YEAH!
**** Number of different items needed
set numquests 3
**** Item 1
set questitem1 12345 4205 14673
set msg1 Thanks for giving me questitem1
**** Item 2
set questitem2 1222 5070 5323 64325
set msg2 Thanks for giving me item 2!
**** Item 3
set questitem3 503 703
set msg3 Thanks buddy
*** This is it! Edit the above part when more items get added - the below will do everything for you
*** Msg is optional, could add more stuff, but you get the gist.
** We're going to loop through this
** Note: This is not the most efficient way of doing so, but
** we have relatively few quest items. If you want to re-use this code
** for substantially more vnums, one way is to order the arrays in
** increasing order, and do a binary search for appropriate vnums
if %actor.varexists(myquestvar)%
set questvars %actor.myquestvar%
eval statusnum %numquests% + 1
extract status %statusnum% %questvars%
set curritem %object.vnum%
*First loop through all arrays. numquests quest items, so numquests arrays
set arrnum 0
while %arrnum% < %numquests%
eval arrnum %arrnum% + 1
extract itemarray %arrnum% %questvars%
set item%arrnum% %itemarray%
* read this array
* Note: We have to eval this, and not set, otherwise it'll be a string
eval currarray %%questitem%arrnum%%%
* So for example, if arrnum was 1, then
* currarray would be set to 12345 4205 14673 (value of questitem1)
* %echo% %currarray%
* uncomment above to check!
* Now, find the length of this array
set stopping_criteria 1
set start 1
while %stopping_criteria% != stop
extract num %start% %currarray%
if !%num%
eval num %start% - 1
set stopping_criteria stop
endif
eval start %start% + 1
done
* We've got the length of the array stored as %num%
* Now, loop through each item in the array
set j 0
while %j% < %num%
eval j %j% + 1
extract itemtocheck %j% %currarray%
* Finally, we check if it's the same item as what we want
if %curritem% == %itemtocheck%
wait 1s
mjunk %object%
* Perfect, let's set the variable to yes
set item%arrnum% yes
* Again, eval and not set
eval currmsg %%msg%arrnum%%%
say %currmsg%
* Set a variable gotcorrectitem because we want the mob to respond
* if none of the items were right
set gotcorrectitem yes
endif
done
done
* At the end of the loop, we need to do two things
* If no right item was given, then
if !%gotcorrectitem%
wait 1
say No, no, that's all wrong.
say Try to get it right next time.
mjunk %object%
wait 2
emo waves his hands and what you handed him disappears!
halt
endif
* Now, we have to check if all 3 were achieved, and concurrently update
* the new variable. Create loop to rebuild array, and count how many
* correct items
* Create new variable resetquest in case player gets all 3
set j 0
set counter 0
while %j% < %numquests%
eval j %j% + 1
eval curritem %%item%j%%%
if %curritem% == yes
eval counter %counter% + 1
endif
if %j% == 1
set myquestvar %curritem%
set resetquest no
else
set myquestvar %myquestvar% %curritem%
set resetquest %resetquest% no
endif
done
if %counter% < %numquests%
* Can't set status to incomplete, but need to use previous
* one, because player might have done quest before
set myquestvar %myquestvar% %status%
else
* Note, got to reset quest, but must flag complete
set myquestvar %resetquest% complete
* Set complete quest sequence here
%send% %actor% I reward thee!
endif
* Finally, don't forget to remote this
remote myquestvar %actor.id%
else
* If no questflag, giving should not do anything
halt
endif
--- End code ---
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version