// Emacs style mode select   -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Cyril Deble 1998 (cyril.deble@inforoute.cgs.fr)
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
//      Doom internal dehacked file loader for amiga only :)
//      Currently only a few options supported
//
//-----------------------------------------------------------------------------

static const char
rcsid[] = "$Id: dehacked.c,v 0.2 1998/02/11 07:45:00 b1 Exp $";

#include <ctype.h>
#include <stdlib.h>

// Data.
#include "doomdef.h"
#include "sounds.h"
#include "m_fixed.h"

#ifdef __GNUG__
#pragma implementation "info.h"
#endif
#include "info.h"

#include "p_mobj.h"

#include "dehacked.h"


enum
{
  THING_ID = 0,
  THING_HIT_POINTS,
  THING_SPEED,
  THING_WIDTH,
  THING_HEIGHT,
  THING_MISSILE_DAMAGE,
  THING_REACTION_TIME,
  THING_PAIN_CHANCE,
  THING_MASS,
  THING_BITS,
  THING_ALERT_SOUND,
  THING_ATTACK_SOUND,
  THING_PAIN_SOUND,
  THING_DEATH_SOUND,
  THING_ACTION_SOUND,
  THING_INITIAL_FRAME,
  THING_FIRST_MOVING_FRAME,
  THING_INJURY_FRAME,
  THING_CLOSE_ATTACK_FRAME,
  THING_FAR_ATTACK_FRAME,
  THING_DEATH_FRAME,
  THING_EXPLODING_FRAME,
  THING_RESPAWN_FRAME,

  FRAME_SPRITE_NUMBER,
  FRAME_SPRITE_SUBNUMBER,
  FRAME_DURATION,
  FRAME_NEXT_FRAME,
  FRAME_ACTION_POINTER,
  FRAME_UNKNOWN_1,
  FRAME_UNKNOWN_2,

  NUM_KEYWORD
};


/* All keywords supported */
char *Keywords[] = {
/* Things */
"id # = ",                  /* mobjinfo.doomednum    */
"hit points = ",            /* mobjinfo.spawnhealth  */
"speed = ",                 /* mobjinfo.speed        */
"width = ",                 /* mobjinfo.radius       */
"height = ",                /* mobjinfo.height       */
"missile damage = ",        /* mobjinfo.damage       */
"reaction time = ",         /* mobjinfo.reactiontime */
"pain chance = ",           /* mobjinfo.painchance   */
"mass = ",                  /* mobjinfo.mass         */
"bits = ",                  /* mobjinfo.flags        */
"alert sound = ",           /* mobjinfo.seesound     */
"attack sound = ",          /* mobjinfo.attacksound  */
"pain sound = ",            /* mobjinfo.painsound    */
"death sound = ",           /* mobjinfo.deathsound   */
"action sound = ",          /* mobjinfo.activesound  */
"initial frame = ",         /* mobjinfo.spawnstate   */
"first moving frame = ",    /* mobjinfo.seestate     */
"injury frame = ",          /* mobjinfo.painstate    */
"close attack frame = ",    /* mobjinfo.meleestate   */
"far attack frame = ",      /* mobjinfo.missilestate */
"death frame = ",           /* mobjinfo.deathstate   */
"exploding frame = ",       /* mobjinfo.xdeathstate  */
"respawn frame = ",         /* mobjinfo.raisestate   */

/* Frame */

"sprite number = ",         /* states.sprite    */
"sprite subnumber = ",      /* states.frame     */
"duration = ",              /* states.tics      */
"next frame = ",            /* states.nextstate */
"#action pointer = ",       /* states.action    */
"unknown 1 = ",             /* states.misc1     */
"unknown 2 = ",             /* states.misc2     */

/* Others to follow :) */

"\n"                     /* The last              */
};


/* For future use */
/*
char *String_Bits[] = {
"Can be picked up",
"Obstacle",
"Shootable",
"Total invisibility",
"Can't be hit",
"Semi-deaf",
"In pain",
"Steps before attack",
"Hangs from ceiling",
"No gravity",
"Travels over cliffs",
"Picks up items",
"No clipping",
"Slides along walls",
"Floating",
"Semi-no clipping",
"Projectiles",
"Disappearing Weapon",
"Partial invisibilty",
"Puffs (vs. bleeds)",
"Sliding helpless",
"No auto-leveling",
"Affects Kill %",
"Affects Item %",
"Running",
"Not in deathmatch",
"Color 1",
"Color 2",
"Unused",
"Unused",
"Unused",
"Unused",
"\n"
};
*/

/* Backup of action pointer */
actionf_t actions[NUMSTATES];

int
DE_Search(char *arg, char **list)
{
  int i, l;

  /* Make into lower case, and get length of string */
  for (l = 0; *(arg + l); l++)
    *(arg + l) = tolower(*(arg + l));
  /*printf("arg = '%s'\n", arg);*/

  for (i = 0; **(list + i) != '\n'; i++) {
    /*printf("arg = '%s' list = '%s'\n", arg, *(list + i));*/
    if (strstr(arg,*(list + i)))
        return(i);
  }
  return(-1);
}


int
DE_Hack( char * line)
{
    static int thing = 0;
    static int frame = 0;
    int choice;
    char * arg;

    /* scanf variables */
    int n1;
    char buf1[255];

    /* first check for main keywords */
    if(sscanf(line, "Thing %d (%s)", &n1, buf1) == 2)
    {
         thing = n1-1;
         printf("-> Changing Thing %d (%s\n", n1, buf1);
         return(1);
    }

    if(sscanf(line, "Frame %d", &n1) == 1)
    {
         frame = n1;
         printf("-> Changing Frame %d\n", n1);
         return(1);
    }

    if(frame >= NUMSTATES) return(0);

    /* search for option */
    choice = DE_Search(line, Keywords);

    if(choice < 0 || choice > NUM_KEYWORD-1) return(0);

    arg = strstr(line, Keywords[choice]) +
          strlen(Keywords[choice]);

    /*printf("Choice = %d, Arg = %s\n", choice, arg);*/

    switch(choice)
    {
      case THING_ID:
          mobjinfo[thing].doomednum = atoi(arg);
          break;
      case THING_HIT_POINTS:
          mobjinfo[thing].spawnhealth = atoi(arg);
          break;
      case THING_SPEED:
          mobjinfo[thing].speed = atoi(arg);
          break;
      case THING_WIDTH:
          mobjinfo[thing].radius = atoi(arg);
          break;
      case THING_HEIGHT:
          mobjinfo[thing].height = atoi(arg);
          break;
      case THING_MISSILE_DAMAGE:
          mobjinfo[thing].damage = atoi(arg);
          break;
      case THING_REACTION_TIME:
          mobjinfo[thing].reactiontime = atoi(arg);
          break;
      case THING_PAIN_CHANCE:
          mobjinfo[thing].painchance = atoi(arg);
          break;
      case THING_MASS:
          mobjinfo[thing].mass = atoi(arg);
          break;
      case THING_BITS:
          mobjinfo[thing].flags = atoi(arg);
          break;
      case THING_ALERT_SOUND:
          mobjinfo[thing].seesound = atoi(arg);
          break;
      case THING_ATTACK_SOUND:
          mobjinfo[thing].attacksound = atoi(arg);
          break;
      case THING_PAIN_SOUND:
          mobjinfo[thing].painsound = atoi(arg);
          break;
      case THING_DEATH_SOUND:
          mobjinfo[thing].deathsound = atoi(arg);
          break;
      case THING_ACTION_SOUND:
          mobjinfo[thing].activesound = atoi(arg);
          break;
      case THING_INITIAL_FRAME:
          mobjinfo[thing].spawnstate = atoi(arg);
          break;
      case THING_FIRST_MOVING_FRAME:
          mobjinfo[thing].seestate = atoi(arg);
          break;
      case THING_INJURY_FRAME:
          mobjinfo[thing].painstate = atoi(arg);
          break;
      case THING_CLOSE_ATTACK_FRAME:
          mobjinfo[thing].meleestate = atoi(arg);
          break;
      case THING_FAR_ATTACK_FRAME:
          mobjinfo[thing].missilestate = atoi(arg);
          break;
      case THING_DEATH_FRAME:
          mobjinfo[thing].deathstate = atoi(arg);
          break;
      case THING_EXPLODING_FRAME:
          mobjinfo[thing].xdeathstate = atoi(arg);
          break;
      case THING_RESPAWN_FRAME:
          mobjinfo[thing].raisestate = atoi(arg);
          break;
      case FRAME_SPRITE_NUMBER:
          states[frame].sprite = atoi(arg);
          break;
      case FRAME_SPRITE_SUBNUMBER:
          states[frame].frame = atoi(arg);
          break;
      case FRAME_DURATION:
          states[frame].tics = atoi(arg);
          break;
      case FRAME_NEXT_FRAME:
          states[frame].nextstate = atoi(arg);
          break;
      case FRAME_ACTION_POINTER:
          states[frame].action = actions[atoi(arg)-1];
          break;
      case FRAME_UNKNOWN_1:
          states[frame].misc1 = atoi(arg);
          break;
      case FRAME_UNKNOWN_2:
          states[frame].misc2 = atoi(arg);
          break;

      default:
        return(0);
    }

    printf("   - %s\n", line);

    return(1);
}


void
DE_AddDeh(char * name)
{
  FILE *fp;
  char text[255];
  int numline = 0;

  printf("DE_AddDeh: Adding %s\n", name);

  if(fp = fopen(name,"r"))
  {
    int i;

    /* Backup all action pointer */
    for(i=0;i<NUMSTATES;i++)
        actions[i] = states[i].action;

    /* Start parsing the file */
    while(fgets(text, 255, fp))
    {
        text[strlen(text)-1] = '\0';

        numline++;
        if(text[0] == '#') continue;
        if(text[0] == '\n') continue;

        /* Do the hack */
        if(DE_Hack(text) == 0)
        {
           /*printf("DEH ERROR: file '%s', line %d, text '%s'\n",
                   name, numline, text);*/
        }
    }

    fclose(fp);
  }
}
