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

                             
 

                                  

                  

                    
                     
                      
 

             




                  

                  
                 
 
                 
             
  
 
             
 
            
     
                         


                           

                             



                           
                              
                 

                                    
                                           


                                             
        
             
            
  
 
            
 
            
     
                  
                  



                                                                                    
                              



                                                                                    



                                             
        
            
  
 



                 
                                                                                        
 
                   
 

                             
 
               


            
                           


                             
                                               



                             
                                           
                 

                                      
                                           


                                             
        
            
  
 
             
 
            
     


                                

              

                                
                        
                                            
                   
                 

              
                                  
                   
                  
 
                                           


                                             
        
            
  
 
               
 
                            



              
                   
                                  


                   
                   

                                    
                                  


                    
                   

                                         


                

                                                         
               

                                                         

              
                      

                                
                                            


               


                                                             
                 
 
                                           


                                             
        
              
  
 
                
                

                
                  
 
                               

                
  
 
 
                   
 

                                                  
 
                   
 

                                
     





                                                                        
                              
                                           


                                             
        
                  
  
 



            
               
 
           

                          
 
              
 

                       
                     
            
                         
 
                                  
 

                                      




             
                        
 

                       

                              




                         
                   
 

                
                     



                                                                      
 
                                                                              
 
                                                                                          
  
 

                           
                                                    








                                 


                    
            
 
                           











                                         


                         
                               
 

                                       


              
                   
                    

                                                   
                      


                    
                   
                                    

                        


                


                                           
                 
 



                                             
        
                  
  
 
                          
 
                         
              
  
 
                              
 
                                                                                                                                 
                          
 

                            

                                                                                        
 
                                                          
 
                   

                                                   
                                                                                                    


                                                                                                                                                                                   

                                                                                                   
                                                        
 
  
 


                                                                                                                    


                                                              


                                                                                 
                                                                                     
 
                                                            
 
                                                                             
                                                                          
 
                                         
 


                                                                                                                                         


                                                    
 
                                                                                  



                                                                  
                                                                                     
 
               
                                                                                      



                                            
                                                                     
 
                                                       

                                               
                 
 

                                                  
 
             
 
                 








                            
 

                                             
                                                            
 
                               
#ifndef MAGIC_INTERPRETER_HPP
#define MAGIC_INTERPRETER_HPP

#include "magic-interpreter.t.hpp"

#include <cassert>

#include "magic.hpp"
#include "map.hpp"
#include "script.hpp"
#include "skill.t.hpp"

struct fun_t;
struct op_t;
struct expr_t;
struct val_t;
struct location_t;
struct area_t;
struct spell_t;
struct invocation;

struct location_t
{
    map_local *m;
    int x, y;
};

struct area_t
{
    union au
    {
        location_t a_loc;
        struct
        {
            location_t loc;
            int width, depth;
            DIR dir;
        } a_bar;
        struct
        {
            location_t loc;
            int width, height;
        } a_rect;
        dumb_ptr<area_t> a_union[2];

        au() { really_memzero_this(this); }
        ~au() = default;
        au(const au&) = default;
        au& operator = (const au&) = default;
    } a;
    int size;
    AREA ty;
};

struct val_t
{
    union vu
    {
        int v_int;
        DIR v_dir;
        dumb_string v_string;
        /* Used ONLY during operation/function invocation; otherwise we use v_int */
        dumb_ptr<block_list> v_entity;
        dumb_ptr<area_t> v_area;
        location_t v_location;
        /* Used ONLY during operation/function invocation; otherwise we use v_int */
        dumb_ptr<invocation> v_invocation;
        dumb_ptr<spell_t> v_spell;

        vu() { really_memzero_this(this); }
        ~vu() = default;
        vu(const vu&) = default;
        vu& operator = (const vu&) = default;
    } v;
    TYPE ty;
};

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

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

struct e_location_t
{
    dumb_ptr<expr_t> m, x, y;
};

struct e_area_t
{
    union a0
    {
        e_location_t a_loc;
        struct
        {
            e_location_t loc;
            dumb_ptr<expr_t> width, depth, dir;
        } a_bar;
        struct
        {
            e_location_t loc;
            dumb_ptr<expr_t> width, height;
        } a_rect;
        dumb_ptr<e_area_t> a_union[2];

        a0() { really_memzero_this(this); }
        ~a0() = default;
        a0(const a0&) = default;
        a0& operator = (const a0&) = default;
    } a;
    AREA ty;
};

struct expr_t
{
    union eu
    {
        val_t e_val;
        e_location_t e_location;
        e_area_t e_area;
        struct
        {
            fun_t *funp;
            int line_nr, column;
            int args_nr;
            dumb_ptr<expr_t> args[MAX_ARGS];
        } e_funapp;
        int e_id;
        struct
        {
            dumb_ptr<expr_t> expr;
            int id;
        } e_field;

        eu() { really_memzero_this(this); }
        ~eu() = default;
        eu(const eu&) = default;
        eu& operator = (const eu&) = default;
    } e;
    EXPR ty;
};

struct effect_t
{
    dumb_ptr<effect_t> next;
    union e0
    {
        struct
        {
            int id;
            dumb_ptr<expr_t> expr;
        } e_assign;
        struct
        {
            int id;
            dumb_ptr<expr_t> area;
            dumb_ptr<effect_t> body;
            FOREACH_FILTER filter;
        } e_foreach;
        struct
        {
            int id;
            dumb_ptr<expr_t> start, stop;
            dumb_ptr<effect_t> body;
        } e_for;
        struct
        {
            dumb_ptr<expr_t> cond;
            dumb_ptr<effect_t> true_branch, false_branch;
        } e_if;
        dumb_ptr<expr_t> e_sleep;        /* sleep time */
        dumb_ptr<const ScriptBuffer> e_script;
        struct
        {
            op_t *opp;
            int args_nr;
            int line_nr, column;
            dumb_ptr<expr_t> args[MAX_ARGS];
        } e_op;
        struct
        {
            std::vector<int> *formalv;
            dumb_ptr<std::vector<dumb_ptr<expr_t>>> actualvp;
            dumb_ptr<effect_t> body;
        } e_call;

        e0() { really_memzero_this(this); }
        ~e0() = default;
        e0(const e0&) = default;
        e0& operator = (const e0&) = default;
    } e;
    EFFECT ty;
};

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

struct component_t
{
    dumb_ptr<component_t> next;
    int item_id;
    int count;
};


struct effect_set_t
{
    dumb_ptr<effect_t> effect, at_trigger, at_end;
};

struct spellguard_t
{
    dumb_ptr<spellguard_t> next;
    union su
    {
        dumb_ptr<expr_t> s_condition;
        dumb_ptr<expr_t> s_mana;
        dumb_ptr<expr_t> s_casttime;
        dumb_ptr<component_t> s_components;
        dumb_ptr<component_t> s_catalysts;
        dumb_ptr<spellguard_t> s_alt;   /* either `next' or `s.s_alt' */
        effect_set_t s_effect;
        su() { really_memzero_this(this); }
        ~su() = default;
        su(const su&) = default;
        su& operator = (const su&) = default;
    } s;
    SPELLGUARD ty;
};

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

struct letdef_t
{
    int id;
    dumb_ptr<expr_t> expr;
};

struct spell_t
{
    FString name;
    FString invocation;
    SPELL_FLAG flags;
    int arg;
    SPELLARG spellarg_ty;

    std::vector<letdef_t> letdefv;

    dumb_ptr<spellguard_t> spellguard;
};

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

struct teleport_anchor_t
{
    FString name;
    FString invocation;
    dumb_ptr<expr_t> location;
};

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

struct magic_conf_t
{
    struct mcvar
    {
        FString name;
        val_t val;
    };
    // This should probably be done by a dedicated "intern pool" class
    std::vector<mcvar> varv;

    std::map<FString, dumb_ptr<spell_t>> spells_by_name, spells_by_invocation;

    std::map<FString, dumb_ptr<teleport_anchor_t>> anchors_by_name, anchors_by_invocation;
};

/* Execution environment */

// these are not an enum they're a nasty intern hack
#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;

struct env_t
{
    magic_conf_t *base_env;
    std::unique_ptr<val_t[]> varu;

    val_t& VAR(size_t i)
    {
        assert (varu);
        if (varu[i].ty == TYPE::UNDEF)
            return base_env->varv[i].val;
        else
            return varu[i];
    }

};

#define MAX_STACK_SIZE 32

struct cont_activation_record_t
{
    dumb_ptr<effect_t> return_location;
    union cu
    {
        struct
        {
            int id;
            TYPE ty;
            dumb_ptr<effect_t> body;
            dumb_ptr<std::vector<int>> entities_vp;
            int index;
        } c_foreach;
        struct
        {
            int id;
            dumb_ptr<effect_t> body;
            int current;
            int stop;
        } c_for;
        struct
        {
            int args_nr;
            int *formalap;
            dumb_ptr<val_t[]> old_actualpa;
        } c_proc;

        cu() { really_memzero_this(this); }
        ~cu() = default;
        cu(const cu&) = default;
        cu& operator = (const cu&) = default;
    } c;
    CONT_STACK ty;
};

struct status_change_ref_t
{
    StatusChange sc_type;
    int bl_id;
};

struct invocation : block_list
{
    dumb_ptr<invocation> next_invocation; /* used for spells directly associated with a caster: they form a singly-linked list */
    INVOCATION_FLAG flags;

    dumb_ptr<env_t> env;
    dumb_ptr<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 */

    Timer 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. */
    dumb_ptr<effect_t> current_effect;
    dumb_ptr<effect_t> trigger_effect;   /* If non-NULL, this is used to spawn a cloned effect based on the same environment */
    dumb_ptr<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 */
    std::vector<status_change_ref_t> status_change_refv;

};

inline dumb_ptr<invocation> block_list::as_spell() { return dumb_ptr<invocation>(static_cast<invocation *>(this)); }
inline dumb_ptr<invocation> block_list::is_spell() { return bl_type == BL::SPELL ? as_spell() : nullptr; }

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(dumb_ptr<component_t> *component_holder, int id, int count);

dumb_ptr<teleport_anchor_t> magic_find_anchor(XString name);

dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell,
        dumb_ptr<map_session_data> caster, int spellpower, XString param);

void magic_free_env(dumb_ptr<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(dumb_ptr<spell_t> spell,
        dumb_ptr<map_session_data> caster,
        dumb_ptr<env_t> env, int *near_miss);

dumb_ptr<invocation> spell_instantiate(effect_set_t *effect, dumb_ptr<env_t> env);

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

// 1 on failure
int spell_unbind(dumb_ptr<map_session_data> subject, dumb_ptr<invocation> invocation);

/**
 * Clones a spell to run the at_effect field
 */
dumb_ptr<invocation> spell_clone_effect(dumb_ptr<invocation> source);

dumb_ptr<spell_t> magic_find_spell(XString invocation);

/* The following is used only by the parser: */
struct args_rec_t
{
    dumb_ptr<std::vector<dumb_ptr<expr_t>>> argvp;
};

struct proc_t
{
    FString name;
    std::vector<int> argv;
    dumb_ptr<effect_t> body;

    proc_t()
    : name()
    , argv()
    , body()
    {}
};

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

#endif // MAGIC_INTERPRETER_HPP