/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
*
* Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
* Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
* Copyright (©) 2002 Mark Wedel & Crossfire Development Team
* Copyright (©) 1992 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
//+GPL
materialtype_t *materialt;
/*
materialtype material[NROFMATERIALS] = {
* P M F E C C A D W G P S P T F C D D C C G H B I *
* H A I L O O C R E H O L A U E A E E H O O O L N *
* Y G R E L N I A A O I O R R A N P A A U D L I T *
* S I E C D F D I P S S W A N R C L T O N Y N R *
* I C T U N O T O L E E H S T P D N *
{"paper", {15,10,17, 9, 5, 7,13, 0,20,15, 0,0,0,0,0,10,0,0,0,0,0,0,0,0}},
{"metal", { 2,12, 3,12, 2,10, 7, 0,20,15, 0,0,0,0,0,10,0,0,0,0,0,0,0,0}},
{"glass", {14,11, 8, 3,10, 5, 1, 0,20,15, 0,0,0,0,0, 0,0,0,0,0,0,0,0,0}},
{"leather", { 5,10,10, 3, 3,10,10, 0,20,15, 0,0,0,0,0,12,0,0,0,0,0,0,0,0}},
{"wood", {10,11,13, 2, 2,10, 9, 0,20,15, 0,0,0,0,0,12,0,0,0,0,0,0,0,0}},
{"organics", { 3,12, 9,11, 3,10, 9, 0,20,15, 0,0,0,0,0, 0,0,0,0,0,0,0,0,0}},
{"stone", { 2, 5, 2, 2, 2, 2, 1, 0,20,15, 0,0,0,0,0, 5,0,0,0,0,0,0,0,0}},
{"cloth", {14,11,13, 4, 4, 5,10, 0,20,15, 0,0,0,0,0, 5,0,0,0,0,0,0,0,0}},
{"adamant", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0, 0,0,0,0,0,0,0,0,0}},
{"liquid", { 0, 8, 9, 6,17, 0,15, 0,20,15,12,0,0,0,0,11,0,0,0,0,0,0,0,0}},
{"soft metal",{ 6,12, 6,14, 2,10, 1, 0,20,15, 0,0,0,0,0,10,0,0,0,0,0,0,0,0}},
{"bone", {10, 9, 4, 5, 3,10,10, 0,20,15, 0,0,0,0,0, 2,0,0,0,0,0,0,0,0}},
{"ice", {14,11,16, 5, 0, 5, 6, 0,20,15, 0,0,0,0,0, 7,0,0,0,0,0,0,0,0}}
};
*/
materialtype_t::materialtype_t ()
{
next = 0;
reset ();
}
void
materialtype_t::reset ()
{
name = shstr_unknown;
description = shstr_unknown_material_description;
material = 0;
for (int i = 0; i < NROFATTACKS; i++)
{
save [i] = 0;
mod [i] = 0;
}
chance = 0;
difficulty = 0;
magic = 0;
damage = 0;
wc = 0;
ac = 0;
sp = 0;
weight = 100;
value = 100;
density = 1000;
}
// create a new material of the given name
static materialtype_t *
dummy_material (shstr_tmp name)
{
materialtype_t *mt = new materialtype_t;
mt->name = name;
// make it susceptible to attacks
for (int i = 0; i < NROFATTACKS; i++)
{
mt->save [i] = 10;
mt->mod [i] = 9;
}
mt->next = materialt; materialt = mt;
return mt;
}
static materialtype_t *
find (const shstr_tmp name)
{
for (materialtype_t *mt = materialt; mt; mt = mt->next)
if (name == mt->name)
return mt;
return 0;
}
/* convert materialname to materialtype_t */
materialtype_t *
name_to_material (const shstr_tmp name)
{
materialtype_t *mt = find (name);
if (!mt)
{
LOG (llevError, "name_to_material called with nonexistent material '%s'\n", &name);
mt = dummy_material (name);
}
return mt;
}
void
object_thawer::get (materialtype_t *&mt) const
{
shstr name;
get (name);
mt = find (name);
if (!mt)
{
parse_error (format ("material called %s requested, but not found, creating dummy material.\n", &name));
mt = dummy_material (name);
}
}
/* 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)
{
if (!op->is_armor ())
return;
if (op->material == MATERIAL_NULL)
return;
if (op->material != change->material)
return;
materialtype_t *mt = op->material;
for (int 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
select_material (object *op, int difficulty)
{
if (op->material != MATERIAL_NULL || !op->materials)
return;
materialtype_t *lmt = 0;
//TODL: dead code?
for (materialtype_t *mt = materialt; mt; mt = mt->next)
if (op->materials & mt->material
&& difficulty >= mt->difficulty
&& rndm (1, 100) <= mt->chance
&& (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->material = lmt;
/* 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;
}
}
}
//-GPL
void
_reload_materials ()
{
object_thawer thawer (settings.datadir, "materials");
if (!thawer)
{
LOG (llevError, "unable to load %s for reading\n", thawer.name);
return;
}
while (thawer.kw != KW_name)
{
thawer.next ();
if (thawer.kw == KW_EOF)
return;
}
materialtype_t *mt;
for (;;)
{
switch (thawer.kw)
{
case KW_name:
coroapi::cede_to_tick ();
{
// create a new dummy material, or find the existing material
shstr name;
thawer.get (name);
mt = find (name);
if (mt)
mt->reset ();
else
{
mt = new materialtype_t;
mt->next = materialt; materialt = mt;
}
mt->name = name;
mt->description = 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:
return;
default:
if (!thawer.parse_error ("materials file"))
return;
break;
}
thawer.next ();
}
}