Merge branch 'NetHack-3.6'
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.1 $ $NHDT-Date: 1557569075 2019/05/11 10:04:35 $
|
$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.3 $ $NHDT-Date: 1558045586 2019/05/16 22:26:26 $
|
||||||
|
|
||||||
This fixes36.3 file is here to capture information about updates in the 3.6.x
|
This fixes36.3 file is here to capture information about updates in the 3.6.x
|
||||||
lineage following the release of 3.6.2 in May 2019. Please note, however,
|
lineage following the release of 3.6.2 in May 2019. Please note, however,
|
||||||
@@ -11,6 +11,10 @@ when place_object() puts a non-boulder on the map at a spot which contains
|
|||||||
other objects, put it under all boulders in the pile rather than just
|
other objects, put it under all boulders in the pile rather than just
|
||||||
under the top one; previously, map wasn't showing a boulder there if
|
under the top one; previously, map wasn't showing a boulder there if
|
||||||
the top one got moved by means other than pushing
|
the top one got moved by means other than pushing
|
||||||
|
when examining the map with '/' or ';', picking a symbol which is used for
|
||||||
|
more than 4 things yielded a sentence lacking its terminating period
|
||||||
|
billing and payment issue as a result of glob coalescing
|
||||||
|
glob pricing did not consider weight properly
|
||||||
|
|
||||||
|
|
||||||
Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository
|
Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository
|
||||||
|
|||||||
@@ -2265,6 +2265,8 @@ E boolean FDECL(block_door, (XCHAR_P, XCHAR_P));
|
|||||||
E boolean FDECL(block_entry, (XCHAR_P, XCHAR_P));
|
E boolean FDECL(block_entry, (XCHAR_P, XCHAR_P));
|
||||||
E char *FDECL(shk_your, (char *, struct obj *));
|
E char *FDECL(shk_your, (char *, struct obj *));
|
||||||
E char *FDECL(Shk_Your, (char *, struct obj *));
|
E char *FDECL(Shk_Your, (char *, struct obj *));
|
||||||
|
E void FDECL(globby_bill_fixup, (struct obj *, struct obj *));
|
||||||
|
E void FDECL(globby_donation, (struct obj *, struct obj *));
|
||||||
|
|
||||||
/* ### shknam.c ### */
|
/* ### shknam.c ### */
|
||||||
|
|
||||||
|
|||||||
@@ -715,7 +715,8 @@ struct obj **potmp, **pobj;
|
|||||||
otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
|
otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
|
||||||
/ (otmp->quan + obj->quan);
|
/ (otmp->quan + obj->quan);
|
||||||
|
|
||||||
otmp->quan += obj->quan;
|
if (!otmp->globby)
|
||||||
|
otmp->quan += obj->quan;
|
||||||
/* temporary special case for gold objects!!!! */
|
/* temporary special case for gold objects!!!! */
|
||||||
if (otmp->oclass == COIN_CLASS)
|
if (otmp->oclass == COIN_CLASS)
|
||||||
otmp->owt = weight(otmp), otmp->bknown = 0;
|
otmp->owt = weight(otmp), otmp->bknown = 0;
|
||||||
|
|||||||
11
src/mkobj.c
11
src/mkobj.c
@@ -2755,6 +2755,10 @@ struct obj **obj1, **obj2;
|
|||||||
otmp1 = *obj1;
|
otmp1 = *obj1;
|
||||||
otmp2 = *obj2;
|
otmp2 = *obj2;
|
||||||
if (otmp1 && otmp2 && otmp1 != otmp2) {
|
if (otmp1 && otmp2 && otmp1 != otmp2) {
|
||||||
|
if (otmp1->unpaid || otmp2->unpaid)
|
||||||
|
globby_bill_fixup(otmp1, otmp2);
|
||||||
|
else if (costly_spot(otmp1->ox, otmp1->oy))
|
||||||
|
globby_donation(otmp1, otmp2);
|
||||||
if (otmp1->bknown != otmp2->bknown)
|
if (otmp1->bknown != otmp2->bknown)
|
||||||
otmp1->bknown = otmp2->bknown = 0;
|
otmp1->bknown = otmp2->bknown = 0;
|
||||||
if (otmp1->rknown != otmp2->rknown)
|
if (otmp1->rknown != otmp2->rknown)
|
||||||
@@ -2837,7 +2841,12 @@ struct obj *otmp2;
|
|||||||
* they'll be out of our view (minvent or container)
|
* they'll be out of our view (minvent or container)
|
||||||
* so don't actually show anything */
|
* so don't actually show anything */
|
||||||
} else if (onfloor || inpack) {
|
} else if (onfloor || inpack) {
|
||||||
pline("The %s coalesce%s.", makeplural(obj_typename(otmp->otyp)),
|
boolean adj = ((otmp->ox != u.ux || otmp->oy != u.uy) &&
|
||||||
|
(otmp2->ox != u.ux || otmp2->oy != u.uy));
|
||||||
|
|
||||||
|
pline("The %s%s coalesce%s.",
|
||||||
|
(onfloor && adj) ? "adjacent " : "",
|
||||||
|
makeplural(obj_typename(otmp->otyp)),
|
||||||
inpack ? " inside your pack" : "");
|
inpack ? " inside your pack" : "");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
18
src/objnam.c
18
src/objnam.c
@@ -25,6 +25,7 @@ STATIC_DCL boolean FDECL(singplur_lookup, (char *, char *, BOOLEAN_P,
|
|||||||
STATIC_DCL char *FDECL(singplur_compound, (char *));
|
STATIC_DCL char *FDECL(singplur_compound, (char *));
|
||||||
STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned));
|
STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned));
|
||||||
STATIC_DCL boolean FDECL(badman, (const char *, BOOLEAN_P));
|
STATIC_DCL boolean FDECL(badman, (const char *, BOOLEAN_P));
|
||||||
|
STATIC_DCL char *FDECL(globwt, (struct obj *, char *));
|
||||||
|
|
||||||
struct Jitem {
|
struct Jitem {
|
||||||
int item;
|
int item;
|
||||||
@@ -1214,11 +1215,12 @@ unsigned doname_flags;
|
|||||||
} else if (with_price) { /* on floor or in container on floor */
|
} else if (with_price) { /* on floor or in container on floor */
|
||||||
int nochrg = 0;
|
int nochrg = 0;
|
||||||
long price = get_cost_of_shop_item(obj, &nochrg);
|
long price = get_cost_of_shop_item(obj, &nochrg);
|
||||||
|
char globbuf[BUFSZ];
|
||||||
|
|
||||||
if (price > 0L)
|
if (price > 0L)
|
||||||
Sprintf(eos(bp), " (%s, %ld %s)",
|
Sprintf(eos(bp), " (%s, %s%ld %s)",
|
||||||
nochrg ? "contents" : "for sale",
|
nochrg ? "contents" : "for sale",
|
||||||
price, currency(price));
|
globwt(obj, globbuf), price, currency(price));
|
||||||
else if (nochrg > 0)
|
else if (nochrg > 0)
|
||||||
Strcat(bp, " (no charge)");
|
Strcat(bp, " (no charge)");
|
||||||
}
|
}
|
||||||
@@ -4195,4 +4197,16 @@ const char *lastR;
|
|||||||
return qbuf;
|
return qbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC_OVL char *
|
||||||
|
globwt(otmp, buf)
|
||||||
|
struct obj *otmp;
|
||||||
|
char *buf;
|
||||||
|
{
|
||||||
|
if (otmp && buf && otmp->globby && otmp->quan == 1L) {
|
||||||
|
Sprintf(buf, "%ld aum, ", otmp->owt);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
/*objnam.c*/
|
/*objnam.c*/
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* NetHack 3.6 pager.c $NHDT-Date: 1555627307 2019/04/18 22:41:47 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.151 $ */
|
/* NetHack 3.6 pager.c $NHDT-Date: 1558045586 2019/05/16 22:26:26 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.153 $ */
|
||||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/*-Copyright (c) Robert Patrick Rankin, 2018. */
|
/*-Copyright (c) Robert Patrick Rankin, 2018. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
@@ -1042,7 +1042,10 @@ struct permonst **for_supplement;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (found > 4)
|
if (found > 4)
|
||||||
Sprintf(out_str, "%s", "That can be many things");
|
/* 3.6.3: this used to be "That can be many things" (without prefix)
|
||||||
|
which turned it into a sentence that lacked its terminating period;
|
||||||
|
we could add one below but reinstating the prefix here is better */
|
||||||
|
Sprintf(out_str, "%scan be many things", prefix);
|
||||||
|
|
||||||
didlook:
|
didlook:
|
||||||
if (looked) {
|
if (looked) {
|
||||||
|
|||||||
163
src/shk.c
163
src/shk.c
@@ -74,6 +74,7 @@ STATIC_DCL void FDECL(deserted_shop, (char *));
|
|||||||
STATIC_DCL boolean FDECL(special_stock, (struct obj *, struct monst *,
|
STATIC_DCL boolean FDECL(special_stock, (struct obj *, struct monst *,
|
||||||
BOOLEAN_P));
|
BOOLEAN_P));
|
||||||
STATIC_DCL const char *FDECL(cad, (BOOLEAN_P));
|
STATIC_DCL const char *FDECL(cad, (BOOLEAN_P));
|
||||||
|
STATIC_DCL long FDECL(get_pricing_units, (struct obj *obj));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
|
invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
|
||||||
@@ -2009,14 +2010,34 @@ int *nochrg; /* alternate return value: 1: no charge, 0: shop owned, */
|
|||||||
items on freespot are implicitly 'no charge' */
|
items on freespot are implicitly 'no charge' */
|
||||||
*nochrg = (top->where == OBJ_FLOOR && (obj->no_charge || freespot));
|
*nochrg = (top->where == OBJ_FLOOR && (obj->no_charge || freespot));
|
||||||
|
|
||||||
if (carried(top) ? (int) obj->unpaid : !*nochrg)
|
if (carried(top) ? (int) obj->unpaid : !*nochrg) {
|
||||||
cost = obj->quan * get_cost(obj, shkp);
|
long per_unit_cost = get_cost(obj, shkp);
|
||||||
|
|
||||||
|
cost = get_pricing_units(obj) * per_unit_cost;
|
||||||
|
}
|
||||||
if (Has_contents(obj) && !freespot)
|
if (Has_contents(obj) && !freespot)
|
||||||
cost += contained_cost(obj, shkp, 0L, FALSE, TRUE);
|
cost += contained_cost(obj, shkp, 0L, FALSE, TRUE);
|
||||||
}
|
}
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC_OVL long
|
||||||
|
get_pricing_units(obj)
|
||||||
|
struct obj *obj;
|
||||||
|
{
|
||||||
|
long units = obj->quan;
|
||||||
|
|
||||||
|
if (obj->globby) {
|
||||||
|
/* globs must be sold by weight not by volume */
|
||||||
|
int unit_weight = (int) objects[obj->otyp].oc_weight,
|
||||||
|
wt = (obj->owt > 0) ? obj->owt : weight(obj);
|
||||||
|
|
||||||
|
if (unit_weight)
|
||||||
|
units = wt / unit_weight;
|
||||||
|
}
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
|
||||||
/* decide whether to apply a surcharge (or hypothetically, a discount) to obj
|
/* decide whether to apply a surcharge (or hypothetically, a discount) to obj
|
||||||
if it had ID number 'oid'; returns 1: increase, 0: normal, -1: decrease */
|
if it had ID number 'oid'; returns 1: increase, 0: normal, -1: decrease */
|
||||||
int
|
int
|
||||||
@@ -2185,7 +2206,7 @@ boolean unpaid_only;
|
|||||||
items on freespot are implicitly 'no charge' */
|
items on freespot are implicitly 'no charge' */
|
||||||
if (on_floor ? (!otmp->no_charge && !freespot)
|
if (on_floor ? (!otmp->no_charge && !freespot)
|
||||||
: (otmp->unpaid || !unpaid_only))
|
: (otmp->unpaid || !unpaid_only))
|
||||||
price += get_cost(otmp, shkp) * otmp->quan;
|
price += get_cost(otmp, shkp) * get_pricing_units(otmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Has_contents(otmp))
|
if (Has_contents(otmp))
|
||||||
@@ -2298,7 +2319,9 @@ set_cost(obj, shkp)
|
|||||||
register struct obj *obj;
|
register struct obj *obj;
|
||||||
register struct monst *shkp;
|
register struct monst *shkp;
|
||||||
{
|
{
|
||||||
long tmp = getprice(obj, TRUE) * obj->quan, multiplier = 1L, divisor = 1L;
|
long tmp, unit_price = getprice(obj, TRUE), multiplier = 1L, divisor = 1L;
|
||||||
|
|
||||||
|
tmp = get_pricing_units(obj) * unit_price;
|
||||||
|
|
||||||
if (uarmh && uarmh->otyp == DUNCE_CAP)
|
if (uarmh && uarmh->otyp == DUNCE_CAP)
|
||||||
divisor *= 3L;
|
divisor *= 3L;
|
||||||
@@ -2474,6 +2497,9 @@ struct monst *shkp;
|
|||||||
} else
|
} else
|
||||||
bp->useup = 0;
|
bp->useup = 0;
|
||||||
bp->price = get_cost(obj, shkp);
|
bp->price = get_cost(obj, shkp);
|
||||||
|
if (obj->globby)
|
||||||
|
/* for globs, the amt charged for quan 1 depends on owt */
|
||||||
|
bp->price *= get_pricing_units(obj);
|
||||||
eshkp->billct++;
|
eshkp->billct++;
|
||||||
obj->unpaid = 1;
|
obj->unpaid = 1;
|
||||||
}
|
}
|
||||||
@@ -2615,9 +2641,11 @@ boolean ininv, dummy, silent;
|
|||||||
ltmp = cltmp = gltmp = 0L;
|
ltmp = cltmp = gltmp = 0L;
|
||||||
container = Has_contents(obj);
|
container = Has_contents(obj);
|
||||||
|
|
||||||
if (!obj->no_charge)
|
if (!obj->no_charge) {
|
||||||
ltmp = get_cost(obj, shkp);
|
ltmp = get_cost(obj, shkp);
|
||||||
|
if (obj->globby)
|
||||||
|
ltmp *= get_pricing_units(obj);
|
||||||
|
}
|
||||||
if (obj->no_charge && !container) {
|
if (obj->no_charge && !container) {
|
||||||
obj->no_charge = 0;
|
obj->no_charge = 0;
|
||||||
return;
|
return;
|
||||||
@@ -2845,7 +2873,7 @@ boolean ininv;
|
|||||||
if (billamt)
|
if (billamt)
|
||||||
price += billamt;
|
price += billamt;
|
||||||
else if (ininv ? otmp->unpaid : !otmp->no_charge)
|
else if (ininv ? otmp->unpaid : !otmp->no_charge)
|
||||||
price += otmp->quan * get_cost(otmp, shkp);
|
price += get_pricing_units(otmp) * get_cost(otmp, shkp);
|
||||||
|
|
||||||
if (Has_contents(otmp))
|
if (Has_contents(otmp))
|
||||||
price = stolen_container(otmp, shkp, price, ininv);
|
price = stolen_container(otmp, shkp, price, ininv);
|
||||||
@@ -2892,7 +2920,7 @@ boolean peaceful, silent;
|
|||||||
if (billamt)
|
if (billamt)
|
||||||
value += billamt;
|
value += billamt;
|
||||||
else if (!obj->no_charge)
|
else if (!obj->no_charge)
|
||||||
value += obj->quan * get_cost(obj, shkp);
|
value += get_pricing_units(obj) * get_cost(obj, shkp);
|
||||||
|
|
||||||
if (Has_contents(obj)) {
|
if (Has_contents(obj)) {
|
||||||
boolean ininv =
|
boolean ininv =
|
||||||
@@ -4264,6 +4292,8 @@ register struct obj *first_obj;
|
|||||||
contentsonly = !cost;
|
contentsonly = !cost;
|
||||||
if (Has_contents(otmp))
|
if (Has_contents(otmp))
|
||||||
cost += contained_cost(otmp, shkp, 0L, FALSE, FALSE);
|
cost += contained_cost(otmp, shkp, 0L, FALSE, FALSE);
|
||||||
|
if (otmp->globby)
|
||||||
|
cost *= get_pricing_units(otmp); /* always quan 1, vary by wt */
|
||||||
if (!cost) {
|
if (!cost) {
|
||||||
Strcpy(price, "no charge");
|
Strcpy(price, "no charge");
|
||||||
contentsonly = FALSE;
|
contentsonly = FALSE;
|
||||||
@@ -4757,4 +4787,121 @@ sasc_bug(struct obj *op, unsigned x)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When one glob is absorbed by another glob, the two become
|
||||||
|
* become indistinguishable and the remaining glob grows in
|
||||||
|
* mass, the product of both.
|
||||||
|
*
|
||||||
|
* The original billed item is lost to the absorption and the
|
||||||
|
* original billed amount for the object being absorbed gets
|
||||||
|
* added to the cost owing for the absorber, and the separate
|
||||||
|
* cost for the absorbed object goes away.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
globby_bill_fixup(obj_absorber, obj_absorbed)
|
||||||
|
struct obj *obj_absorber, *obj_absorbed;
|
||||||
|
{
|
||||||
|
struct bill_x *bp, *bp_absorber = (struct bill_x *) 0;
|
||||||
|
struct monst *shkp = 0;
|
||||||
|
|
||||||
|
if (!obj_absorber->globby)
|
||||||
|
impossible("globby_bill_fixup called for non-globby object");
|
||||||
|
|
||||||
|
if (obj_absorber->unpaid) {
|
||||||
|
/* look for a shopkeeper who owns this object */
|
||||||
|
for (shkp = next_shkp(fmon, TRUE); shkp;
|
||||||
|
shkp = next_shkp(shkp->nmon, TRUE))
|
||||||
|
if (onbill(obj_absorber, shkp, TRUE))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* sanity check, in case obj is on bill but not marked 'unpaid' */
|
||||||
|
if (!shkp)
|
||||||
|
shkp = shop_keeper(*u.ushops);
|
||||||
|
|
||||||
|
if ((bp_absorber = onbill(obj_absorber, shkp, FALSE)) != 0) {
|
||||||
|
bp = onbill(obj_absorbed, shkp, FALSE);
|
||||||
|
if (bp) {
|
||||||
|
bp_absorber->price += bp->price;
|
||||||
|
ESHK(shkp)->billct--;
|
||||||
|
#ifdef DUMB
|
||||||
|
{
|
||||||
|
/* DRS/NS 2.2.6 messes up -- Peter Kendell */
|
||||||
|
int indx = ESHK(shkp)->billct;
|
||||||
|
|
||||||
|
*bp = ESHK(shkp)->bill_p[indx];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
*bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
|
||||||
|
#endif
|
||||||
|
clear_unpaid_obj(shkp, obj_absorbed);
|
||||||
|
} else {
|
||||||
|
/* should never happen */
|
||||||
|
bp_absorber->price += get_cost(obj_absorbed, shkp)
|
||||||
|
* get_pricing_units(obj_absorbed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The caller is about to make obj_absorbed go away.
|
||||||
|
*
|
||||||
|
* There's no way for you (or a shopkeeper) to prevent globs
|
||||||
|
* from merging with each other on the floor due to the
|
||||||
|
* inherent nature of globs so it irretrievably becomes part
|
||||||
|
* of the floor glob mass.
|
||||||
|
*
|
||||||
|
* globby_donation() needs to handle whether/how to
|
||||||
|
* compensate you for that.
|
||||||
|
*
|
||||||
|
* unpaid globs don't end up here.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
globby_donation(obj_absorber, obj_absorbed)
|
||||||
|
struct obj *obj_absorber, *obj_absorbed;
|
||||||
|
{
|
||||||
|
if (obj_absorber->where == OBJ_FLOOR
|
||||||
|
&& costly_spot(obj_absorber->ox, obj_absorber->oy)) {
|
||||||
|
int x = obj_absorber->ox, y = obj_absorber->oy;
|
||||||
|
char *o_shop = in_rooms(x, y, SHOPBASE);
|
||||||
|
struct monst *shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
|
||||||
|
struct eshk *eshkp = ESHK(shkp);
|
||||||
|
long amount, per_unit_cost = get_cost(obj_absorbed, shkp);
|
||||||
|
|
||||||
|
if (saleable(shkp, obj_absorbed)) {
|
||||||
|
amount = get_pricing_units(obj_absorbed) * per_unit_cost;
|
||||||
|
if (eshkp->debit >= amount) {
|
||||||
|
if (eshkp->loan) { /* you carry shop's gold */
|
||||||
|
if (eshkp->loan >= amount)
|
||||||
|
eshkp->loan -= amount;
|
||||||
|
else
|
||||||
|
eshkp->loan = 0L;
|
||||||
|
}
|
||||||
|
eshkp->debit -= amount;
|
||||||
|
pline_The("donated %s %spays off your debt.",
|
||||||
|
obj_typename(obj_absorbed->otyp),
|
||||||
|
eshkp->debit ? "partially " : "");
|
||||||
|
} else {
|
||||||
|
long delta = amount - eshkp->debit;
|
||||||
|
|
||||||
|
eshkp->credit += delta;
|
||||||
|
if (eshkp->debit) {
|
||||||
|
eshkp->debit = 0L;
|
||||||
|
eshkp->loan = 0L;
|
||||||
|
Your("debt is paid off.");
|
||||||
|
}
|
||||||
|
if (eshkp->credit == delta)
|
||||||
|
pline_The("%s established %ld %s credit.",
|
||||||
|
obj_typename(obj_absorbed->otyp),
|
||||||
|
delta, currency(delta));
|
||||||
|
else
|
||||||
|
pline_The("%s added %ld %s %s %ld %s.",
|
||||||
|
obj_typename(obj_absorbed->otyp),
|
||||||
|
delta, currency(delta),
|
||||||
|
"to your credit; total is now",
|
||||||
|
eshkp->credit, currency(eshkp->credit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*shk.c*/
|
/*shk.c*/
|
||||||
|
|||||||
Reference in New Issue
Block a user