Author Topic: Trading Scripts  (Read 9446 times)

0 Members and 1 Guest are viewing this topic.

Offline erwin

  • Sr. Member
  • ****
  • Posts: 314
    • View Profile
Trading Scripts
« on: December 01, 2015, 03:09:43 am »
Here's one way to do a trading script, which would account for lots of different items being traded, and rejected.

However, before the script is posted, let's think about how the script would work. In the old days, the script would be something like (in pseudo code):
Code: [Select]
if %item.vnum% == 100 || %item.vnum% == 101
  %send% %actor% Thank you for trading item number 100 or item 101!
  %send% %actor% Let me give you a reward
elseif %item.vnum% == 103
  %send% %actor% Thank you for trading item number 103!
  %send% %actor% Let me give you a reward
elseif %item.vnum% == 105
  %send% %actor% Thank you for trading item number 105!
  %send% %actor% Let me give you a reward!
elseif %item.vnum% == 110 || %item.vnum% == 114 || %item.vnum% == 120
  %send% %actor% Sorry, I don't take this type of items
  %send% %actor% Go away!
endif

However, we see that a lot of things are repeated. For example, for a correct item, the code is always of the form:
Code: [Select]
if %item.vnum% == "correct vnum"
  mob gives some reward for the item
  mob says thank you
endif

For example, if the mob can receive 10 different items, then for each item, we might have the (duplicated) code
Code: [Select]
wait 1s
mjunk %object%
say thank you
give TP reward
give XP reward
10 items would mean 50 lines of duplicated code. This takes up a lot of space. Can we do better? (yes).

So here's a way to do it

Code: [Select]
* First, set the number of items that the mob trades. Suppose the mob is a jeweller, and trades the six items only
* The numbers correspond to the correct vnums
* Speech is optional - could have lots of variables for this, just make sure the last "character" of the speech is the
* same number of the item. But if you want the mob to say the same thing for each item
* then in the loop below, could just "say thank you".

* Item 1 corresponds to diamonds
set item1 111 112 113 114 120
set speecha1 thank you for the diamonds
set speechb1 blah blah love you

* Item 2 corresponds to rubies
set item2 200 201 214 206
set speecha2 thank you for the rubies
set speechb2 blah blah love you


* Item 3 corresponds to garnets
set item3 300 301 333 399
set speecha3 thank you for the garnets
set speechb3 blah blah love you

* Item 4 corresponds to sapphires
set item4 400 420 490
set speecha4 thank you for the sapphires
set speechb4 blah blah love you


* Item 5 corresponds to quartz
set item5 500
set speecha5 thank you for the quartz
set speechb5 blah blah love you


* Item 6 corresponds to topaz
set item6 666 669
set speecha6 thank you for the topaz
set speechb6 blah blah love you


* Set the maximum items the mob trades, in this case 6
set max_items 6

* Set the rewards for each of them. So item 1 (diamonds) would get 1 TP and 1000 xp, and item 6 (topaz)
* would get 9 TP and 4000 xp

set tp_reward_vec 1 4 3 2 4 9
set exp_reward_vec 1000 3000 1000 1000 4000 4000

* You can set rejected items as well, for example, suppose the mob rejects fool's gold and iron pyrite

* rej_item 1 corresponds to fool's gold
set rej_item1 1000 1005 1110
set rej_speech1 I don't want fool's gold.

* rej_item 2 corresponds to iron pyrite
set rej_item2 2000 2222
set rej_speech2 I don't want iron pyrite.

* Set maximum number of rej items. In this case, 2
set rej_max_items 2

* Now comes the main part

set currvnum %object.vnum%

* We want to find which item it is, so we loop through all items (in item1 to item 6)
set traded_item 0
set i 1

while %i% <= %max_items%
  * look at first itemvec
  * Need to eval this!
  eval item_to_check %%item%i%%%
 
  set j 1
 
  while %j% != 0
    extract curr_item %j% %item_to_check%
    if !%curr_item%
      * Loop will stop
      set j 0
    else
      if %curr_item% == %currvnum%
        set traded_item %i%
        break
      endif
      eval j %j% + 1
    endif
  done
  if %traded_item% != 0
    eval i %max_items% + 1
  endif
  eval i %i% + 1
done

* This will create a variable traded_item which will tell you what item it is
* For example, if traded_item is 4, then the player gave sapphires
* If the traded_item was 0, means it was none of the 6 possible items

if %traded_item% != 0
  *Great, no rejected items. Now to find which one
  wait 1
  mjunk %object%
  * evals the correct speech corresponding to the traded item
  eval tosaypartone %%speecha%traded_item%%%
  eval tosayparttwo %%speechb%traded_item%%%

  say %tosaypartone%
  say %tosayparttwo%
  wait 1
  * Reward goes here, corresponding to the traded_item
  set tp_reward %tp_reward_vec.wordat(%traded_item%)%
  nop %actor.trade(%tp_reward%)%
  eval d %actor.level%*%exp_reward_vec.wordat(%traded_item%)%
  nop %actor.exp(%d%)%
 
  * Halt this script if we have successfully traded! 
  halt
endif

* If traded_item is zero,  then it's a rejected item
return 0
wait 1
emote makes a refusing gesture.

* Check if it was either fool's gold or iron pyrite, same loop as above
set rej_traded_item 0
set i 1

while %i% <= %rej_max_items%
  * look at first itemvec
  * Need to eval this!
  eval item_to_check %%rej_item%i%%%
  set j 1 
  while %j% != 0
    extract curr_item %j% %item_to_check%
    if !%curr_item%
      * Loop will stop
      set j 0
    else
      if %curr_item% == %currvnum%
        set rej_traded_item %i%
        break
      endif
      eval j %j% + 1
    endif
  done
  if %rej_traded_item% != 0
    eval i %rej_max_items% + 1
  endif
  eval i %i% + 1
done

* same thing

if %rej_traded_item% != 0 
  eval tosay %%rej_speech%rej_traded_item%%%
  say %tosay%
  halt
else
  say This is a generic statement saying I don't like your item.
endif

What are the benefits of this script?

1. You can trade LOTS of different items. So if we traded 50 items, writing the code the long way might mean duplicating 50*5 = 250 lines of code.

With this script, we save on 250 lines of code (there is extra code because of the loop, but that has a constant number of lines whether you trade 5 items or 500 items).

2. You don't need lots of ifchecks like
Code: [Select]
if %object.vnum% == 1000 || %object.vnum% == 1001 || %object.vnum == 1002
for every item. For example, did you notice in the code above, I left out a % in %object.vnum == 1002? Hard to spot such errors! However, with the above script, all a builder needs to do is to edit the first few lines. Fewer chances of mistakes.

Yay!

Offline erwin

  • Sr. Member
  • ****
  • Posts: 314
    • View Profile
Re: Trading Scripts
« Reply #1 on: December 01, 2015, 03:28:56 am »
Also, you can create two functions for the traded_item loop, and the rejected_item loop.

Then, for all traders in the MUD, just call these two functions whenever you trade something, so in the future, code might just look like

Code: [Select]
set item1 111 112 113 114 120
set speecha1 thank you for the diamonds
set speechb1 blah blah love you

set item2 200 201 214 206
set speecha2 thank you for the rubies
set speechb2 blah blah love you

set item3 300 301 333 399
set speecha3 thank you for the garnets
set speechb3 blah blah love you

set item4 400 420 490
set speecha4 thank you for the sapphires
set speechb4 blah blah love you

set item5 500
set speecha5 thank you for the quartz
set speechb5 blah blah love you

set item6 666 669
set speecha6 thank you for the topaz
set speechb6 blah blah love you

set max_items 6

set tp_reward_vec 1 4 3 2 4 9
set exp_reward_vec 1000 3000 1000 1000 4000 4000

set rej_item1 1000 1005 1110
set rej_speech1 I don't want fool's gold.

set rej_item2 2000 2222
set rej_speech2 I don't want iron pyrite.

set rej_max_items 2

set currvnum %object.vnum%

* Loop for traded_item function
function 122

if %traded_item% != 0
  *Great, no rejected items. Now to find which one
  wait 1
  mjunk %object%
  * evals the correct speech corresponding to the traded item
  eval tosaypartone %%speecha%traded_item%%%
  eval tosayparttwo %%speechb%traded_item%%%

  say %tosaypartone%
  say %tosayparttwo%
  wait 1
  * Reward goes here, corresponding to the traded_item
  set tp_reward %tp_reward_vec.wordat(%traded_item%)%
  nop %actor.trade(%tp_reward%)%
  eval d %actor.level%*%exp_reward_vec.wordat(%traded_item%)%
  nop %actor.exp(%d%)%
 
  * Halt this script if we have successfully traded! 
  halt
endif

* If traded_item is zero,  then it's a rejected item
return 0
wait 1
emote makes a refusing gesture.

* Loop for rejected items
function 125

if %rej_traded_item% != 0 
  eval tosay %%rej_speech%rej_traded_item%%%
  say %tosay%
  halt
else
  say This is a generic statement saying I don't like your item.
endif


Offline erwin

  • Sr. Member
  • ****
  • Posts: 314
    • View Profile
Re: Trading Scripts
« Reply #2 on: December 03, 2015, 02:58:09 am »
One last post to explain what the first loop does. If it's complicated, pretend it's a DG function like .contains or replace_word (which are simple - but the code behind them is not so simple).

Think of this loop as a DG function which takes into input all your item#. In the first post, we had item1, item2, ... , item6.

Then, it outputs the number where the vnum occurs, and 0 otherwise.

So, think of this as a "black box". If we had

Code: [Select]
set item1 111 112 113 114 120

set item2 200 201 214 206

set item3 300 301 333 399

set item4 400 420 490

set item5 500

set item6 666 669

Then if the object vnum was 400, our loop would return the number 4 (because 400 was in item4).

If the object vnum was 206, our loop would return the number 2 (because 206 was in item2).

If the object vnum was 10000, our loop would return the number 0 (because 10000 is not in any of the items).

Returning the number is useful, because we can use this number to check for rewards.

We had (for example)
Code: [Select]
set speecha1 thank you for the diamonds
set speechb1 blah blah love you
set tp_reward_vec 1 4 3 2 4 9
set exp_reward_vec 1000 3000 1000 1000 4000 4000

Think of the number that the loop returns (or black box) helpful, by identifying what speech to give. Eg, if we had the number 4, then we will give speecha4 and speechb4, the value of the TP in the 4th number (2), and the value of the XP in the 4th number (1000).

So this portion
Code: [Select]
if %traded_item% != 0
  *Great, no rejected items. Now to find which one
  wait 1
  mjunk %object%
  * evals the correct speech corresponding to the traded item
  eval tosaypartone %%speecha%traded_item%%%
  eval tosayparttwo %%speechb%traded_item%%%

  say %tosaypartone%
  say %tosayparttwo%
  wait 1
  * Reward goes here, corresponding to the traded_item
  set tp_reward %tp_reward_vec.wordat(%traded_item%)%
  nop %actor.trade(%tp_reward%)%
  eval d %actor.level%*%exp_reward_vec.wordat(%traded_item%)%
  nop %actor.exp(%d%)%
 
  * Halt this script if we have successfully traded! 
  halt
endif

if you read it line by line, it just checks for the number (in %traded_item%), finds the correct speech to give with
Code: [Select]
  eval tosaypartone %%speecha%traded_item%%%
  eval tosayparttwo %%speechb%traded_item%%%

and gives the right TP reward and XP reward in
Code: [Select]
  set tp_reward %tp_reward_vec.wordat(%traded_item%)%
  nop %actor.trade(%tp_reward%)%
  eval d %actor.level%*%exp_reward_vec.wordat(%traded_item%)%
  nop %actor.exp(%d%)%

If you have problems reading this code, here's another way to look at this.

We have the reward code as
Code: [Select]
if %traded_item% != 0
  *Great, no rejected items. Now to find which one
  wait 1
  mjunk %object%
  * evals the correct speech corresponding to the traded item
  eval tosaypartone %%speecha%traded_item%%%
  eval tosayparttwo %%speechb%traded_item%%%

  say %tosaypartone%
  say %tosayparttwo%
  wait 1
  * Reward goes here, corresponding to the traded_item
  set tp_reward %tp_reward_vec.wordat(%traded_item%)%
  nop %actor.trade(%tp_reward%)%
  eval d %actor.level%*%exp_reward_vec.wordat(%traded_item%)%
  nop %actor.exp(%d%)%
 
  * Halt this script if we have successfully traded! 
  halt
endif

There's lots of variables, so let's pretend that we gave object vnum 206. Running the "black box" loop, we have %traded_item% to be 2, because we had
Code: [Select]
set item2 200 201 214 206
and 206 is inside.

Let's replace %traded_item% in the code by 2 (the value of %traded_item%)
Code: [Select]
if 2 != 0
  *Great, no rejected items. Now to find which one
  wait 1
  mjunk %object%
  * evals the correct speech corresponding to the traded item
  eval tosaypartone %%speecha2%%
  eval tosayparttwo %%speechb2%%

  say %tosaypartone%
  say %tosayparttwo%
  wait 1
  * Reward goes here, corresponding to the traded_item
  set tp_reward %tp_reward_vec.wordat(2)%
  nop %actor.trade(%tp_reward%)%
  eval d %actor.level%*%exp_reward_vec.wordat(2)%
  nop %actor.exp(%d%)%
 
  * Halt this script if we have successfully traded! 
  halt
endif

Okay, we still have more variables now like %%speecha2%%, %%speechb2%%, and %tp_reward_vec.wordat(2)%, etc, but it should be easier to see. If not, we'll go through the code one more time and replace these variables by what we've defined.

Code: [Select]
if 2 != 0
  *Great, no rejected items. Now to find which one
  wait 1
  mjunk %object%
  * evals the correct speech corresponding to the traded item
  eval tosaypartone thank you for the rubies
  eval tosayparttwo blah blah love you

  say %tosaypartone%
  say %tosayparttwo%
  wait 1
  * Reward goes here, corresponding to the traded_item
  * because 4 was the word at 2 for the tp_reward_vec
  set tp_reward 4
  nop %actor.trade(%tp_reward%)%
  * because 3000 was the word at 2 for the exp_reward_vec
  eval d %actor.level%*3000
  nop %actor.exp(%d%)%
 
  * Halt this script if we have successfully traded! 
  halt
endif

And that's it :)








------------

This is the loop to find the value of %traded_item% for further info. If it bothers you, pretend it's a DG function that gives you what you want :)

Code: [Select]
while %i% <= %max_items%
  * look at first itemvec
  * Need to eval this!
  eval item_to_check %%item%i%%%
 
  set j 1
 
  while %j% != 0
    extract curr_item %j% %item_to_check%
    if !%curr_item%
      * Loop will stop
      set j 0
    else
      if %curr_item% == %currvnum%
        set traded_item %i%
        break
      endif
      eval j %j% + 1
    endif
  done
  if %traded_item% != 0
    eval i %max_items% + 1
  endif
  eval i %i% + 1
done

I'm reluctant to say: "Use this code even if you don't understand it", because that's where lots of errors can occur. But in that case, we also shouldn't use cool DG commands like
Code: [Select]
.contains
.wordat()
.strlen
replace_word
etc, because we don't know how to "script" the equivalent in DG. But we still use them anyway. For example, replace_word as a DG function is easy to understand
Code: [Select]
set sentence This is a dog and it is barking
replace_word boy 4 %sentence%
will give This is a boy and it is barking. But not many of us will be able to script the equivalent in DG.
Code: [Select]
set sentence This is a dog and it is barking
* want to replace boy in word 4
set word_to_replace boy
set num_at_replace 4

* After setting sentence, word_to_replace, num_at_replace, then:

* Find the maximum length of this sentence
set len 0
while %len%
  eval len %len% + 1
  extract tmp %len% %sentence%
  if !%tmp%
    break
  endif
done
eval len %len% - 1

*len is now the length of the sentence (ie number of words)


extract newsentence 1 %sentence%
set i 2
while %i% < %num_at_replace%
  extract nextword %i% %sentence%
  set newsentence %newsentence% %nextword%
  eval i %i% + 1
done

set newsentence %newsentence% %word_to_replace%
eval i %i% + 1
while %i% <= %len%
  extract nextword %i% %sentence%
  set newsentence %newsentence% %nextword%
  eval i %i% + 1
done

However, hold on! This code won't work if we wanted to replace the first word. So the actual code would be something like
Code: [Select]
set sentence This is a dog and it is barking
* want to replace that in word 1
set word_to_replace that
set num_at_replace 1

* After setting sentence, word_to_replace, num_at_replace, then:

* Find the maximum length of this sentence
set len 0
while %len%
  eval len %len% + 1
  extract tmp %len% %sentence%
  if !%tmp%
    break
  endif
done
eval len %len% - 1

*len is now the length of the sentence (ie number of words)

if %num_at_replace% == 1
  set newsentence %word_to_replace%
  set i 2
else
  extract newsentence 1 %sentence%
  set i 2
  while %i% < %num_at_replace%
    extract nextword %i% %sentence%
    set newsentence %newsentence% %nextword%
  eval i %i% + 1
  done
  set newsentence %newsentence% %word_to_replace%
  eval i %i% + 1
endif

while %i% <= %len%
  extract nextword %i% %sentence%
  set newsentence %newsentence% %nextword%
  eval i %i% + 1
done

It's a pain to read, especially without comments. Most builders probably don't understand what that does, and wouldn't dare to use it, but they would use
Code: [Select]
replace_word

even though it does the same thing.

So maybe you have a question: If we can put that terrible looking loop in the form of
Code: [Select]
replace_word

then why can't we do the same for
Code: [Select]
while %i% <= %max_items%
  * look at first itemvec
  * Need to eval this!
  eval item_to_check %%item%i%%%
 
  set j 1
 
  while %j% != 0
    extract curr_item %j% %item_to_check%
    if !%curr_item%
      * Loop will stop
      set j 0
    else
      if %curr_item% == %currvnum%
        set traded_item %i%
        break
      endif
      eval j %j% + 1
    endif
  done
  if %traded_item% != 0
    eval i %max_items% + 1
  endif
  eval i %i% + 1
done
?

Well, let's see how replace_word works. The syntax is
Code: [Select]
replace_word blah 4 sentence
And you can read this as: "We are going to replace the 4th word of sentence by the word blah"

But, what the "black box" loop does is: Given any number of possible traded items (could be 6, could 10, could 2), the loop will return the item number. How would such an input look like if we had such a function? Eg if we wanted to check if vnum 12345 was in item1 to item3, then..
Code: [Select]
blackboxloop 12345 item1 item2 item3
?

But if we had 10 items, then
Code: [Select]
blackboxloop 12345 item1 item2 item3 item4 item5 item6 item7 item8 item9 item10
?

What if the builder transposed two numbers, eg
Code: [Select]
blackboxloop 12345 item2 item1 item3
, would it still return the right number? So maybe it's better if the loop was in DG instead of a function...
« Last Edit: December 03, 2015, 03:27:24 am by erwin »

Offline erwin

  • Sr. Member
  • ****
  • Posts: 314
    • View Profile
Re: Trading Scripts
« Reply #3 on: December 03, 2015, 03:04:35 am »
Also, note that
Code: [Select]
set speecha1 thank you for the diamonds
set speechb1 blah blah love you

etc is optional. If the mob does a generic thank you, you might as well have
Code: [Select]
if %traded_item% != 0
  *Great, no rejected items. Now to find which one
  wait 1
  mjunk %object%
  say thank you!
  wait 1
  * Reward goes here, corresponding to the traded_item
  set tp_reward %tp_reward_vec.wordat(%traded_item%)%
  nop %actor.trade(%tp_reward%)%
  eval d %actor.level%*%exp_reward_vec.wordat(%traded_item%)%
  nop %actor.exp(%d%)%
 
  * Halt this script if we have successfully traded! 
  halt
endif

Similarly, if you have fewer / more speeches to give, you could have
Code: [Select]
set speecha1 thank you for the diamonds
set speechb1 blah blah love you
set speechc1 laa
if you wanted the mob to say three lines, for example.

You might then say: "What if for one item, I want the mob to do something different?" Well, then you can have
Code: [Select]
if %traded_item% != 0
  *Great, no rejected items. Now to find which one
  wait 1
  mjunk %object%
  say thank you!
  wait 1
  * Reward goes here, corresponding to the traded_item
  set tp_reward %tp_reward_vec.wordat(%traded_item%)%
  nop %actor.trade(%tp_reward%)%
  eval d %actor.level%*%exp_reward_vec.wordat(%traded_item%)%
  nop %actor.exp(%d%)%
 
  if %traded_item% == 4
    %echo% This is a special item! Do special stuff here
  endif
 
  * Halt this script if we have successfully traded! 
  halt
endif

Offline erwin

  • Sr. Member
  • ****
  • Posts: 314
    • View Profile
Re: Trading Scripts
« Reply #4 on: January 06, 2017, 07:22:55 am »
Trading script v3, uses real examples. Imms only need to edit the first part, and can add as many or as few items as wanted. Script takes care of the rest.

Wishlist: Can we hardcode this somehow? Something like medit / oedit / sedit. tradeedit?

Note: We're setting a flag for this, so we can also track how many items players have traded, for that vendor.
Code: [Select]

if !%actor.is_pc%
  halt
endif
* Molly, Kvetch, whoever wants to add MORE trading stuff here, follow the
* comments
*
* If you want to reduce the number of items traded, it's a bit more complex.
* Send me a note, or any of the coders.
* Ideally, we should probably write this in C instead of DG scripts.
*
* Flag: trade_winter
* Currently, can trade SIX items, and mob rejects FOUR items
*
*********
*********
*** The Edit Place
* Edit the below if you want to change the number of items traded
set max_items 6
* na_flag is basically SIX nas (or however max_items nas)
set na_flag na na na na na na

* thinrope
set item1 52615
set speecha1 Bob says, 'OK, most of the mountaneers buy a thin rope from me.'

* thickrope
set item2 52616
set speecha2 Bob says, 'Right, thinropes are in most demand of course.
set speechb2 But there are situations when the mountaineers need thicker ropes too.
set speechc2 I've seen ten of them dangle over a precipice from the same rope.'

* longrope
set item3 52617
set speecha3 Bob says, 'Thanks! Just what I wanted.
set speechb3 I need a longrope in reserve in case some of them mountaneers falls into a deep ravine.'

* ropeladder
set item4 52618
set speecha4 Bob says, 'Great! I was just out of ropeladders!'

* wool yarn
set item5 52619 52620
set speecha5 Bob says, 'Yup, wool yarn is popular around here.'

* wool cloth
set item6 52624 52625
set speecha6 Bob says, 'Mmm, wool cloth is just what we need.
set speechb6 None of the other kinds keep you warm enough.'

* TP and EXP for each item
set tp_reward_vec 5 13 28 0 3 7
set brass_reward_vec 0 0 0 1 0 0
set exp_reward_vec 3000 6000 8000 10000 1000 1000


* rejected items

set rej_max_items 3

* cotton thread
set rej1 3266 30957
set rejspeecha1 Bob says, 'No thanks, I'm really just interested in wool yarn and cloth.
set rejspeechb1 It's too cold for other materials here.'

* silk
set rej2 52651 52661
set rejspeecha2 Bob says wistfully, 'I wish I could afford it.
set rejspeechb2 But nobody around here would buy silk, And it's too cold for it anyway.'

* cloth
set rej3 3267 30958 44653
set rejspeecha3 Bob says, 'Sorry, I cannot afford silk, and neither can my customers.'


****
* Can stop here for most cases. Below is generic stuff.
*
set trade_winter %na_flag%
if !%actor.varexists(trade_winter)%
  remote trade_winter %actor.id%
elseif %actor.varexists(trade_winter)%
  * Check to see if we have any changes in the length if this var exists
  set findnumwords %actor.trade_winter%
  function 21625
  * Check to see if variable max_items (set above) is equal
  * to number of words in trade_winter, eg if you modified above
  * flag to trade NINE items instead of SIX.
  if %max_items% != %num%
    * someone added more items so that's fine
    set ub 0
    while %ub% < %num%
      eval ub %ub% + 1
      *%echo% Replacing...
      replace_word %findnumwords.wordat(%ub%)% %ub% trade_winter
    done
    remote trade_winter %actor.id%
  endif
endif

set trade_winter %actor.trade_winter%

* BEFORE CALLING 21627
* Make sure you have defined a prefix for the items traded
* Above it's item1, item2, item3, item4, item5, item6, so prefix is item
* Also make sure you've set max_items, which ought to be ABOVE

* For the purists: function 21627 takes in an input prefix, and max_items,
* gives an output item_in_list

set prefix item
function 21627
set traded_item %item_in_list%

** The reward for great trading items
** Can mostly ignore this part
if %traded_item% != 0
  *Great, no rejected items. Now to find which one
  wait 1
  mjunk %object%
  * evals the correct speech corresponding to the traded item
  eval tosaypartone %%speecha%traded_item%%%
  eval tosayparttwo %%speechb%traded_item%%%
  eval tosaypartthree %%speechc%traded_item%%%

  %send% %actor% %tosaypartone%
  if %tosayparttwo%
    %send% %actor% %tosayparttwo%
  endif
  if %tosaypartthree%
    %send% %actor% %tosaypartthree%
  endif
  wait 1
  * Reward goes here, corresponding to the traded_item
  set tp_reward %tp_reward_vec.wordat(%traded_item%)%
  nop %actor.trade(%tp_reward%)%
  if %tp_reward% == 1
    emote hands over %tp_reward% tradepoint.
  elseif %tp_reward% > 1
    emote hands over %tp_reward% tradepoints.
  endif
  eval d %actor.level% * %exp_reward_vec.wordat(%traded_item%)%
  nop %actor.exp(%d%)%
  * tokens
  set bronze_reward %brass_reward_vec.wordat(%traded_item%)%
  set counter 0
  while %counter% < %bronze_reward
    eval counter %counter% + 1
    emote hands over a brass token.
    %load% obj 3300 %actor%
  done
  set trade_winter %actor.trade_winter%
  set curr_item %trade_winter.wordat(%traded_item%)%
  if %curr_item% == na
    set curr_item 1
  else
    eval curr_item %curr_item% + 1
  endif
  replace_word %curr_item% %traded_item% trade_winter
  remote trade_winter %actor.id%
  * Halt this script if we have successfully traded! 
  halt
endif

* Let's do the same for rejected items for special messages
* We are calling the same function 21627 again, but with
* rejected items as input
* So max_items is now rej_max_items, and prefix is rej

set max_items %rej_max_items%
set prefix rej
function 21627
set rej_traded_item %item_in_list%

if %rej_traded_item% != 0 
  eval tosay1 %%rejspeecha%rej_traded_item%%%
  eval tosay2 %%rejspeechb%rej_traded_item%%%
  %send% %actor% %tosay1%
  if %tosay2%
    %send% %actor% %tosay2%
  endif
  halt
else
  emote says, 'Sorry, I don't trade in that kind of stuff.'
endif
« Last Edit: January 06, 2017, 07:40:39 am by erwin »

Offline erwin

  • Sr. Member
  • ****
  • Posts: 314
    • View Profile
Re: Trading Scripts
« Reply #5 on: January 29, 2017, 11:18:51 pm »
Trading Script v4, until Roland puts in a Trading OLC to render this obsolete. It's still pretty funky.

tstat 2140 for this

All you need is to set the flags (below), basically:

1) max_items  (number of items this mob accepts)
2) na_flag (nas depending max items. If the mob accepts 5 items, then na_flag should be: set na_flag na na na na na)
3) flagname (flag to set on actor call it whatever you want, here I've called it trade_crete_tino
4) item and "speech" (rather more of what actor sees) flags, up to 3 different ones. Eg.

Code: [Select]
* items are what the mob accepts. For example, there's lots of wolf ears in the MUD, so you could do something like
set item1 1234 2222 5828

* if 1234, 2222, 5828 were vnums of wolf ears

* You get up to three consecutive actions the player sees in order.
* You don't need to use all three of them. So for example, you can have

set item1 52614
set speecha1 Tino says, 'Good! I can always use more hemp twine!'

* where item1 only has one line the player sees

set item2 12345
set speecha2 Gollum says, 'A ring, great!"
set speechb2 Gollum says, 'My precioussssssss'
set speechc2 Gollum caresses the ring eagerly.

* item 2 has three lines the player sees

set item3 123 6839 5824 52850
set speecha3 The player sees this.
set speechb3 and this.

* item 3 has three lines the player sees

* items / speeches are always set in consecutive order

5) tp_reward_vec: TP in order of the items given
6) exp_reward_vec: Exp in order of the items given
7) brass_reward_vec: Brass tokens in order of the items given

8) rej_max_items: How many "special" items will the mob reject? Same like above, we have variables rej1, rej2, ..., and rejspeecha1, rejspeechb1, rejspeechc1, .... etc.

9) genreja, genrejb, genrejc - 3 potential variables for generic rejection speech, again in consecutive order

Here's an example.

Code: [Select]
if !%actor.is_pc%
  halt
endif
* Molly, Kvetch, whoever wants to add MORE trading stuff here, follow the
* comments
*
* If you want to reduce the number of items traded, it's a bit more complex.
* Send me a note, or any of the coders.
* Ideally, we should probably write this in C instead of DG scripts.
*
* Flag: trade_crete_tino
* Currently, can trade THREE items, and mob rejects ONE item
*
*********
*********
*** The Edit Place
*************************
* Edit the below if you want to change the number of items traded
set max_items 3
*************************
* na_flag is basically THREE nas (or however max_items nas)
set na_flag na na na
*************************
* flagname - the flag for the trading
set flagname trade_crete_tino

* hemp twine
set item1 52614
set speecha1 Tino says, 'Good! I can always use more hemp twine!'

* sail cloth
set item2 52797
set speecha2 Tino says, 'Great! We were about to run out of sailcloth completely.'

* thin rope
set item3 52615
set speecha3 Tino says, 'Great, that thinrope will be enough for me to finish this batch of sails.'

* TP and EXP for each item
set tp_reward_vec 1 8 4
* This has no brass token
* set brass_reward_vec 0 0 0 1 0 0
set exp_reward_vec 1000 4000 3000

* rejected items

set rej_max_items 1

* sails
set rej1 44673 44674
set rejspeecha1 Tino says, 'Dude, I SELL sails, I don't buy them.
set rejspeechb1 So you can keep any sails you've made for yourself.' 


****
* Generic rejection speech
set genreja Tino says, 'I don't trade in such things.'
*
*

* This function will fix length of questflag, eg if more items were
* added
* Required inputs: na_flag, flagname, and max_items

function 2151

* BEFORE CALLING 21627
* Make sure you have defined a prefix for the items traded
* Above it's item1, item2, item3, item4, item5, item6, so prefix is item
* Also make sure you've set max_items, which ought to be ABOVE

* For the purists: function 21627 takes in an input prefix, and max_items,
* gives an output item_in_list

set prefix item
function 21627
set traded_item %item_in_list%

if %traded_item% != 0
  ** The reward for great trading items
  function 2152
  halt
endif


* Let's do the same for rejected items for special messages
* We are calling the same function 21627 again, but with
* rejected items as input
* So max_items is now rej_max_items, and prefix is rej

set max_items %rej_max_items%
set prefix rej
function 21627
set rej_traded_item %item_in_list%

function 2153

**** END

Offline erwin

  • Sr. Member
  • ****
  • Posts: 314
    • View Profile
Re: Trading Scripts
« Reply #6 on: January 31, 2017, 10:25:48 am »
Trading Script V6.

This is in room 47300 in 6001. More info can be found there, but feel free to play about with it. Send a note for more requests for different types of triggers.

The intention is to make trading scripts "easier to write" - eg, there's actually no code below, it's just setting what you want the player to do / mob to react. It's also easier to debug (since no code), and also somewhat easier to see if the rewards are appropriate.

Code: [Select]
Name: 'Trigger for Generic Trade',  VNum: [47300], RNum: [ 8677]
Trigger Intended Assignment: Mobiles
Trigger Type: Receive , Numeric Arg: 100, Arg list: None
Commands:


if !%actor.is_pc%
  halt
endif

**** Set parameters
**** What the player sees if supposed to get multiple tradepoints
**** eg, tp_start_plural NUM TRADEPOINTS tp_end_plural

set tp_start_plural Bob hands over
set tp_end_plural tradepoints.
set tp_sing Bob hands over 1 tradepoint.

**** What the player sees if supposed to get multiple brass tokens
**** eg, brass_start_plural NUM TOKENS brass_end_plural

set brass_start_plural Bob hands over
set brass_end_plural brass tokens.
set brass_sing Bob hands over 1 brass token.

**** What the player sees if supposed to get multiple brass tokens
**** eg, bronze_start_plural NUM TOKENS bronze_end_plural

set bronze_start_plural Bob hands over
set bronze_end_plural bronze tokens.
set bronze_sing Bob hands over 1 bronze token.


* Accepted Trade items only
* ALWAYS PLACE PARTIAL ITEMS AT THE END
* Partial items - eg trade FIVE grapes for ONE wine
* You get up to FIVE messages for everything
* Unlimited items to trade (in theory)

* Total number of items traded

set max_items 5

* Non partial items, eg trade ONE item to get reward

set ordinary_items 3

* Partial items, eg trade FIVE grapes for reward

set part_items 2

* Makes it easier for questjournal in future to keep track of trades
* Trade_flag can be: trade_egypt_mobname etc etc

set trade_flag trade_thiszone_thismob

* Place the part_items at the end.
* Up to 5 messages, with delay in seconds
* If you need more messages, send a note

* Delay between mob messages
set delay 2

* Flags for items
* If none, don't need to have the flag there
* item_x : list vnums, or short desc
* type_x : Is it a vnum, or short desc?
* msg_Ax, msg_Bx, msg_Cx, msg_Dx, msg_Ex : What mob says
* reward_x : reward is in terms of XP TP BRASS BRONZE
* item_reward_x : vnum of item reward
* how_many_x : For partial items, how many to get a reward?
* reward_after_x : The reward after getting all partial items
* item_reward_after_x : The item reward after getting all partial items

* Put the three ordinary items first

* Item 1 (diamonds)

* Bob will accept one item, will have three actions
* This item gets 1000 XP * level, 10 TP, 0 brass, 0 bronze

set item_1 8465
set type_1 vnum
set msg_A1 Bob says, 'Thank you for trading this item'
set msg_B1 Bob smiles.
set msg_C1 Bob says, 'I have nothing else to say.'

* Reward is in terms of XP, TP, BRASS, BRONZE
set reward_1 1000 10 0 0


* Item 2 (logs)
* Bob will accept any item with short desc logs, will have four actions
* This item gets 5000 XP * level, 4 TP, 1 brass, 2 bronze
* This item will also get a object reward vnum 2523

set item_2 log
set type_2 short
set msg_A2 Bob says, 'Thank you for trading the log item'
set msg_B2 Bob smiles.
set msg_C2 Bob says, 'I have given you a small gift of a chair.'
set msg_D2 Bob thanks you heartily.
* Reward is in terms of XP, TP, BRASS, BRONZE
set reward_2 5000 4 1 2
set item_reward_2 2523

* Item 3 (bread)
* Bob will accept two items: 10, 9291 and has one action
* This item gets 1 TP


set item_3 10 9291
set type_3 vnum
set msg_A3 Bob says, 'I like bread.'
set reward_3 0 1 0 0

* Reminder, always put partial items last

* Item 4 (grapes)
* Bob will accept two items: 6346, 44495 and has two actions
* This item gets no reward each time
* Bob has a message to count them, eg msg_counter_before NUMGIVEN msg_counter_after

* But when all 5 are given (how_many_4 flag)
* Player gets 1000 xp * level, 5 TP, 1 brass, 0 bronze
* Player also gets object 6349

* Item 4 (grapes - trade 5 to get 1 wine)
set item_4 6346 44495
set type_4 vnum
set how_many_4 5
set msg_A4 Bob says, 'Thanks for the grapes'
set msg_B4 Bob says, 'I will store them to make wine'

set msg_counter_before_4 Bob says, 'Keep them coming,
set msg_counter_after_4 out of 5!

set reward_4 0 0 0 0
set msg_after_A4 Bob says, 'You have given me 5 grapes'
set msg_after_B4 Bob says, 'I will give you some wine'

set reward_after_4 1000 5 1 0
set item_reward_after_4 6349


* Item 5 (ear)
* Bob will accept one items: 15083
* This item gets 1 TP each time it is given
* Bob has a message to count them, eg msg_counter_before NUMGIVEN msg_counter_after

* But when all 10 are given (how_many_5 flag)
* Player gets 1000 xp * level, 10 TP, 10 brass, 10 bronze

set item_5 15083
set type_5 vnum
set how_many_5 10
set msg_A5 Bob says, 'Thanks for the wolf ear'
set msg_B5 Bob says, 'I will give you 1 TP.
set reward_5 0 1 0 0

set msg_counter_before_5 Bob says, 'Look at these ears piling up,
set msg_counter_after_5 out of 10!

set reward_after_5 1000 10 10 10
set msg_after_A5 Bob says, 'I'm going to give you a bonus!'
set msg_after_B5 Bob says, 'Tokens and stuff and more'
set msg_after_C5 Bob says, 'But no items.'


******** Rejected items
* same thing

set rej_max_items 2

* Bob rejects items 8704, 1404 with a special message

set rej_item_1 8704 1404
set rej_type_1 vnum

set rej_msg_A1 Bob says, 'I don't like gold.'
set rej_msg_B1 Bob says, 'Go away.'

* Bob rejects items with short desc flower with a special message


set rej_item_2 flower
set rej_type_2 short

set rej_msg_A2 Bob says, 'I hate flowers.'
set rej_msg_B2 Bob says, 'Go away.'

***** Default message

set rej_default_A Bob says, 'What is this crap?'
set rej_default_B Bob says, 'Go away.'

**** The magic function
function 47391
« Last Edit: January 31, 2017, 11:01:38 am by erwin »