summaryrefslogblamecommitdiff
path: root/src/map/magic-interpreter.hpp
blob: 21e8d3987da2cf6edd09580d84a3c64801602d21 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                       

                             





                   




















                               
 


                                                                                         







                         
                         






















                           



                       






                         



                   
                         










                                   
        
              


                     




                   
                       
                                                                                                            

                              
                                                                                                                        




                              



                 
                                                                                        





                         
                         
 

                         


                           



                     
                           










                                             



                     



                   


                                











                                        



                     





















                                 
                                 
 




























                                                      
                                   












                                   



                     
                
                

                

                        
                           

                 

              











                                 


                                           

               

                         
                            

           




                                  
                                                                    




                              



            


                     


                 


                                                                                                     
 

                    

                     



                                                                            
 
                    








                             

                              








                         


                 
                          
                                                                          
 

                        
 
                   

                     
                                                                             


                                













                                 

                  









                                 

                                     
                              





















                                   



                           



                                

                      


                                                                                                                                
 

                         


                                                                                                                               
               


                   

                                                                                         
 
                                                         
 
                    

                                                   
                                                                                                     
                             

                                                                                                                                                                          

                                                                                                   
                               



                                            


                                                              


                                                                                 
                                                                              
 
                                                  



                                                                                                               

                                                                            
 
                                  
 


                                                                                                                                         

                                                                   
 
                                                                     



                                                                  
                                                                   
 

                                                                     



                                            
                                                         
 
                                             

                                               


                       


                  





                   

         



                                                       
                                           
/* Magic interpreter */

#ifndef MAGIC_INTERPRETER_HPP
#define MAGIC_INTERPRETER_HPP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "../common/nullpo.hpp"

#include "battle.hpp"
#include "chat.hpp"
#include "chrif.hpp"
#include "clif.hpp"
#include "intif.hpp"
#include "itemdb.hpp"
#include "magic.hpp"
#include "map.hpp"
#include "mob.hpp"
#include "npc.hpp"
#include "pc.hpp"
#include "party.hpp"
#include "script.hpp"
#include "skill.hpp"
#include "storage.hpp"
#include "trade.hpp"

#include "../common/timer.hpp"
#include "../common/socket.hpp"

#define SPELLARG_NONE	0       /* No spell parameter */
#define SPELLARG_PC	1           /* Spell parameter describes pc (defaults to self) */
#define SPELLARG_STRING	2       /* Spell parameter describes pc (defaults to self) */

/* ------ */
/* Values */
/* ------ */

#define TY_UNDEF	0
#define TY_INT		1
#define TY_DIR		2
#define TY_STRING	3
#define TY_ENTITY	5
#define TY_LOCATION	6
#define TY_AREA		7
#define TY_SPELL	8
#define TY_INVOCATION	9
#define TY_FAIL		127

#define DIR_S	0
#define DIR_SW	1
#define DIR_W	2
#define DIR_NW	3
#define DIR_N	4
#define DIR_NE	5
#define DIR_E	6
#define DIR_SE	7

struct expr;
struct val;
struct location;
struct area;
struct spell;
struct invocation;

typedef struct location
{
    int  m;
    int  x, y;
} location_t;

#define AREA_LOCATION	0
#define AREA_UNION	1
#define AREA_RECT	2
#define AREA_BAR	3

typedef struct area
{
    union a
    {
        location_t a_loc;
        struct
        {
            location_t loc;
            int  width, depth, dir;
        } a_bar;
        struct
        {
            location_t loc;
            int  width, height;
        } a_rect;
        struct area *a_union[2];
    } a;
    int  size;
    unsigned char ty;
} area_t;

typedef struct val
{
    union v
    {
        int  v_int;
        char *v_string;
        entity_t *v_entity;     /* Used ONLY during operation/function invocation; otherwise we use v_int */
        area_t *v_area;
        location_t v_location;
        struct invocation *v_invocation;    /* Used ONLY during operation/function invocation; otherwise we use v_int */
        struct spell *v_spell;
    } v;
    unsigned char ty;
} val_t;

/* ----------- */
/* Expressions */
/* ----------- */

#define MAX_ARGS 7              /* Max. # of args used in builtin primitive functions */

#define EXPR_VAL	0
#define EXPR_LOCATION	1
#define EXPR_AREA	2
#define EXPR_FUNAPP	3
#define EXPR_ID		4
#define EXPR_SPELLFIELD	5

typedef struct e_location
{
    struct expr *m, *x, *y;
} e_location_t;

typedef struct e_area
{
    union a0
    {
        e_location_t a_loc;
        struct
        {
            e_location_t loc;
            struct expr *width, *depth, *dir;
        } a_bar;
        struct
        {
            e_location_t loc;
            struct expr *width, *height;
        } a_rect;
        struct e_area *a_union[2];
    } a;
    unsigned char ty;
} e_area_t;

typedef struct expr
{
    union e
    {
        val_t e_val;
        e_location_t e_location;
        e_area_t e_area;
        struct
        {
            int  id, line_nr, column;
            int  args_nr;
            struct expr *args[MAX_ARGS];
        } e_funapp;
        int  e_id;
        struct
        {
            struct expr *expr;
            int  id;
        } e_field;
    } e;
    unsigned char ty;
} expr_t;

/* ------- */
/* Effects */
/* ------- */

#define EFFECT_SKIP	0
#define EFFECT_ABORT	1
#define EFFECT_ASSIGN	2
#define EFFECT_FOREACH	3
#define EFFECT_FOR	4
#define EFFECT_IF	5
#define EFFECT_SLEEP	6
#define EFFECT_SCRIPT	7
#define EFFECT_BREAK	8
#define EFFECT_OP	9
#define EFFECT_END	10
#define EFFECT_CALL	11

#define FOREACH_FILTER_MOB	1
#define FOREACH_FILTER_PC	2
#define FOREACH_FILTER_ENTITY	3
#define FOREACH_FILTER_TARGET	4
#define FOREACH_FILTER_SPELL	5
#define FOREACH_FILTER_NPC	6

typedef struct effect
{
    struct effect *next;
    union e0
    {
        struct
        {
            int  id;
            expr_t *expr;
        } e_assign;
        struct
        {
            int  id;
            expr_t *area;
            struct effect *body;
            unsigned char filter;
        } e_foreach;
        struct
        {
            int  id;
            expr_t *start, *stop;
            struct effect *body;
        } e_for;
        struct
        {
            expr_t *cond;
            struct effect *true_branch, *false_branch;
        } e_if;
        expr_t *e_sleep;        /* sleep time */
        const ScriptCode *e_script;
        struct
        {
            int  id;
            int  args_nr;
            int  line_nr, column;
            expr_t *args[MAX_ARGS];
        } e_op;
        struct
        {
            int  args_nr, *formals;
            expr_t **actuals;
            struct effect *body;
        } e_call;
    } e;
    unsigned char ty;
} effect_t;

/* ---------- */
/* Components */
/* ---------- */

typedef struct component
{
    struct component *next;
    int  item_id;
    int  count;
} component_t;

/* ----------- */
/* Spellguards */
/* ----------- */

#define SPELLGUARD_CONDITION	0
#define SPELLGUARD_COMPONENTS	1
#define SPELLGUARD_CATALYSTS	2
#define SPELLGUARD_CHOICE	3
#define SPELLGUARD_MANA		4
#define SPELLGUARD_CASTTIME	5
#define SPELLGUARD_EFFECT	6

typedef struct effect_set
{
    effect_t *effect, *at_trigger, *at_end;
} effect_set_t;

typedef struct spellguard
{
    struct spellguard *next;
    union s
    {
        expr_t *s_condition;
        expr_t *s_mana;
        expr_t *s_casttime;
        component_t *s_components;
        component_t *s_catalysts;
        struct spellguard *s_alt;   /* either `next' or `s.s_alt' */
        effect_set_t s_effect;
    } s;
    unsigned char ty;
} spellguard_t;

/* ------ */
/* Spells */
/* ------ */

typedef struct letdef
{
    int  id;
    expr_t *expr;
} letdef_t;

#define SPELL_FLAG_LOCAL	(1 << 0)    // spell associated not with caster but with place
#define SPELL_FLAG_SILENT	(1 << 1)    // spell invocation never uttered
#define SPELL_FLAG_NONMAGIC	(1 << 2)    // `magic word' only:  don't require spellcasting ability

typedef struct spell
{
    char *name;
    char *invocation;
    int  index;                 // Relative location in the definitions file
    int  flags;
    int  arg;
    int  spellarg_ty;

    int  letdefs_nr;
    letdef_t *letdefs;

    spellguard_t *spellguard;
} spell_t;

/* ------- */
/* Anchors */
/* ------- */

typedef struct teleport_anchor
{
    char *name;
    char *invocation;
    expr_t *location;
} teleport_anchor_t;

/* ------------------- */
/* The big config blob */
/* ------------------- */

typedef struct
{
    int  vars_nr;
    const char **var_name;
    val_t *vars;                /* Initial assignments, if any, or NULL */

    int  obscure_chance;
    int  min_casttime;

    int  spells_nr;
    spell_t **spells;

    int  anchors_nr;            /* NEGATIVE iff we have sorted the anchors */
    teleport_anchor_t **anchors;
} magic_conf_t;

/* Execution environment */

#define VAR_MIN_CASTTIME	0
#define VAR_OBSCURE_CHANCE	1
#define VAR_CASTER		2
#define VAR_SPELLPOWER		3
#define VAR_SPELL		4
#define VAR_INVOCATION		5
#define VAR_TARGET		6
#define VAR_SCRIPTTARGET	7
#define VAR_LOCATION		8

struct magic_config;

typedef struct env
{
    magic_conf_t *base_env;
    val_t *vars;
} env_t;

#define MAX_STACK_SIZE 32

#define CONT_STACK_FOREACH	0
#define CONT_STACK_FOR		1
#define CONT_STACK_PROC		2

typedef struct cont_activation_record
{
    effect_t *return_location;
    union c
    {
        struct
        {
            int  id, ty;
            effect_t *body;
            int  entities_nr;
            int *entities;
            int  index;
        } c_foreach;
        struct
        {
            int  id;
            effect_t *body;
            int  current;
            int  stop;
        } c_for;
        struct
        {
            int  args_nr, *formals;
            val_t *old_actuals;
        } c_proc;
    } c;
    unsigned char ty;
} cont_activation_record_t;

typedef struct status_change_ref
{
    int  sc_type;
    int  bl_id;
} status_change_ref_t;

#define INVOCATION_FLAG_BOUND		(1 << 0)    /* Bound directly to the caster (i.e., ignore its location) */
#define INVOCATION_FLAG_ABORTED		(1 << 1)    /* Used `abort' to terminate */
#define INVOCATION_FLAG_STOPATTACK	(1 << 2)    /* On magical attacks:  if we run out of steam, stop attacking altogether */

typedef struct invocation
{
    struct block_list bl;

    struct invocation *next_invocation; /* used for spells directly associated with a caster: they form a singly-linked list */
    int  flags;

    env_t *env;
    spell_t *spell;
    int  caster;                /* this is the person who originally invoked the spell */
    int  subject;               /* when this person dies, the spell dies with it */

    int  timer;                 /* spell timer, if any */

    int  stack_size;
    cont_activation_record_t stack[MAX_STACK_SIZE];

    int  script_pos;            /* Script position; if nonzero, resume the script we were running. */
    effect_t *current_effect;
    effect_t *trigger_effect;   /* If non-NULL, this is used to spawn a cloned effect based on the same environment */
    effect_t *end_effect;       /* If non-NULL, this is executed when the spell terminates naturally, e.g. when all status changes have run out or all delays are over. */

    /* Status change references:  for status change updates, keep track of whom we updated where */
    int  status_change_refs_nr;
    status_change_ref_t *status_change_refs;

} invocation_t;

extern magic_conf_t magic_conf; /* Global magic conf */
extern env_t magic_default_env; /* Fake default environment */

/**
 * Adds a component selection to a component holder (which may initially be NULL)
 */
void magic_add_component (component_t ** component_holder, int id, int count);

teleport_anchor_t *magic_find_anchor (char *name);

/**
 * The parameter `param' must have been dynamically allocated; ownership is transferred to the resultant env_t.
 */
env_t *spell_create_env (magic_conf_t * conf, spell_t * spell,
                         character_t * caster, int spellpower, char *param);

void magic_free_env (env_t * env);

/**
 * near_miss is set to nonzero iff the spell only failed due to ephemereal issues (spell delay in effect, out of mana, out of components)
 */
effect_set_t *spell_trigger (spell_t * spell, character_t * caster,
                             env_t * env, int *near_miss);

invocation_t *spell_instantiate (effect_set_t * effect, env_t * env);

/**
 * Bind a spell to a subject (this is a no-op for `local' spells).
 */
void spell_bind (character_t * subject, invocation_t * invocation);

int                             // 1 on failure
     spell_unbind (character_t * subject, invocation_t * invocation);

/**
 * Clones a spell to run the at_effect field
 */
invocation_t *spell_clone_effect (invocation_t * source);

spell_t *magic_find_spell (char *invocation);

/* The following is used only by the parser: */
typedef struct args_rec
{
    int  args_nr;
    expr_t **args;
} args_rec_t;

typedef struct
{
    char *name;
    int  args_nr;
    int *args;
    effect_t *body;
} proc_t;

// must be called after itemdb initialisation
int magic_init(const char *);
void spell_update_location (invocation_t * invocation);

#endif /* !defined (MAGIC_INTERPRETER_H) */