Crashcourse - Part 09

[previous part] [Table of contents] [next part]

Okay, we've gotten past the +STAT stage, where we make special EQ that just changes the player's stats. It's time to make some more interesting items. They are often more fun to use, but can be tough to create. And, most of the time, the special coding is not the problem. The problem is fantasy. Ideas for cool stuff are not always easily come by. And fantasy is hard to teach. ;-) But, take a look at the files in this course, and maybe they can help you get some ideas for special items of your own.

Before we start we add two colourcodes to our defs.h file. C_BOLD for bold colour and C_END for ending the colour.

Special items, as well as +stat items, should normally be unique. There is an easy way of accomplishing this if the item belongs to a monster. By using the optional parameters for the add_eq() function in monsters, we can decide how UNIQUE a special item is supposed to be. Read the manual page 'add_eq' for examples and descriptions of the different arguments.

Let's just get the show rolling...

FILENAME: voiceamulet.c
FILENAME: voicefuncs.c

This time you get to use your coding skills to their fullest. The functionfile for this amulet contains some new functions:

query_idle(player)      - Returns the idle time of a player (in seconds).
heal_self(amount)       - Will heal a living with amount hps+sps.
query_worn_by()         - Will return the wearer of the armour, if any.
remove_call_out(func)   - Will remove any call_outs to the function func
                          inside this object.
_query_property(prop)   - Will return the real value of the property prop.

The difference between '_query_property()' and 'query_property()' is that '_query_property()' will return 0 if the property is set to 0, while 'query_property()' would return 1(TRUE).

The amulet feeds upon souls of the dead. Every time the player kills something (while wearing the amulet), a property will be increased inside the amulet. And as the player take lives, the property will continue to increase, and also change the item description of the 'glass' item. At different intervals, the amulet's call_out()'d function will be called. This function will check to see if the player has killed something and if so, it will "use" the number of kills to heal the player some(either hp, sp or both). When the player is healed, the kills property in the amulet will be decreased. But, since we don't like idling players much, we won't heal the players that is idle more than 2 minutes. ;-) They will only get a message...
If the amulet is removed, all kills are gone. And if the amulet is dropped it is destroyed(It's fragile).

FILENAME: axeofdeception.c
FILENAME: axefuncs.c

This is truly a weapon of deception. If you've got bad luck, it will turn against you and aid your opponent. ;-)

As you can see in the axe file itself, there's one new function to discuss, set_hit_func(). This function defines a function that will be called every time the weapon is used. This function may return a value. This value will then be added to the weapon's hits. Or subtracted, if negative. This way you can actually make a weapon appearing to be good (high weapon class), but does no damage at all.. ;-)
set_hit_func() can easily be swapped out with the hook '__weapon_hit' if desirable, but since the function already exists, it's easier just to use it. To remove a hit_func from a weapon use the function without an argument.

The function to check who's wielding the weapon is query_wielded_by(). It will return the object of the wielder if any. There is an older one called query_wield(), but please don't use it (only kept for compat).

query_weapon(arg) will give you the weapon the living object is wielding. If arg == 1, right hand weapon will be returned, else the left hand weapon will be returned. If a twohanded weapon is being wielded, both will return the same weapon, so make sure you check if that's actually two different weapons or just the same in both hands where it is neccessary.

There are two important functions for weapons, unwield() and wield(). Their purpose is obvious, I hope? ;-)
wield() uses one argument. This argument may be 1 or nothing. If the argument equals 1, then the weapon will be wielded in the left hand, else the weapon will be wielded in the right hand. unwield()'s argument is a silent flag. This flag tells the mudlib if the standard unwielding messages should be displayed. As you can see, we have used both methods in the 'axefuncs.c' file. First to have the wielder unwield the axe silently. This is done because of the messages we display. But, when we let the opponent unwield his/her/its weapon, we let the normal messages be displayed. As you can see, we check for the returnvalue of unwield(). This is done because it might not be possible to unwield the weapon at the time. There could be a blocking hook inside either two weapons keeping the weapon from being unwielded.

FILENAME: hornofhell.c
FILENAME: hornfuncs.c

This is a very special horn and there should only be one of its kind in the game. It should be unique. The horn has a trigger called 'blow'. When this trigger is called, we check to see if the player actually wanted to blow the horn, and if so, we clone a demon to stay at his/her/its side.

FILENAME: demon.c
FILENAME: demonfuncs.c

This is the demon called for by the horn. As you can see, we have given it some spells from a previous course(#06). It's got a lot of skills, making it vulnerable and protective against different damage types and quite a few hooks attached to it. ;-) But, there's not much new to say about them.

But, there are a few new functions in the functionfile that should be mentioned:

strsrch(str,item,flag)  - This function will look for the substring 'item'
                          inside the string 'str'. If found, it will return
                          its position. If not found it will return -1.
                          If the flag is defined, the function will return
                          the last occurence of 'item' in 'str'.

command(cmd)            - This will execute the command 'cmd' for the
                          current living object. This also works for
                          players, but this is logged by the system and
                          should not be exploited.

do_attack(att)          - Will make the current object attack the object
                          'att' in its environment.

query_chat_chance()     - Returns the chance of a chat in the monster.
                          Used in this file to see if load_chat() had been
                          defined earlier. No need to do things twice... ;-)

destroy()               - Use with extreme caution. Will destroy an object

This demon will try to use its kills to save its own life, and also try to save its master's life if it's in danger. The demon will trade the earlier kills with a life, if it's lucky.

This is not a very good implementation at all, but maybe you've already noticed? We're using global variables inside the functionfile. Not a very good idea. And why? Because while the demon can be cloned more than once, the functionfile (or rather the object loaded from the file) cannot. There is only one such object in existance. Which in turn means that if you clone more than one of those demons, they will be using the same variables in the functionfile object. And that will most certainly cause problems. The best way to void this would be to either

  1. use variables inside the demons, not in the functionfile object or
  2. use properties in the demons to store the variables.

The latter one is probably the easiest one if you want to keep the monster replace-programmed. But, if you make sure that only one demon is in the game at a time, this kind of programming doesn't pose as a problem.

FILENAME: spectacles.c
FILENAME: specfuncs.c

These spectacles are a pair of assessment spectacles. You can use the command 'assess ' to assess the strengths/weaknesses of monsters. It's not a very good assessment routine, but it shows you the basics of assessing monsters. There are a lot more to consider when assessing a monster, but the basics are there.

FILENAME: spyfuncs.c

The spy is nothing but a glassorb that allows you to "spy" on a room for a little while. You send it to a player or monster and the orb will vanish, but let you see messages into the room.

! WARNING ! It is ILLEGAL to spy on other players, so don't abuse this.

I have personally used a similar function to "relay" messages inside my tournament ring to the room outside it so that people may watch fights inside the ring. This is the kind of use functions of this kind should have. I had doubt about using this example at all, but I thought it better that you all know what is possible and that if you are a bit paranoid and want to protect your privacy, you can do the following to your "talk"-rooms (workroom for instance):

Add a hook called __enter_inv inside your room. This hook will send through the two arguments: object entering the room and where it came from. Then you just have to check this object and if neccessary, kick it out/destroy it.

Well, I think we'll end this course with this warning. And I sure hope that you have enjoyed the examples and maybe, just maybe, you have learned something or perhaps gotten some good ideas for some special items of your own?

WRITTEN: 04 - Oct - 1996 - Gunner
LAST UPDATE: 28 - May - 1998 - Gunner
HTML Version: 06 - Feb - 2000 - Ghorwin

[previous part] [to the top] [Table of contents] [next part]