forked from github/server
Merge branch 'develop'
This commit is contained in:
commit
75aff73e9a
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="cerddor">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#cerddor" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_roqf" level="11" />
|
|
||||||
</spellbook>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="draig">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#draig" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_firesword" level="12" />
|
|
||||||
<entry spell="create_trollbelt" level="9" />
|
|
||||||
</spellbook>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="gray">
|
|
||||||
<entry spell="create_runesword" level="6" />
|
|
||||||
<entry spell="create_chastitybelt" level="7" />
|
|
||||||
<entry spell="create_focus" level="9" />
|
|
||||||
<entry spell="create_ror" level="9" />
|
|
||||||
</spellbook>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="gwyrrd">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#gwyrrd" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_magicherbbag" level="5" />
|
|
||||||
</spellbook>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="illaun">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#illaun" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_dreameye" level="14" />
|
|
||||||
<entry spell="create_invisibility_sphere" level="13" />
|
|
||||||
</spellbook>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="tybied">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#tybied" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_antimagic" level="7" />
|
|
||||||
<entry spell="create_rop" level="9" />
|
|
||||||
<entry spell="create_bagofholding" level="10" />
|
|
||||||
</spellbook>
|
|
|
@ -46,7 +46,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
static int read_seenspells(variant *var, void *owner, struct gamedata *data)
|
static int read_seenspells(variant *var, void *owner, struct gamedata *data)
|
||||||
{
|
{
|
||||||
selist *ql;
|
selist *ql = NULL;
|
||||||
storage *store = data->store;
|
storage *store = data->store;
|
||||||
spell *sp = 0;
|
spell *sp = 0;
|
||||||
char token[32];
|
char token[32];
|
||||||
|
|
18
src/battle.c
18
src/battle.c
|
@ -1539,6 +1539,17 @@ static int get_tactics(const side * as, const side * ds)
|
||||||
return result - defense;
|
return result - defense;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double tactics_chance(const unit *u, int skilldiff) {
|
||||||
|
double tacch = 0.1 * skilldiff;
|
||||||
|
if (fval(u->region->terrain, SEA_REGION)) {
|
||||||
|
const ship *sh = u->ship;
|
||||||
|
if (sh) {
|
||||||
|
tacch *= sh->type->tac_bonus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tacch;
|
||||||
|
}
|
||||||
|
|
||||||
static troop select_opponent(battle * b, troop at, int mindist, int maxdist)
|
static troop select_opponent(battle * b, troop at, int mindist, int maxdist)
|
||||||
{
|
{
|
||||||
fighter *af = at.fighter;
|
fighter *af = at.fighter;
|
||||||
|
@ -1560,12 +1571,7 @@ static troop select_opponent(battle * b, troop at, int mindist, int maxdist)
|
||||||
|
|
||||||
/* percentage chance to get this attack */
|
/* percentage chance to get this attack */
|
||||||
if (tactics > 0) {
|
if (tactics > 0) {
|
||||||
double tacch = 0.1 * tactics;
|
double tacch = tactics_chance(af->unit, tactics);
|
||||||
if (fval(b->region->terrain, SEA_REGION)) {
|
|
||||||
ship *sh = at.fighter->unit->ship;
|
|
||||||
if (sh)
|
|
||||||
tacch *= sh->type->tac_bonus;
|
|
||||||
}
|
|
||||||
if (!chance(tacch)) {
|
if (!chance(tacch)) {
|
||||||
dt.fighter = NULL;
|
dt.fighter = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,6 +270,7 @@ extern "C" {
|
||||||
const char *sidename(const struct side * s);
|
const char *sidename(const struct side * s);
|
||||||
void battle_message_faction(struct battle * b, struct faction * f, struct message *m);
|
void battle_message_faction(struct battle * b, struct faction * f, struct message *m);
|
||||||
|
|
||||||
|
double tactics_chance(const struct unit *u, int skilldiff);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <kernel/item.h>
|
#include <kernel/item.h>
|
||||||
#include <kernel/race.h>
|
#include <kernel/race.h>
|
||||||
#include <kernel/region.h>
|
#include <kernel/region.h>
|
||||||
|
#include <kernel/ship.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
|
|
||||||
#include <spells/buildingcurse.h>
|
#include <spells/buildingcurse.h>
|
||||||
|
@ -665,6 +666,22 @@ static void test_drain_exp(CuTest *tc)
|
||||||
test_teardown();
|
test_teardown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_tactics_chance(CuTest *tc) {
|
||||||
|
unit *u;
|
||||||
|
ship_type *stype;
|
||||||
|
|
||||||
|
test_setup();
|
||||||
|
u = test_create_unit(test_create_faction(NULL), test_create_ocean(0, 0));
|
||||||
|
CuAssertDblEquals(tc, 0.1, tactics_chance(u, 1), 0.01);
|
||||||
|
CuAssertDblEquals(tc, 0.3, tactics_chance(u, 3), 0.01);
|
||||||
|
stype = test_create_shiptype("brot");
|
||||||
|
u->ship = test_create_ship(u->region, stype);
|
||||||
|
CuAssertDblEquals(tc, 0.2, tactics_chance(u, 2), 0.01);
|
||||||
|
stype->tac_bonus = 2.0;
|
||||||
|
CuAssertDblEquals(tc, 0.4, tactics_chance(u, 2), 0.01);
|
||||||
|
test_teardown();
|
||||||
|
}
|
||||||
|
|
||||||
CuSuite *get_battle_suite(void)
|
CuSuite *get_battle_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
|
@ -681,6 +698,7 @@ CuSuite *get_battle_suite(void)
|
||||||
SUITE_ADD_TEST(suite, test_natural_armor);
|
SUITE_ADD_TEST(suite, test_natural_armor);
|
||||||
SUITE_ADD_TEST(suite, test_magic_resistance);
|
SUITE_ADD_TEST(suite, test_magic_resistance);
|
||||||
SUITE_ADD_TEST(suite, test_projectile_armor);
|
SUITE_ADD_TEST(suite, test_projectile_armor);
|
||||||
|
SUITE_ADD_TEST(suite, test_tactics_chance);
|
||||||
DISABLE_TEST(suite, test_drain_exp);
|
DISABLE_TEST(suite, test_drain_exp);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ order_data *db_driver_order_load(int id)
|
||||||
order_data * od = NULL;
|
order_data * od = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
ERRNO_CHECK();
|
||||||
if (g_order_tx_size > 0) {
|
if (g_order_tx_size > 0) {
|
||||||
g_order_tx_size = 0;
|
g_order_tx_size = 0;
|
||||||
err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL);
|
err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL);
|
||||||
|
@ -45,10 +46,12 @@ order_data *db_driver_order_load(int id)
|
||||||
assert(bytes > 0);
|
assert(bytes > 0);
|
||||||
text = sqlite3_column_text(g_stmt_select, 0);
|
text = sqlite3_column_text(g_stmt_select, 0);
|
||||||
odata_create(&od, 1+(size_t)bytes, (const char *)text);
|
odata_create(&od, 1+(size_t)bytes, (const char *)text);
|
||||||
|
ERRNO_CHECK();
|
||||||
return od;
|
return od;
|
||||||
}
|
}
|
||||||
} while (err == SQLITE_ROW);
|
} while (err == SQLITE_ROW);
|
||||||
assert(err == SQLITE_DONE);
|
assert(err == SQLITE_DONE);
|
||||||
|
ERRNO_CHECK();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +62,8 @@ int db_driver_order_save(order_data *od)
|
||||||
|
|
||||||
assert(od && od->_str);
|
assert(od && od->_str);
|
||||||
|
|
||||||
|
ERRNO_CHECK();
|
||||||
|
|
||||||
if (g_order_batchsize > 0) {
|
if (g_order_batchsize > 0) {
|
||||||
if (g_order_tx_size == 0) {
|
if (g_order_tx_size == 0) {
|
||||||
err = sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
err = sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||||
|
@ -82,7 +87,7 @@ int db_driver_order_save(order_data *od)
|
||||||
g_order_tx_size = 0;
|
g_order_tx_size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ERRNO_CHECK();
|
||||||
return (int)id;
|
return (int)id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +96,7 @@ void db_driver_open(void)
|
||||||
int err;
|
int err;
|
||||||
const char *dbname;
|
const char *dbname;
|
||||||
|
|
||||||
|
ERRNO_CHECK();
|
||||||
g_order_batchsize = config_get_int("game.dbbatch", 100);
|
g_order_batchsize = config_get_int("game.dbbatch", 100);
|
||||||
dbname = config_get("game.dbname");
|
dbname = config_get("game.dbname");
|
||||||
if (!dbname) {
|
if (!dbname) {
|
||||||
|
@ -108,16 +114,20 @@ void db_driver_open(void)
|
||||||
assert(err == SQLITE_OK);
|
assert(err == SQLITE_OK);
|
||||||
err = sqlite3_prepare_v2(g_db, "SELECT data FROM orders WHERE id = ?", -1, &g_stmt_select, NULL);
|
err = sqlite3_prepare_v2(g_db, "SELECT data FROM orders WHERE id = ?", -1, &g_stmt_select, NULL);
|
||||||
assert(err == SQLITE_OK);
|
assert(err == SQLITE_OK);
|
||||||
|
ERRNO_CHECK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void db_driver_close(void)
|
void db_driver_close(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
ERRNO_CHECK();
|
||||||
err = sqlite3_finalize(g_stmt_select);
|
err = sqlite3_finalize(g_stmt_select);
|
||||||
assert(err == SQLITE_OK);
|
assert(err == SQLITE_OK);
|
||||||
err = sqlite3_finalize(g_stmt_insert);
|
err = sqlite3_finalize(g_stmt_insert);
|
||||||
assert(err == SQLITE_OK);
|
assert(err == SQLITE_OK);
|
||||||
err = sqlite3_close(g_db);
|
err = sqlite3_close(g_db);
|
||||||
assert(err == SQLITE_OK);
|
assert(err == SQLITE_OK);
|
||||||
|
ERRNO_CHECK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,7 @@ ship_type *st_get_or_create(const char * name) {
|
||||||
st = (ship_type *)calloc(sizeof(ship_type), 1);
|
st = (ship_type *)calloc(sizeof(ship_type), 1);
|
||||||
st->_name = str_strdup(name);
|
st->_name = str_strdup(name);
|
||||||
st->storm = 1.0;
|
st->storm = 1.0;
|
||||||
|
st->tac_bonus = 1.0;
|
||||||
st_register(st);
|
st_register(st);
|
||||||
}
|
}
|
||||||
return st;
|
return st;
|
||||||
|
|
|
@ -36,6 +36,8 @@ extern "C" {
|
||||||
#define SFL_NOCOAST 0x04
|
#define SFL_NOCOAST 0x04
|
||||||
#define SFL_SPEEDY 0x08
|
#define SFL_SPEEDY 0x08
|
||||||
|
|
||||||
|
#define SFL_DEFAULT 0
|
||||||
|
|
||||||
typedef struct ship_type {
|
typedef struct ship_type {
|
||||||
char *_name;
|
char *_name;
|
||||||
|
|
||||||
|
@ -57,7 +59,7 @@ extern "C" {
|
||||||
|
|
||||||
int at_bonus; /* Ver<65>ndert den Angriffsskill (default: 0) */
|
int at_bonus; /* Ver<65>ndert den Angriffsskill (default: 0) */
|
||||||
int df_bonus; /* Ver<65>ndert den Verteidigungskill (default: 0) */
|
int df_bonus; /* Ver<65>ndert den Verteidigungskill (default: 0) */
|
||||||
float tac_bonus;
|
double tac_bonus;
|
||||||
|
|
||||||
struct terrain_type ** coasts; /* coast that this ship can land on */
|
struct terrain_type ** coasts; /* coast that this ship can land on */
|
||||||
|
|
||||||
|
|
|
@ -369,7 +369,7 @@ static void test_stype_defaults(CuTest *tc) {
|
||||||
CuAssertPtrEquals(tc, 0, stype->coasts);
|
CuAssertPtrEquals(tc, 0, stype->coasts);
|
||||||
CuAssertDblEquals(tc, 0.0, stype->damage, 0.0);
|
CuAssertDblEquals(tc, 0.0, stype->damage, 0.0);
|
||||||
CuAssertDblEquals(tc, 1.0, stype->storm, 0.0);
|
CuAssertDblEquals(tc, 1.0, stype->storm, 0.0);
|
||||||
CuAssertDblEquals(tc, 0.0, stype->tac_bonus, 0.0);
|
CuAssertDblEquals(tc, 1.0, stype->tac_bonus, 0.01);
|
||||||
CuAssertIntEquals(tc, 0, stype->cabins);
|
CuAssertIntEquals(tc, 0, stype->cabins);
|
||||||
CuAssertIntEquals(tc, 0, stype->cargo);
|
CuAssertIntEquals(tc, 0, stype->cargo);
|
||||||
CuAssertIntEquals(tc, 0, stype->combat);
|
CuAssertIntEquals(tc, 0, stype->combat);
|
||||||
|
|
22
src/report.c
22
src/report.c
|
@ -96,7 +96,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
/* libc includes */
|
/* libc includes */
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -111,17 +110,6 @@ extern int *storms;
|
||||||
extern int weeks_per_month;
|
extern int weeks_per_month;
|
||||||
extern int months_per_year;
|
extern int months_per_year;
|
||||||
|
|
||||||
static void check_errno(const char * file, int line) {
|
|
||||||
if (errno) {
|
|
||||||
char zText[64];
|
|
||||||
sprintf(zText, "error %d during report at %s:%d", errno, file, line);
|
|
||||||
perror(zText);
|
|
||||||
errno = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHECK_ERRNO() check_errno(__FILE__, __LINE__)
|
|
||||||
|
|
||||||
static char *gamedate_season(const struct locale *lang)
|
static char *gamedate_season(const struct locale *lang)
|
||||||
{
|
{
|
||||||
static char buf[256]; /* FIXME: static return value */
|
static char buf[256]; /* FIXME: static return value */
|
||||||
|
@ -2195,7 +2183,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = 0;
|
ch = 0;
|
||||||
CHECK_ERRNO();
|
ERRNO_CHECK();
|
||||||
for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem;
|
for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem;
|
||||||
a = a->next) {
|
a = a->next) {
|
||||||
const item_type *itype = (const item_type *)a->data.v;
|
const item_type *itype = (const item_type *)a->data.v;
|
||||||
|
@ -2245,7 +2233,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newline(out);
|
newline(out);
|
||||||
CHECK_ERRNO();
|
ERRNO_CHECK();
|
||||||
centre(out, LOC(f->locale, "nr_alliances"), false);
|
centre(out, LOC(f->locale, "nr_alliances"), false);
|
||||||
newline(out);
|
newline(out);
|
||||||
|
|
||||||
|
@ -2253,7 +2241,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
||||||
|
|
||||||
rpline(out);
|
rpline(out);
|
||||||
|
|
||||||
CHECK_ERRNO();
|
ERRNO_CHECK();
|
||||||
anyunits = 0;
|
anyunits = 0;
|
||||||
|
|
||||||
for (r = ctx->first; r != ctx->last; r = r->next) {
|
for (r = ctx->first; r != ctx->last; r = r->next) {
|
||||||
|
@ -2367,7 +2355,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
||||||
|
|
||||||
newline(out);
|
newline(out);
|
||||||
rpline(out);
|
rpline(out);
|
||||||
CHECK_ERRNO();
|
ERRNO_CHECK();
|
||||||
}
|
}
|
||||||
if (!is_monsters(f)) {
|
if (!is_monsters(f)) {
|
||||||
if (!anyunits) {
|
if (!anyunits) {
|
||||||
|
@ -2379,7 +2367,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fstream_done(&strm);
|
fstream_done(&strm);
|
||||||
CHECK_ERRNO();
|
ERRNO_CHECK();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,14 @@ without prior permission by the authors of Eressea.
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
void errno_check(const char * file, int line) {
|
||||||
|
if (errno) {
|
||||||
|
log_info("errno is %d (%s) at %s:%d",
|
||||||
|
errno, strerror(errno), file, line);
|
||||||
|
errno = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef STDIO_CP
|
#ifdef STDIO_CP
|
||||||
static int stdio_codepage = STDIO_CP;
|
static int stdio_codepage = STDIO_CP;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -28,12 +28,16 @@ extern "C" {
|
||||||
int log_level(struct log_t *log, int flags);
|
int log_level(struct log_t *log, int flags);
|
||||||
void log_close(void);
|
void log_close(void);
|
||||||
|
|
||||||
extern void log_fatal(const char *format, ...);
|
void log_fatal(const char *format, ...);
|
||||||
extern void log_error(const char *format, ...);
|
void log_error(const char *format, ...);
|
||||||
extern void log_warning(const char *format, ...);
|
void log_warning(const char *format, ...);
|
||||||
extern void log_debug(const char *format, ...);
|
void log_debug(const char *format, ...);
|
||||||
extern void log_info(const char *format, ...);
|
void log_info(const char *format, ...);
|
||||||
extern void log_printf(FILE * ios, const char *format, ...);
|
void log_printf(FILE * ios, const char *format, ...);
|
||||||
|
|
||||||
|
void errno_check(const char *file, int line);
|
||||||
|
#define ERRNO_CHECK() errno_check(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
|
||||||
#define LOG_CPERROR 0x01
|
#define LOG_CPERROR 0x01
|
||||||
#define LOG_CPWARNING 0x02
|
#define LOG_CPWARNING 0x02
|
||||||
|
|
|
@ -448,14 +448,19 @@ static int parse_ships(xmlDocPtr doc)
|
||||||
|
|
||||||
for (child = node->children; child; child = child->next) {
|
for (child = node->children; child; child = child->next) {
|
||||||
if (strcmp((const char *)child->name, "modifier") == 0) {
|
if (strcmp((const char *)child->name, "modifier") == 0) {
|
||||||
double value = xml_fvalue(child, "value", 0.0);
|
|
||||||
propValue = xmlGetProp(child, BAD_CAST "type");
|
propValue = xmlGetProp(child, BAD_CAST "type");
|
||||||
if (strcmp((const char *)propValue, "tactics") == 0)
|
if (strcmp((const char *)propValue, "tactics") == 0) {
|
||||||
st->tac_bonus = (float)value;
|
st->tac_bonus = xml_fvalue(child, "factor", 1.0);
|
||||||
else if (strcmp((const char *)propValue, "attack") == 0)
|
}
|
||||||
|
else {
|
||||||
|
int value = xml_ivalue(child, "value", 0);
|
||||||
|
if (strcmp((const char *)propValue, "attack") == 0) {
|
||||||
st->at_bonus = (int)value;
|
st->at_bonus = (int)value;
|
||||||
else if (strcmp((const char *)propValue, "defense") == 0)
|
}
|
||||||
|
else if (strcmp((const char *)propValue, "defense") == 0) {
|
||||||
st->df_bonus = (int)value;
|
st->df_bonus = (int)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
xmlFree(propValue);
|
xmlFree(propValue);
|
||||||
}
|
}
|
||||||
else if (strcmp((const char *)child->name, "construction") == 0) {
|
else if (strcmp((const char *)child->name, "construction") == 0) {
|
||||||
|
|
Loading…
Reference in New Issue