/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
*
* Copyright (©) 2005,2006,2007,2008,2009,2010,2011 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
*/
/*
* compatibility functions for older (GPL) source code parts
*/
#include
#include
#include
#include
#include
#include
#include "define.h"
#include "path.h"
/* buf_overflow() - we don't want to exceed the buffer size of
* buf1 by adding on buf2! Returns true if overflow will occur.
*/
int
buf_overflow (const char *buf1, const char *buf2, int bufsize)
{
int len1 = 0, len2 = 0;
if (buf1)
len1 = strlen (buf1);
if (buf2)
len2 = strlen (buf2);
if ((len1 + len2) >= bufsize)
return 1;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
/*
* The random functions here take luck into account when rolling random
* dice or numbers. This function has less of an impact the larger the
* difference becomes in the random numbers. IE, the effect is lessened
* on a 1-1000 roll, vs a 1-6 roll. This can be used by crafty programmers,
* to specifically disable luck in certain rolls, simply by making the
* numbers larger (ie, 1d1000 > 500 vs 1d6 > 3)
*/
/*
* Roll a random number between min and max. Uses op to determine luck,
* and if goodbad is non-zero, luck increases the roll, if zero, it decreases.
* Generally, op should be the player/caster/hitter requesting the roll,
* not the recipient (ie, the poor slob getting hit). [garbled 20010916]
*/
int
random_roll (int r_min, int r_max, const object *op, bool prefer_high)
{
if (r_min > r_max)
swap (r_min, r_max);
int range = r_max - r_min + 1;
int num = rndm (r_min, r_max);
if (op->stats.luck)
{
int base = range > 2 ? 20 : 50; /* d2 and d3 are corner cases */
if (rndm (base) < min (10, abs (op->stats.luck)))
{
// we have a winner, increase/decrease number by one accordingly
int adjust = sign (op->stats.luck);
if (!prefer_high)
adjust = -adjust;
num = clamp (num + adjust, r_min, r_max);
}
}
return num;
}
/*
* This is a 64 bit version of random_roll above. This is needed
* for exp loss calculations for players changing religions.
*/
sint64
random_roll64 (sint64 r_min, sint64 r_max, const object *op, bool prefer_high)
{
if (r_min > r_max)
swap (r_min, r_max);
sint64 range = r_max - r_min + 1;
/*
* Make a call to get two 32 bit unsigned random numbers, and just do
* a little bitshifting.
*/
sint64 num = rndm.next () ^ (sint64 (rndm.next ()) << 31);
num = num % range + r_min;
if (op->stats.luck)
{
int base = range > 2 ? 20 : 50; /* d2 and d3 are corner cases */
if (rndm (base) < min (10, abs (op->stats.luck)))
{
// we have a winner, increase/decrease number by one accordingly
int adjust = sign (op->stats.luck);
if (!prefer_high)
adjust = -adjust;
num = clamp (num + adjust, r_min, r_max);
}
}
return num;
}
/*
* Roll a number of dice (2d3, 4d6). Uses op to determine luck,
* If goodbad is non-zero, luck increases the roll, if zero, it decreases.
* Generally, op should be the player/caster/hitter requesting the roll,
* not the recipient (ie, the poor slob getting hit).
* The args are num D size (ie 4d6) [garbled 20010916]
*/
int
die_roll (int num, int size, const object *op, bool prefer_high)
{
int min_roll, luck, total, i, gotlucky;
int diff = size;
min_roll = 1;
luck = total = gotlucky = 0;
int base = diff > 2 ? 20 : 50; /* d2 and d3 are corner cases */
if (size < 2 || diff < 1)
{
LOG (llevError | logBacktrace, "Calling die_roll with num=%d size=%d\n", num, size);
return num; /* avoids a float exception */
}
if (op->type == PLAYER)
luck = op->stats.luck;
for (i = 0; i < num; i++)
{
if (rndm (base) < min (10, abs (luck)) && !gotlucky)
{
/* we have a winner */
gotlucky++;
((luck > 0) ? (luck = 1) : (luck = -1));
diff -= luck;
if (diff < 1)
return (num); /*check again */
((prefer_high) ? (min_roll += luck) : (diff));
total += max (1, min (size, rndm (diff) + min_roll));
}
else
total += rndm (size) + 1;
}
return total;
}
/////////////////////////////////////////////////////////////////////////////
#ifndef PATH_MAX
# define PATH_MAX 8192
#endif
char *
path_combine (const char *src, const char *dst)
{
char *p;
static char path[PATH_MAX];
if (*dst == '/')
{
/* absolute destination path => ignore source path */
strcpy (path, dst);
}
else
{
/* relative destination path => add after last '/' of source */
strcpy (path, src);
p = strrchr (path, '/');
if (p)
p++;
else
{
p = path;
if (*src == '/')
*p++ = '/';
}
strcpy (p, dst);
}
return path;
}
static void
path_normalize (char *path)
{
char *p; /* points to the beginning of the path not yet processed; this is
either a path component or a path separator character */
char *q; /* points to the end of the path component p points to */
char *w; /* points to the end of the already normalized path; w <= p is
maintained */
size_t len; /* length of current component (which p points to) */
p = path;
w = p;
while (*p != '\0')
{
if (*p == '/')
{
if ((w == path && *path == '/') || (w > path && w[-1] != '/'))
*w++ = '/';
p++;
continue;
}
q = strchr (p, '/');
if (q == NULL)
q = p + strlen (p);
len = q - p;
assert (len > 0);
if (len == 1 && *p == '.')
{
/* remove current component */
}
else if (len == 2 && memcmp (p, "..", 2) == 0)
{
if (w == path || (w == path + 3 && memcmp (path, "../", 3) == 0))
{
/* keep ".." at beginning of relative path ("../x" => "../x") */
memmove (w, p, len);
w += len;
}
else if (w == path + 1 && *path == '/')
{
/* remove ".." at beginning of absolute path ("/../x" => "/x") */
}
else
{
/* remove both current component ".." and preceding one */
if (w > path && w[-1] == '/')
w--;
while (w > path && w[-1] != '/')
w--;
}
}
else
{
/* normal component ==> add it */
memmove (w, p, len);
w += len;
}
p = q;
}
/* remove trailing slashes, but keep the one at the start of the path */
while (w > path + 1 && w[-1] == '/')
w--;
*w = '\0';
}
char *
path_combine_and_normalize (const char *src, const char *dst)
{
char *path;
path = path_combine (src, dst);
path_normalize (path);
return (path);
}
#define EOL_SIZE (sizeof("\n")-1)
void
strip_endline (char *buf)
{
if (*buf && buf [strlen (buf) - 1] == '\n')
buf [strlen (buf) - 1] = '\0';
}
/**
* Replace in string src all occurrences of key by replacement. The resulting
* string is put into result; at most resultsize characters (including the
* terminating null character) will be written to result.
*/
void
replace (const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
{
size_t resultlen;
size_t keylen;
/* special case to prevent infinite loop if key==replacement=="" */
if (strcmp (key, replacement) == 0)
{
snprintf (result, resultsize, "%s", src);
return;
}
keylen = strlen (key);
resultlen = 0;
while (*src != '\0' && resultlen + 1 < resultsize)
{
if (strncmp (src, key, keylen) == 0)
{
snprintf (result + resultlen, resultsize - resultlen, "%s", replacement);
resultlen += strlen (result + resultlen);
src += keylen;
}
else
{
result[resultlen++] = *src++;
}
}
result[resultlen] = '\0';
}