With the sketch in mind, we begin to think about how the function might work. When someone drinks something in the presence of the venom, including the venom itself, the server first fires a command_drink event. While in many cases we might have to satisfy ourselves with handling this event, in the case of the drink command, a better option exists: the do_drink event. The server sends this event only to the object being drunk, allowing us to leave the parsing of the command up to the regular code. Quaffing the venom is similar: we need merely handle the do_quaff event.
Once the venom begins to take affect, we must periodically damage the victim. We manage this activity by adding our own events and using the do_event handler to apply the damage to the victim. The strength penalty is easily added, but has the added benefit of serving as a marker for the curing of the victim--we know that someone has cured the victim when the strength penalty vanishes.
In summary, we need implement the following handlers for the desired behavior:
special drink_venom (object obj, person pc) { // We will insert the code here. }
The object obj here is the venom, and the person pc is the one who drank or quaffed the venom. Before we tackle the body of the routine, we can write the "glue" that ties the two handlers into our routine. The handlers must appear after the routine in the function's file--nothing can call a routine until it has been defined. We merely pass the arguments to the routine and return the value returned by the routine:
special do_drink (object obj, person pc) { return drink_venom (obj, pc); } special do_quaff (object obj, person pc) { return drink_venom (obj, pc); }
object { public: action[PO] drink_pc, drink_room; action[P] suffer_pc, suffer_room; instance: person victim; } special drink_venom (object obj, person pc) { // First, show the person drinking the venom. show_action (drink_pc, to_player, pc, obj); show_action (drink_room, to_room, pc, obj); // We can't destroy the object until we move it off of the nohassled // person. move (obj, find_room_by_vnum (0), inside_of); // If a nohassled person drinks the venom, just send the drinking // message and quit. We return handled to ensure that the normal // messages are not sent, particularly because we have already // destroyed the venom. if (pc.nohassled) { obj.destroy; return handled; } // Store a pointer to the pc. We might simply attach the pc to the // suffering event (see below), but if the pc died to something besides // the venom, the event would be removed and the venom would never be // destroyed. victim = pc; // We now add an event for damaging the pc. */ add_event (none, none, obj, none, 1, number (15, 25)); // Add a strength penalty to the pc. This marker also allows us to // detect the use of cure poison on the pc--if the marker is gone, // then either 100 ticks have passed (the duration), or someone cast // cure poison on the pc. add_modifier (pc, spell_poison, 100, modify_strength, -5, false, false); // Return handled to avoid normal drink/quaff messages. return handled; } special do_event (room rm, person mob, object obj, entity ent, integer type) { person pc; boolean saved; integer damage; if (victim == none) { obj.destroy; return handled; } pc = victim; if (!pc.poisoned || ((saved = save_against (pc, save_poison)) && number (1, 100) < save_chance (pc, save_poison) / 10)) { obj.destroy; return handled; } damage = make_dice (type, 8, 5).roll; if (saved) damage /= 2; else type++; show_action (suffer_pc, to_player, pc); show_action (suffer_room, to_room, sight, if_visible, pc); do_damage (pc, pc, type_none, damage); if (!pc.valid) obj.destroy; else add_event (none, none, obj, none, type, number (25, 75)); return handled; }