/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
*
* Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
* Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
* Copyright (©) 1992,2007 Frank Tore Johansen
*
* Deliantra is free software: you can redistribute it and/or modify it under
* the terms of the Affero 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 Affero GNU General Public License
* and the GNU General Public License along with this program. If not, see
* .
*
* The authors can be reached via e-mail to
*/
#include
#include
/* convert materialname to materialtype_t */
materialtype_t *
name_to_material (const shstr_cmp name)
{
for (materialtype_t *mt = materialt; mt; mt = mt->next)
if (name == mt->name)
return mt;
return 0;
}
/* when doing transmutation of objects, we have to recheck the resistances,
* as some that did not apply previously, may apply now.
*/
void
transmute_materialname (object *op, const object *change)
{
materialtype_t *mt;
int j;
if (!op->materialname)
return;
if (op->materialname != change->materialname)
return;
if (!op->is_armor ())
return;
mt = name_to_material (op->materialname);
if (!mt)
{
LOG (llevError, "archetype '%s>%s' uses nonexistent material '%s'\n", &op->arch->archname, &op->name, &op->materialname);
return;
}
for (j = 0; j < NROFATTACKS; j++)
if (op->resist[j] == 0 && change->resist[j] != 0)
{
op->resist[j] += mt->mod[j];
if (op->resist[j] > 100)
op->resist[j] = 100;
if (op->resist[j] < -100)
op->resist[j] = -100;
}
}
/* set the materialname and type for an item */
void
set_materialname (object *op, int difficulty, materialtype_t *nmt)
{
materialtype_t *mt, *lmt;
if (!op->materialname)
return;
if (nmt)
lmt = nmt;
else
{
lmt = 0;
for (mt = materialt; mt; mt = mt->next)
if (op->materials & mt->material && rndm (1, 100) <= mt->chance &&
difficulty >= mt->difficulty && (op->magic >= mt->magic || mt->magic == 0))
{
lmt = mt;
if (!(op->is_weapon () || op->is_armor ()))
break;
}
}
if (lmt)
{
if (op->stats.dam && op->is_weapon ())
{
op->stats.dam += lmt->damage;
if (op->stats.dam < 1)
op->stats.dam = 1;
}
if (op->stats.sp && op->type == BOW)
op->stats.sp += lmt->sp;
if (op->stats.wc && op->is_weapon ())
op->stats.wc += lmt->wc;
if (op->is_armor ())
{
if (op->stats.ac)
op->stats.ac += lmt->ac;
for (int j = 0; j < NROFATTACKS; j++)
if (op->resist[j] != 0)
{
op->resist[j] += lmt->mod[j];
if (op->resist[j] > 100)
op->resist[j] = 100;
if (op->resist[j] < -100)
op->resist[j] = -100;
}
}
op->materialname = lmt->name;
/* dont make it unstackable if it doesn't need to be */
if (op->is_weapon () || op->is_armor ())
{
op->weight = (op->weight * lmt->weight) / 100;
op->value = (op->value * lmt->value) / 100;
}
}
}
//TODO: make this a constructor
static materialtype_t *
get_empty_mat (void)
{
materialtype_t *mt;
int i;
mt = new materialtype_t;
mt->name = shstr_unknown;
mt->description = 0;
for (i = 0; i < NROFATTACKS; i++)
{
mt->save[i] = 0;
mt->mod[i] = 0;
}
mt->chance = 0;
mt->difficulty = 0;
mt->magic = 0;
mt->damage = 0;
mt->wc = 0;
mt->ac = 0;
mt->sp = 0;
mt->weight = 100;
mt->value = 100;
mt->density = 1;
mt->next = 0;
return mt;
}
void
load_materials (void)
{
char filename[MAX_BUF];
sprintf (filename, "%s/materials", settings.datadir);
LOG (llevDebug, "Reading material type data from %s...\n", filename);
//TODO: somehow free old materials, or update them in-place
materialt = 0;
object_thawer thawer (filename);
if (!thawer)
{
LOG (llevError, "Cannot open %s for reading\n", filename);
goto done;
}
while (thawer.kw != KW_name)
{
thawer.next ();
if (thawer.kw == KW_EOF)
goto done;
}
materialtype_t *mt;
for (;;)
{
switch (thawer.kw)
{
case KW_name:
mt = get_empty_mat ();
mt->next = materialt;
materialt = mt;
thawer.get (mt->name);
mt->description = mt->name;
break;
case KW_description:
thawer.get (mt->description);
break;
case KW_material:
thawer.get (mt->material);
break;
case KW_saves:
{
const char *cp = thawer.get_str () - 1;
for (int i = 0; i < NROFATTACKS; i++)
{
if (!cp)
{
mt->save[i] = 0;
continue;
}
int value;
++cp;
sscanf (cp, "%d", &value);
mt->save[i] = (sint8) value;
cp = strchr (cp, ',');
}
}
break;
case KW_mods:
{
const char *cp = thawer.get_str () - 1;
for (int i = 0; i < NROFATTACKS; i++)
{
if (!cp)
{
mt->save[i] = 0;
continue;
}
++cp;
int value;
sscanf (cp, "%d", &value);
mt->mod[i] = (sint8) value;
cp = strchr (cp, ',');
}
}
break;
case KW_chance: thawer.get (mt->chance); break;
case KW_difficulty: // cf+ alias, not original cf
case KW_diff: thawer.get (mt->difficulty); break;
case KW_magic: thawer.get (mt->magic); break;
case KW_dam: // cf+ alias, not original cf
case KW_damage: thawer.get (mt->damage); break;
case KW_wc: thawer.get (mt->wc); break;
case KW_ac: thawer.get (mt->ac); break;
case KW_sp: thawer.get (mt->sp); break;
case KW_weight: thawer.get (mt->weight); break;
case KW_value: thawer.get (mt->value); break;
case KW_density: thawer.get (mt->density); break;
case KW_EOF:
goto done;
default:
if (!thawer.parse_error ("materials file", "materials"))
goto done;
break;
}
thawer.next ();
}
done:
if (!materialt)
materialt = get_empty_mat ();
LOG (llevDebug, "Done.\n");
}