Loading...
/*

 - - = = = The Shrine of Shoggoth = = = - -
Copyright (C) 2010-2011  Thomas Glyn Dennis.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qqqArchive.h"
#include "qqqClass.h"
#include "qqqGraphics.h"
#include "csv/csv.h"

/* [INTERNAL] Maximum possible number of classes. */

#define QQQ_MAX_CLASSES 64

/* [INTERNAL] Class list. */

long qqq_class_count = 0;

qqqClass *qqq_class[QQQ_MAX_CLASSES];

/* [INTERNAL] Register a new class. */

qqqClass *classRegister (qqqBehave think, const char *name, const char *mesh)
{

  qqqClass *clss = NULL;

  /* Ensure that this is a valid name. */

  if      (qqq_class_count >= QQQ_MAX_CLASSES ) { return NULL; }
  else if (classFind (name)                   ) { return NULL; }
  else if (!name                              ) { return NULL; }
  else if (strlen (name)   >= QQQ_MAXCLASSNAME) { return NULL; }

  /* Allocate memory for the new class. */

  qqq_class[qqq_class_count] = (qqqClass*)malloc (sizeof (qqqClass));

  if (!qqq_class[qqq_class_count]) { return NULL; }

  /* Resize the actor class list. */

  clss = qqq_class[qqq_class_count];

  qqq_class_count++;

  /* Initialise it. */

  strcpy (clss->name, name);

  clss->behave = think;

  /* Load mesh, generate animations and load textures. */

  clss->mesh = morphLoadFile (mesh);

  if (!clss->mesh)
  {

    long          len   = 0;
    unsigned char *data = NULL;

    data = archiveMalloc (mesh, &len);
    clss->mesh = morphLoadBuffer (len, data);
    if (data) { free (data); }

  }

  clss->anim = animGenerateMorphList (clss->mesh);

  clss->mtrl = NULL;
  gfxLoadClassMaterials (clss);

  /* Success. */

  return clss;

}

/* [PUBLIC] Load a list of classes from a file. */

long classLoad (const char *file_name)
{

  qqqBehave think = QQQ_BEHAVE_DEFAULT;

  CsvTable *list = NULL;

  long count = 0;
  long i     = 0;

  /* Load class definition file. */

  list = csvLoadFile (file_name, ',', '"');

  if (!list)
  {

    long          len   = 0;
    unsigned char *data = NULL;

    data = archiveMalloc (file_name, &len);
    list = csvLoadBuffer (len, data, ',', '"');
    if (data) { free (data); }

  }

  if (!list) { return 0; }

  if (list->width < 3)
  {

    csvFree (list);

    return 0;

  }

  /* Load classes. */

  count = 0;

  for (i = 0; i < list->height; i++)
  {

    if (list->cell[0][i])
    {

      /* Determine class type. */

      if      (strcmp (list->cell[0][i], "PLAYER") == 0)
      { think = QQQ_BEHAVE_PLAYER; }
      else if (strcmp (list->cell[0][i], "GHOST" ) == 0)
      { think = QQQ_BEHAVE_GHOST; }
      else
      { think = QQQ_BEHAVE_DEFAULT; }

      /* Register class. */

      if (!classRegister (think, list->cell[1][i], list->cell[2][i]))
      {

        /* TODO: Log an error here. */

      } else { count++; }

    }

  }

  /* Free list. */

  csvFree (list);

  /* Return the number of classes registered. */

  return count;

}

/* [PUBLIC] Free the class list. */

void classClear (void)
{

  int i = 0;

  /* Loop through the class list. */

  for (i = 0; i < qqq_class_count; i++)
  {

    if (qqq_class[i])
    {

      /* Free materials. */

      gfxFreeClassMaterials (qqq_class[i]);

      /* Free mesh anims. */

      animFreeList (qqq_class[i]->anim);

      /* Free mesh. */

      morphFree (qqq_class[i]->mesh);

      /* Free the class structure. */

      free (qqq_class[i]);

    }

  }

  /* Reset the class counter. */

  qqq_class_count = 0;

}

/* [PUBLIC] Find a class by its name and return a pointer to it if it exists. */

qqqClass *classFind (const char *name)
{

  long i = 0;

  if (!name) { return NULL; }

  /* Loop through the actor class list, searching for a matching class name. */

  for (i = 0; i < qqq_class_count; i++)
  {

    if (qqq_class[i])
    {

      if (strcmp (qqq_class[i]->name, name) == 0) { return qqq_class[i]; }

    }

  }

  /* No match was found. */

  return NULL;

}