/* ************************************************************************
*  file: force.c     Implementation of core magic         Part of Copper3 *
*  Usage : Very, very carefully...                                        *
*  Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
************************************************************************* */

#include CONFIG

#include <stdio.h>
#include <strings.h>
#include <ctype.h>

#include "structs.h"
#include "comm.h"
#include "utils.h"
#include "magic.h"
#include "error.h"
#include "proto.h"

/*
#######################################################################
This is a tricky file... it seems once timing is understood, it'll fall
together...how should PERM IMBUE STR differ from IMBUE PERM STR???
#######################################################################
*/

/* For new "core" magic system -
 *
 * This is intended to be entirely private, hence the structures and
 * defines are declared internal to this file, with only the prototypes
 * of the functions to be declared, in proto.h and the ATTRIB_* values
 * (in magic.h??)
 *
 * Part of the aim is to have, at least vaguely, object-oriented magic.
 * This should be easier to graft onto diku than other fundamental
 * changes, since the magic system is mostly independent already from
 * the rest of the code.
 *
 * Spells, or other magical effects, should interface to these routines
 * like this:
 *
 * struct magic *m;
 * int error;
 *
 * if((error=create_magic(<creator of the magic>,&m))!=OKAY) *note ptr to ptr*
 *    return(error);
 *
 * if((error=bind_magic_to_object(m,object))!=OKAY)
 *    return(error);
 * * Perhaps the magic could, on failure, revert to the "caster" *
 * *             if(object<>caster) bind_magic_to_object(m,caster);...
 *
 * * a_to_m does return an error code, but we can ignore it here *
 * attribute_to_magic(m,ATTRIB_VISIBILITY,-5);
 * attribute_to_magic(m,ATTRIB_ODOR,+30);
 *
 * * If the magic is triggered later on, do not call this *
 * expend_magic(m);
 */

/* #define ATTRIB_ define these elsewhere... */

struct attrib {
    int type;
    int value;
    struct attrib *next;
};

/* Magic flags */

#define MAGIC_LOCAL       1 /* Not sure what I meant by this */
#define MAGIC_WAIT        2 /* Delay the application of the attributes */
#define MAGIC_DIFFUSE     4 /* Not identifiable to the source, but will */
                            /* appear in the region near the source */
#define MAGIC_INHERENT    8 /* Something part of the object - not to be */
                            /* dispelled without dispelling the object */
                            /* itself...(don't use this one lightly) */

struct magic {
    struct attrib *attribs;
    struct generic target;
    int label;
    int flags;
    int power;
    int entire_period;    /* Do these make sense? */
    int period_remaining;
    struct magic *next;
};


int create_magic(struct generic *initiator,struct magic **m)
{
    CREATE((*m),struct magic,1);

    switch(initiator->attach_type) {
	case ATTACH_OBJ:
/*            (*m)->power = initiator->attached_to.obj->power; / * (range?);*/
            break;
	case ATTACH_CHAR:
/*            (*m)->power = initiator->attached_to.char->power; / * (range?);*/
            break;
	case ATTACH_ROOM:
/*            (*m)->power = initiator->attached_to.room->power; / * (range?);*/
            break;

        default:
            free(*m);
            return ERROR_INTERNAL;
            break;
    }
    /*TEMP TEMP TEMP*/
    (*m)->power = 30; /*COMPLETELY ARBITRARY VALUE */
    return OKAY;
}

int bind_magic_to_object(struct magic *m, struct generic *target)
{
    if(!m||!target)
        return ERROR_INTERNAL;

    if(number(1,100) > power_over_object(m,target))
        return ERROR_FAILED;

    /* whole structure copy */
    m->target= *target;

    switch(target->attach_type) {
	case ATTACH_ROOM:
            m->next = target->attached_to.room->magic;
            target->attached_to.room->magic = m;
	    break;
	case ATTACH_OBJ:
            m->next = target->attached_to.obj->magic;
            target->attached_to.obj->magic = m;
	    break;
	case ATTACH_CHAR:
            m->next = target->attached_to.ch->magic;
            target->attached_to.ch->magic = m;
	    break;
	default:
	    return ERROR_INTERNAL;
	    break;
    }
    return OKAY;
}

int attribute_to_magic(struct magic *m,int attribute,int value)
{
    struct attrib *a;

    for(a=m->attribs;a;a=a->next)
        if(a->type==attribute) {
            if(a->value==value)
                return OKAY;
            else
                return ERROR_NO_SENSE;
        }

    CREATE(a,struct attrib,1);

    a->type=attribute;
    a->value=value;
    a->next=m->attribs;
    m->attribs=a;
    return OKAY;
}

int query_attribute(struct magic *m,int attribute)
{
    struct attrib *a;

    for(a=m->attribs;a;a=a->next)
        if(a->type==attribute)
            return(a->value);

    return(ERROR_INTERNAL); /* Not a valid place to return ERROR_*... */
}

/* return a percentage of "normal" force that can be exerted on the object*/
int power_over_object(struct magic *m, struct generic *target)
{
    int percent = 100;

    switch(target->attach_type) {
	case ATTACH_ROOM: /* Previous spells? */
            break;
	case ATTACH_OBJ: /* Previous spells? */
            break;
	case ATTACH_CHAR: /* Check magic resistance, level, int/wis */
            break;
        default:
            return(ERROR_INTERNAL); /* Again, bad place for an error */
            break;
    }
    return(percent);
}


int expend_magic(struct magic *m,struct generic *target)
{
    struct attrib *a;
    int imbue=ATTRIB_DIR_SELF; /* A handy default value */
    int duration=0; /* not too handy, but better than random dust */

    for(a=m->attribs;a;a=a->next) {
        switch(a->type) {
            case ATTRIB_NULL: /* nop it */
            case ATTRIB_ORIGIN_T:
            case ATTRIB_ORIGIN_ID:
                break;
            case ATTRIB_STR:
            case ATTRIB_INT:
            case ATTRIB_WIS:
            case ATTRIB_DEX:
            case ATTRIB_CON:
            case ATTRIB_CHR:
                /* This is a key part,  how to do it? 
                attrib_attach(m->target,a->type,a->value,imbue); *****/
                break;
            case ATTRIB_IMBUE:
                imbue=a->value;
                break;
            case ATTRIB_PERMANENT:
                duration=-1;
                break;
            default:
                log("BUG: Bad attribute type in expend_magic");
                break;
        }
    }
    return OKAY;
}

int magical_attack(struct magic *m,struct generic *target)
{
    return OKAY;
}

/* This seems silly - if someone needs to loop, let them loop in this file
int next_attribute(struct magic *m,last)
{
}***/

int remove_magic(struct magic *m)
{
    struct magic *i,**head;
    struct attrib *a;

    switch(m->target.attach_type) {
	case TARGET_ROOM:
            head= &(m->target.attached_to.room->magic);
            break;
	case TARGET_OBJ:
            head= &(m->target.attached_to.obj->magic);
            break;
	case TARGET_CHAR:
            head= &(m->target.attached_to.ch->magic);
            break;
        default:
            return ERROR_INTERNAL;
            break;
    }

    /* Check to see if it's the head of the list */
    if(*head==m) {
        *head = m->next;

    } else {
        /* Get to here, and we have to walk through the list */
        i=*head;
        while(i) {
            if(i->next == m) {
                i->next = m->next;
                break;
            }
            i=i->next;
        }
        if(!i) {
            log("BUG: Bad attachment of magic, remove_magic()");
            return ERROR_INTERNAL;
        }
    }

    while(m->attribs) {
	a = m->attribs->next;
	free(m->attribs);
	m->attribs = a;
    }

    free(m);

    return OKAY;
}