OSDN Git Service

Nazghul-0.7.1
[nazghul-jp/nazghul-jp.git] / doc / GHULSCRIPT
1 The GhulScript Specification
2
3
4 -Conversation
5
6 A conversation is a set of other conversations and a set of keyword-response
7 pairs.
8
9         <conversation> := CONV tag { IMPORT { <conversations> } 
10                                      NATIVE { <qr_pairs> }}
11         <conversation> := tag <conversations> |
12         <qr_pairs> := <qr_pair> <qr_pairs> |
13         <qr_pair> := <query> tag
14
15 The lookup rules determine how to match a keyword to a response. The order of
16 searching qr_pairs for a keyword match is as follows:
17
18         1. The NATIVE section of a conversation, in the order specified
19         2. Each conversation in the IMPORT section, in the order specified
20         3. The DEFAULT keyword
21
22 Note that rule 2 is recursive (and if I haven't said it yet circular inclusion
23 of conversations is disallowed). The DEFAULT keyword is a special keyword used
24 when a search fails. Other special keywords include HAIL, used when starting a
25 conversation, and BYE, used when ending a conversation.
26
27
28 --Special Keywords
29
30  Normally a keyword is something the player types during a conversation, but
31  the following keywords are special in that the engine generates them
32  automatically in certain situations.
33
34         DEFAULT If the player keyword does not match anything in the
35                 conversation, then the engine looks up the response for the
36                 DEFAULT keyword instead. This gives NPC characters the chance
37                 to customize their "I don't know" response.
38
39         HAIL    When the conversation first starts up, before the player has a
40                 chance to give a query, the engine will check if the
41                 conversation has a response for the HAIL keyword and will
42                 invoke it if so. This gives NPC characters a chance to have the
43                 first word.
44
45         BYE     When the conversation terminates, after the player has issued
46                 his last query and received a response, the engine will check
47                 if the conversation has a response to the BYE keyword and will
48                 invoke it if so. This gives NPC characters a chance to say
49                 "Farewell" or have the last word.
50
51 The player may type these keywords and they will be looked up in the usual way.
52
53
54 --Responses
55
56 In the grammar above a qr_pair is a <query> (which is a simple string) and a
57 tag. The tag refers to a response. Each response is defined separately in its
58 own construct. Because responses are independent you may mix them with
59 different keywords in different conversations as you like. The syntax for a
60 response declaration is like this:
61
62         <tagged_response> := RESP tag <response-list>
63
64         <response-list> := { <response> <response-or-nil> }
65
66         <response> := SAY string              |
67                       TRADE <trade-list>      |
68                       TURN_AWAY               |
69                       SET_FLAG flag           |
70                       CLEAR_FLAG flag         |
71                       TAKE GOLD               |
72                       CHANGE_PARM <parm-id> <delta> |
73                       TAKE_ITEM tag           |
74                       GIVE_ITEM tag           |
75                       JOIN                    |
76                       ATTACK                  |
77                       GET_AMOUNT              |
78                       <check> <response-list> <response-list>
79
80                       /* Proposed constructs: */
81                       MENU <menu> |
82                       BREAK
83
84         <delta> := +int | -int
85         <trade-list> := { <trade-entry> <trade-entry-or-nil> }
86         <trade-entry> := tag <price>
87         <price> := int
88
89         <check> := GET_YES_NO |
90                    CHECK_PARM <parm-id> operator int |
91                    CHECK_FLAG flag int bool |
92                    CHECK_ITEM tag |
93                    CHECK_MEMBER tag
94
95         <parm-id> := int
96
97         <menu> := { <menu-item> <menu-item-or-nil> }
98         <menu-item> := <name> <cost> <response-list>
99         <name> := string
100         <cost> := int
101
102         <menu-item-or-nil> := <menu-item> |
103         
104         <response-or-nil> := <response> |
105
106
107         SAY     The SAY command prints a line on the console. It prints the
108                 literal string that follows it with no formatting.
109
110         TRADE   The TRADE command invokes the trading subroutine of the game
111                 engine, providing it a list of items and prices to trade. The
112                 engine automatically adds buy/sell and quantity prompts and
113                 handles the exchange of money and goods.
114
115                 When the player opts to Buy he sees the list of goods and
116                 prices. He can buy as many as he cares to and can afford (in
117                 other words the merchant has an endless supply of the goods
118                 listed).
119
120                 When the player opts to Sell then the engine scans player
121                 inventory and lists any of the items from inventory which
122                 appear on the trade list. The sell price is fixed at 1/4 of the
123                 buying price. This constant is currently hard-coded in the
124                 engine and applies to all trade situations.
125
126         TURN_AWAY
127                 The TURN_AWAY command causes the NPC to terminate the
128                 conversation without player consent. The player will see a
129                 console message like "Hawknoz turns away." and then
130                 conversation mode will be over.
131
132         SET_FLAG
133                 The SET_FLAG command sets the value of the specified flag,
134                 causing a subsequent CHECK_FLAG to evaluate to true. The
135                 opposite of SET_FLAG is CLEAR_FLAG.
136
137         CLEAR_FLAG
138                 The opposite of SET_FLAG.
139
140         TAKE_GOLD
141                 Decrement the player's gold counter by the indicated
142                 amount. The engine will not decrement beyond zero. (Note that
143                 there is no corresponding GIVE_GOLD simply because I haven't
144                 needed it).
145
146         CHANGE_PARM
147                 Change the indicated parameter by the indicated amount. If the
148                 amount is negative the engine will not decrement beyond
149                 zero. (Note the absence of a SET_PARM - again because I haven't
150                 needed it yet).
151
152         TAKE_ITEM
153                 Decrement one count of the indicated item type from player
154                 inventory. If the player has none in inventory then this has no
155                 effect. If the tag does not resolve to an item type then this
156                 has no effect.
157
158                 Note: currently this does not add the item to the NPC's
159                 inventory, as one might expect.
160
161         GIVE_ITEM
162                 The opposite of TAKE_ITEM. This does not actually remove
163                 anything from the NPC's inventory.
164
165         GET_YES_NO
166                 Prompt the player to answer yes or no. The player must respond
167                 with one or the other (ie he cannot escape from the
168                 prompt). "Yes" means true and "no" means false.
169
170          CHECK_PARM
171                 Check if the given expression is true for the indicated
172                 parameter.
173
174          CHECK_FLAG
175                 Test if a flag is set.
176
177          CHECK_ITEM
178                 Check if the player has at least one count of the indicated
179                 item in inventory.
180
181          CHECK_MEMBER
182                 Check if the indicated character has joined the player party.
183
184          
185          /* Proposed constructs */
186          
187          MENU   Use the status window to display a list of choices to the
188                 player. When the player selects an entry from the list the
189                 corresponding set of responses is executed. Upon completion -
190                 unless one of the responses was a BREAK or EXIT - the menu will
191                 "loop", displaying the list of choices again. MENUs may be
192                 nested.
193
194          BREAK  Break out of a MENU loop. Execution resumes after the MENU
195                 block. If the MENUs are nested, only the lowest level MENU is
196                 aborted.
197
198 ---Flags
199
200 The SET_FLAG, CLEAR_FLAG and CHECK_FLAG responses all operate on flags. A flag
201 is an unsigned 8-bit integer id for a boolean value. 
202
203 Flags may be global or per-conversation. Global flags may be accessed from any
204 conversation in the game. Per-conversation flags apply only to the conversation
205 in which they appear. Different conversations may use the same per-conversation
206 flag id but each will have its own value for the flag. Per-conversation flag
207 ids have the high bit clear (giving them the range 0 to 127) and global flag
208 ids have the high bit set (giving them the range 128 to 255).
209
210 Note: Initially all flags are clear. When savegames are implemented flag values
211 will need to be saved/restored, so in the future there will need to be syntax
212 for specifying initial flag values.
213
214
215 ---Parameters
216
217 The CHANGE_PARM and CHECK_PARM responses operate on parameters. A parameter is
218 a signed 32-bit id for an integer value.
219
220 The engine reserves all negative parameter ids. The following parameter ids are
221 currently supported by the engine:
222
223         -1 AMOUNT
224                 The AMOUNT parameter refers to the value obtained by the last
225                 GET_AMOUNT response. A value of -1 means the player did not
226                 enter an amount at the last prompt (i.e. escaped out of the
227                 prompt).
228
229         -2 GOLD
230                 This refers to the player's gold counter.
231
232         -3 FOOD
233                 This refers to the player's food counter.
234
235         -4 ACTIVITY
236                 This refers to the speaking NPC party's current activity
237                 code. Activity codes are used by schedules. This parameter
238                 allows conversation scripts to change their response based on
239                 what the npc party is currently doing. For example, in u5 the
240                 NPC merchants would not trade with the player when they were
241                 not in their shop.
242
243 All parameter id's of 0 or greater are available for use by the game script.
244
245 All parameters are global in scope.
246
247 Note: Initially all non-reserved parameters are zero. When savegames are
248 implemented parameter values will need to be saved/restored, so in the future
249 there will need to be syntax for specifying initial parameter values.
250
251
252 ---Branching
253
254 The GET_YES_NO, CHECK_PARM, CHECK_FLAG, CHECK_ITEM and CHECK_MEMBER responses
255 are all branching responses. They each specify a test and two sets of
256 responses. If the test evaluates to true then the first set executes, otherwise
257 the second set executes.
258
259
260 ---Examples
261
262 These are not final, but are experimental examples for my own benefit while
263 designing changes to the language.
264
265 Example: a healer. This example illustrates how one might use some as-yet
266 unimplemented constructs like MENU, GET_PARTY_MEMBER, CHANGE_HP and an
267 unsupported PARTY_MEMBER parameter to script a healer. Note the heavy
268 duplication of code for each menu response, and also the dubious syntax for
269 checking if the player escaped out of the GET_PARTY_MEMBER prompt.
270
271 RESP r_healer {
272     SAY "Hail, traveler! Do you require my healing services?"
273     GET_YES_NO {
274         MENU {
275             "Heal        30g"  {
276                 CHECK_PARM GOLD >= 30 {
277                     SAY "Who requires healing?"
278                     GET_PARTY_MEMBER
279                     CHECK_PARM PARTY_MEMBER = 0 {
280                         SAY "Never mind then."
281                     }{                    
282                         CHANGE_HP PARTY_MEMBER +10
283                     }
284                 }{
285                     SAY "You lack the gold, my friend."
286                 }
287             }
288             "Cure       50g" {
289                 SAY "Whom shall I cure?"
290                 GET_PARTY_MEMBER
291                 CHECK_PARM PARTY_MEMBER = 0 {
292                     SAY "Never mind then."
293                 }{
294                     SET_POISONED PARTY_MEMBER false
295                 }
296             }
297             "Resurrect 500g" {
298                 SAY "Whom shall I call back from the dead?"
299                 GET_PARTY_MEMBER
300                 CHECK_PARM PARTY_MEMBER = 0 {
301                     SAY "Never mind then."
302                 }{
303                     SET_DEAD PARTY_MEMBER false
304                     CHANGE_HP PARTY_MEMBER +10
305                 }
306             }
307             "Done" { 
308                 SAY "Very well." 
309                 BREAK /* exit the MENU loop */
310             }
311         }
312     }{
313         SAY "Very well."    
314     }
315 }
316
317
318 Example: A weapon merchant. The example illustrates the use of a
319 yet-unimplemented technique whereby one response "calls" another by referring
320 to its tag. The r_weaponsmith_hail response invokes the r_sell_to_player
321 response in order to avoid some of the duplication seen above in the healer
322 example. "Arguments" to the "called" response take the form of parameters set
323 by the caller before invoking it.
324
325 Note that I left the SELL clause blank because I was at a loss on how to
326 proceed. There is no proposed syntax for building a MENU list on the fly at
327 runtime, and that is essentially what is required for the SELL clause as
328 written. An alternative is not to use a MENU for sell, but to use hand-crafted
329 checks for items in player inventory followed by offers to buy them one type at
330 a time off the player.
331
332 Also note the use of multiplication in the r_sell_to_player response. This is
333 currently not implemented.
334
335
336 RESP r_sell_to_player {
337     SAY "How many would you like?"
338     GET_AMOUNT
339     CHECK_PARM AMOUNT > 0 {
340         SET_PARM COST (AMOUNT * COST)
341         CHECK_PARM GOLD >= COST) {
342             SAY "Here you go.";
343             TAKE GOLD COST;
344             GIVE t_sword AMOUNT;
345         }{
346             SAY "You don't have enough gold!";
347         }
348     }{
349         SAY "Changed your mind, eh?";
350     }     
351 }
352
353 RESP r_weaponsmith_hail {
354     SAY "Hail, traveler! Do you require my healing services?"
355     GET_YES_NO {
356         MENU {
357             "Buy"  {
358                 MENU {
359                     "Swords 100g" {
360
361
362                         /*
363                          * "Call" the other response after setting up the
364                          * "arguments" to it.
365                          */
366                         SET_PARM ITEM $t_sword; 
367                         SET_PARM COST 100;
368                         $r_sell_to_player;
369
370                     }
371                     /*** add other items here ***/
372                     "Done" { 
373                         BREAK;
374                     }
375                 }
376             }
377             "Sell" { 
378             
379             }
380             "Done" { 
381                 SAY "Very well.";
382                 BREAK; /* exit the MENU loop */
383             }
384         }
385     }{
386         SAY "Hrumph.";
387         EXIT;
388     }
389 }
390
391 ----------------------------------------------------------------------------
392 Spell Effects
393
394 An effect is a change to an object, map or place.
395
396 A recurring effect is attached to a target and takes effect every turn. Wether
397 or not an effect is recurring is determined by its duration. A duration of < 0
398 means it recurs indefinitely (until some other effect removes it). A duration
399 of > 0 indicates the number of turns for which the effect will recur before
400 expiring. A duration of 0 means the effect is not recurring. Henceforth, I
401 DON'T DISTINGUISH BETWEEN RECURRING EFFECTS AND EFFECTS IN THIS DISCUSSION.
402
403 A spell attaches a set of effects to a set of targets. A conversation response
404 may do the same. So may using an item, stepping on a terrain, or engaging a
405 mech. When it comes to effects, the difference between all these things lies in
406 how the set of targets is specified. Specifying the set of effects probably
407 won't change much between them. But this discussion is about spells. I only
408 mention those other things as a reminder.
409
410 An effect is a change, so what can be changed? It depends on the target. I've
411 listed below some of the most reasonable things I can think of.
412
413         Character Hit Points
414         Character Mana Points
415         Character Strength
416         Character Dexterity
417         Character Intelligence
418         Character Experience
419         Character Level
420         Object Glow
421         Character or Party Turns
422         Object Location
423         Character or Party Alignment
424         Character, Vehicle, Terrain or Mech Passability
425         Character or Party Can Take a Turn
426         Character is Dead  
427         Hidden Objects are Revealed
428         Time is Stopped
429         Magic is Negated
430         Wind Direction
431         Object's Existence
432         Terrain Type
433         Object's Edibility
434         Ambient Glow
435         Mechanism Jam
436         Mechanism Signals
437         Existing Effects (an effect that affects another effect)
438         Object User Bits*
439         Object User Fields*
440
441 Those last two (marked with asterisks) probably don't make a lot of sense to
442 you now. Why are they there? Well, I can't think of everything a map hacker is
443 going to want to design into a game. And some things I don't think require
444 engine support. For example, u4/u5 had a virtue system. Currently nazghul does
445 not. But by taking advantage of the user bits or user fields a map hacker can
446 add one. These bits and fields have no semantic value to the engine, but they
447 can be interpreted by the ghulscript. They can be modified by effects, and they
448 can be checked by conversation scripts (and perhaps eventually mech
449 scripts). Remind me to provide an example somewhere if you're interested in,
450 that's all I'm going to say for now.
451
452 An effect specification is a piece of ghulscript which declares an effect. Once
453 declared, an effect can be referred to elsewhere in the script (such as terrain
454 or spell type declarations). I'll show the syntax further down (after I figure
455 out what it is ;-)).
456
457 Anyway, the first part of an effect specification is WHAT it affects. I refer
458 to this as the SUBJECT OF THE EFFECT.
459
460 The next part specifies IN WHAT WAY it effects it. This part of the spec
461 depends upon what type of attribute is affected. Here's a table:
462
463 ============================================================================
464 Target Type | Subject      | Subject Type    | Notes
465 ============================================================================
466 Character   | Alignment    | SET             |
467 Character   | Dead         | BOOL            | Necessary? Or HP==0 enough?
468 Character   | Dexterity    | INT             |
469 Character   | Experience   | INT             |
470 Character   | Field[0-9]   | INT             | Generic attributes
471 Character   | Flags        | SET             | Generic flags
472 Character   | Hit Points   | INT             |
473 Character   | Immunity     | SET             | Effect immunities
474 Character   | Intelligence | INT             |
475 Character   | Level        | INT             |
476 Character   | Lose Turn    | BOOL            |
477 Character   | Mana Points  | INT             |
478 Character   | Occupation   | TAG             | Change jobs
479 Character   | Passability  | SET             |
480 Character   | Protections  | SET (?)         |
481 Character   | Species      | TAG             | Were-shift somebody
482 Character   | Speed        | INT             |
483 Character   | Strength     | INT             |
484 Effect      | Existence    | BOOL            | Remove another effect
485 Mech        | Passability  | SET             | Applies to current state
486 Mech        | Jam          | BOOL            |
487 Mech        | Signal       | INT             |
488 Object      | Glow         | INT             |
489 Object      | Location     | (TAG, INT, INT) | Meaning (place, x, y)
490 Object      | LocationDelt | (TAG, INT, INT) | 
491 Object      | Visible      | BOOL            | Applies to particular object
492 Object      | Existence    | BOOL            | Used to destroy an object
493 Object      | Type         | TAG             | Morph an object
494 Object      | Edibility    | BOOL            | Turn something into food
495 Party       | Lose Turn    | BOOL            |
496 Party       | Speed        | INT             |
497 Party       | Alignment    | SET             |
498 Party       | Reveal       | BOOL            | Can see invisible objects
499 Party       | TimeStop     | BOOL            | Only this party can take turns
500 Party       | MagicNegated | BOOL            | Spellcasting disabled
501 Place       | Wind Directi | DIR             | Wind direction
502 Place       | Ambient Glow | INT             |
503 Terrain     | Passability  | SET             |
504 Tile        | Terrain Type | TAG             |
505 Vehicle     | Passability  | SET             |
506
507 The engine can infer the subject type from the target type and subject, so
508 there's no need to specify it in the script. But map hackers will need this
509 info as they design effects. If a spec gives a value which is the wrong type
510 then the engine needs to complain about it at load time.
511
512 The value of an effect is the amount or direction by which the subject changes,
513 or the value to which the subject is set. For scaler and vector subject types
514 the value of the effect might be a signed offset. This would be added to the
515 existing value. The possible operations for each subject meta-type are listed
516 below:
517
518 ============================================================================
519 Subject Metatype | Operations
520 ============================================================================
521 scaler           | assign, add, subtract, multiply
522 vector           | assign, add, subtract, multiply
523 tag              | assign, instantiate, destroy(?)
524 bool             | assign, invert
525 set              | assign, intersect, union, invert
526 ============================================================================
527
528 Multiple operations can be combined.
529
530 An effect is a change which is achieved by some means, and the means indicates
531 wether or not the effect will apply to a particular target. Some targets may be
532 immune to a particular means so that the effect will not apply. Or some targets
533 may have modifiers which apply to a particular means which reduce the value of
534 the effect.
535
536 At this point I can speculate about what an effect specification is going to
537 look like:
538
539 EFFECT MagicFireball {
540    target_type Character;
541    subject     HitPoints;
542    value       -10
543    method      (MAGIC|BURN)
544 }
545
546 // Reduce the value of burn effects by 10
547 EFFECT Protection {
548    target_type Character;
549    subject     Protections;
550    value       +10
551    method      (BURN)   
552 }
553
554 // Make a character immune to burning effects
555 EFFECT BurnImmunity {
556    target_type Character;
557    subject     Immunity;
558    value       +BURN
559    method      (MAGIC)
560 }
561
562 // Here's an effect which might be produced by a sword:
563 EFFECT EdgedWeaponDamage {
564    target_type Character;
565    subject     HitPoints;
566    value       -5
567    method      (EDGED_WEAPON)
568 }
569
570 // And here's one which might be produced by a shield:
571 EFFECT EdgedWeaponDamageProtection {
572    target_type Character;
573    subject     Protections;
574    value       +5
575    method      (EDGED_WEAPON)
576 }
577
578 But what if the character is immune to heat damage? To accomodate immunities in
579 the game the effect must specify HOW the effect is achieved. Now the engine has
580 no interest in the semantics here, so we can use an open set and let map
581 hackers decide what they want the elements of a set to "mean".
582
583 Not to get too far off track, but you can see that I'm thinking about the way
584 sets should be represented in ghulscript. Currently we use a bitmask. This may
585 be a bit too esoteric for normal people. So instead I'm considering a new
586 ghulscript construct to pre-declare set elements similar to an
587 enumeration. I see no reason to discard the C bitwise operators as a means of
588 constructing sets.
589
590 EFFECT Burn {
591    // same as before
592    method     (BURN) // where BURN is a script-defined set element
593 }
594
595 So how does the engine know not to burn a character if that character is immune
596 to burn effects? It does this by checking the character's immunity set. If any
597 element in the effect method set is not in the character immunity set, then the
598 effect is applied. For those who like to think about such things, consider an
599 effect which confers immunity to effects which confer immunity... :-)
600
601 How is the effect achieved?
602
603         Poison
604         Fire
605         Acid
606         Sleep
607         Paralysis
608         Petrify
609         Frighten
610         Encourage
611         Extensible Bits
612
613 How is the effect quantified?
614
615         Integer
616         Integer Offset
617         Boolean
618         Direction
619         Location
620         Location Offset
621         Object Type
622         Terrain Type
623         Terrain Map
624
625 How is the target specified?
626
627         Object
628         Object Type
629         Tile
630         Tile Rectangle
631         Tile Circle
632         Alignment        
633         Species
634         Occupation
635         Circle Arc
636         Passability
637
638 What special effects apply?
639
640         Change the character's sprite to prone (sleeping, unconscious or dead)
641         Shake the screen
642         Animated missile
643         Animated shockwave (arc-specified)
644         Chain lightning
645         Meteor strike
646         Sounds
647         Screen flash
648         Alpha transparency
649
650 Examples:
651
652         An Nox (Cure Poison)
653         What: Existing Character Effect
654         How: Poison
655         Value: False
656         Target Method: Select Party Member
657         
658         In Nox Por (Poison)
659         What:   Character Hit Points
660         How:    Poison
661         Value:  -10
662         Dur:    Indefinite
663         Target: Tile
664         Cumul:  No
665         Multi:  No        
666         
667         Because it affects specifically Character hit points, the engine knows
668         to search the targeted tile for a Character object. Because it does not
669         support multiple targets only the first Character found will be
670         affected. Because the effect is not cumulative the engine will search
671         the list of existing effects for the Character to make sure a Poison
672         effect is not already at work. If not then it checks the Character's
673         immunity mask and if the Poison bit is set then the effect is
674         ignored. Otherwise it inserts the new effect in the list of effects for
675         the character and applies -10 to the Character hit points. Since the
676         duration is indefinite the engine does not decrement the duration
677         counter.
678
679 Effects which create objects are a bit different then what is discussed
680 above. Such an effect has no subject, as it is not changing an existing
681 object's attributes. Instead it is creating a new subject.
682
683 There are several ways to carry out object creation. First of all, we must
684 unfortunately distinguish between characters and other object types. The reason
685 is that most objects have a type, and this type specifies the default values
686 for an object. But characters do not have a single type. Instead they have a
687 species, an occupation, a schedule and a conversation. Perhaps they should have
688 a type which combines all these elements. The downside is you end up with a lot
689 of character types which will only have a single instance because the type info
690 is so specific to a single character, which is why I deviated from the rule a
691 bit. Anyway, besides that distinction we must also recognize that sometimes we
692 want to create a new object from scratch and sometimes we want to clone an
693 existing object.
694
695 EFFECT SlimeCloneWhenDamaged {
696         target_type   Character;
697         target_method Effected;
698         subject       Existence;
699         hook          HpReduced;
700         source        ();
701         value         new;
702         probability   0.25;
703 }
704
705
706
707 Prototype header file:
708
709         // What the effect applies to.
710         enum effect_target_type {
711                 effect_target_type_none = 0,
712         };
713
714         // How to pick what the effect applies to.
715         enum effect_target_method {
716                 effect_target_method_none = 0,
717                 effect_target_method_affected,
718         };
719
720         // What is being changed about the thing the effect applies to?
721         enum effect_subject {
722                 effect_subject_none = 0,
723                 effect_subject_affected,
724         };
725
726         // List of subject value types.
727         enum effect_value_type {
728                 effect_value_none = 0,
729                 effect_value_tag,
730                 effect_value_bool,
731                 effect_value_int,
732                 effect_value_float,
733         };
734
735         // How is the value of the subject going to be changed?
736         struct effect_value {
737                 enum effect_value_type type;
738                 union value {
739                         char *tag;
740                         int _bool:1;
741                         int _int;
742                         float _float;
743                 };
744         };
745
746         // List of events which invoke an effect ("hooks" an effect is attached
747         // to)
748         enum effect_hook {
749                 effect_hook_none = 0,
750                 effect_hook_hp_reduced,
751         };
752
753         // List of ways to specify a target for an effect.
754         enum effect_target_method {
755                 effect_target_none = 0,
756                 effect_target_effected,  // whatever the effect is attached to
757         };
758
759         // List of operators applied to the subject
760         enum effect_operator {
761                 effect_operator_none     = 0,
762                 effect_operator_assign   = '=',
763                 effect_operator_new      = 'n',
764                 effect_operator_delete   = 'd',
765                 effect_operator_clone    = 'c', // the subject
766                 effect_operator_add      = '+', // w/ assignment to subject
767                 effect_operator_subtract = '-', // w/ assignment to subject
768                 effect_operator_multiply = '*', // w/ assignment to subject
769                 effect_operator_divide   = '/', // w/ assignment to subject
770         };
771
772         // The effect data structure.
773         struct effect {
774                 char *tag;
775                 struct list list;
776                 enum effect_target_type type;
777                 enum effect_target_method target_method;
778                 enum effect_subject subject;
779                 enum effect_hook hook;
780                 enum effect_source source;
781                 enum effect_operator operator;
782                 struct effect_value value;
783                 float probability;
784         };
785
786         // Create and initialize an effect structure from ghulscript.
787         extern struct effect *effect_load(class Loader *);
788
789         // Apply an effect (attempt to, anyway).
790         extern int effect_apply(struct effect *effect, class Object *affected);
791
792         // Properly deallocate an effect structure.
793         extern void effect_destroy(structeffect *effect);
794