|
|
|
|
@@ -9,6 +9,8 @@
|
|
|
|
|
#define CONTAINED_SYM '>' /* designator for inside a container */
|
|
|
|
|
#define HANDS_SYM '-'
|
|
|
|
|
|
|
|
|
|
STATIC_DCL void FDECL(loot_classify, (Loot *, struct obj *));
|
|
|
|
|
STATIC_DCL char *FDECL(loot_xname, (struct obj *));
|
|
|
|
|
STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (const genericptr,
|
|
|
|
|
const genericptr));
|
|
|
|
|
STATIC_DCL void NDECL(reorder_invent);
|
|
|
|
|
@@ -46,7 +48,219 @@ static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
|
|
|
|
|
*/
|
|
|
|
|
static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
|
|
|
|
|
|
|
|
|
|
unsigned sortlootmode = 0;
|
|
|
|
|
/* sortloot() classification; called at most once for each object sorted */
|
|
|
|
|
STATIC_OVL void
|
|
|
|
|
loot_classify(sort_item, obj)
|
|
|
|
|
Loot *sort_item;
|
|
|
|
|
struct obj *obj;
|
|
|
|
|
{
|
|
|
|
|
/* we may eventually make this a settable option to always use
|
|
|
|
|
with sortloot instead of only when the 'sortpack' option isn't
|
|
|
|
|
set; it is similar to sortpack's inv_order but items most
|
|
|
|
|
likely to be picked up are moved to the front */
|
|
|
|
|
static char def_srt_order[MAXOCLASSES] = {
|
|
|
|
|
COIN_CLASS, AMULET_CLASS, RING_CLASS, WAND_CLASS, POTION_CLASS,
|
|
|
|
|
SCROLL_CLASS, SPBOOK_CLASS, GEM_CLASS, FOOD_CLASS, TOOL_CLASS,
|
|
|
|
|
WEAPON_CLASS, ARMOR_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
|
|
|
|
|
};
|
|
|
|
|
static char armcat[8];
|
|
|
|
|
const char *classorder;
|
|
|
|
|
char *p;
|
|
|
|
|
int k, otyp = obj->otyp, oclass = obj->oclass;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* For the value types assigned by this classification, sortloot()
|
|
|
|
|
* will put lower valued ones before higher valued ones.
|
|
|
|
|
*/
|
|
|
|
|
if (!Blind)
|
|
|
|
|
obj->dknown = 1; /* xname(obj) does this; we want it sooner */
|
|
|
|
|
/* class order */
|
|
|
|
|
classorder = flags.sortpack ? flags.inv_order : def_srt_order;
|
|
|
|
|
p = index(classorder, oclass);
|
|
|
|
|
if (p)
|
|
|
|
|
k = 1 + (int) (p - classorder);
|
|
|
|
|
else
|
|
|
|
|
k = 1 + (int) strlen(classorder) + (oclass != VENOM_CLASS);
|
|
|
|
|
sort_item->class = (xchar) k;
|
|
|
|
|
/* subclass designation; only a few classes have subclasses
|
|
|
|
|
and the non-armor ones we use are fairly arbitrary */
|
|
|
|
|
switch (oclass) {
|
|
|
|
|
case ARMOR_CLASS:
|
|
|
|
|
if (!armcat[7]) {
|
|
|
|
|
/* one-time init; we use a different order than the subclass
|
|
|
|
|
values defined by objclass.h */
|
|
|
|
|
armcat[ARM_HELM] = 1; /* [2] */
|
|
|
|
|
armcat[ARM_GLOVES] = 2; /* [3] */
|
|
|
|
|
armcat[ARM_BOOTS] = 3; /* [4] */
|
|
|
|
|
armcat[ARM_SHIELD] = 4; /* [1] */
|
|
|
|
|
armcat[ARM_CLOAK] = 5; /* [5] */
|
|
|
|
|
armcat[ARM_SHIRT] = 6; /* [6] */
|
|
|
|
|
armcat[ARM_SUIT] = 7; /* [0] */
|
|
|
|
|
armcat[7] = 8; /* sanity protection */
|
|
|
|
|
}
|
|
|
|
|
k = objects[otyp].oc_armcat;
|
|
|
|
|
/* oc_armcat overloads oc_subtyp which is an 'schar' so guard
|
|
|
|
|
against somebody assigning something unexpected to it */
|
|
|
|
|
if (k < 0 || k >= 7)
|
|
|
|
|
k = 7;
|
|
|
|
|
k = armcat[k];
|
|
|
|
|
break;
|
|
|
|
|
case WEAPON_CLASS:
|
|
|
|
|
/* for weapons, group by ammo (arrows, bolts), launcher (bows),
|
|
|
|
|
missile (darts, boomerangs), stackable (daggers, knives, spears),
|
|
|
|
|
'other' (swords, axes, &c), polearms */
|
|
|
|
|
k = objects[otyp].oc_skill;
|
|
|
|
|
k = (k < 0) ? ((k >= -P_CROSSBOW && k <= -P_BOW) ? 1 : 3)
|
|
|
|
|
: ((k >= P_BOW && k <= P_CROSSBOW) ? 2
|
|
|
|
|
: (k == P_SPEAR || k == P_DAGGER || k == P_KNIFE) ? 4
|
|
|
|
|
: !is_pole(obj) ? 5 : 6);
|
|
|
|
|
break;
|
|
|
|
|
case TOOL_CLASS:
|
|
|
|
|
if (obj->dknown && objects[otyp].oc_name_known
|
|
|
|
|
&& (otyp == BAG_OF_TRICKS || otyp == HORN_OF_PLENTY))
|
|
|
|
|
k = 2; /* known pseudo-container */
|
|
|
|
|
else if (Is_container(obj))
|
|
|
|
|
k = 1; /* regular container or unknown bag of tricks */
|
|
|
|
|
else
|
|
|
|
|
switch (otyp) {
|
|
|
|
|
case WOODEN_FLUTE:
|
|
|
|
|
case MAGIC_FLUTE:
|
|
|
|
|
case TOOLED_HORN:
|
|
|
|
|
case FROST_HORN:
|
|
|
|
|
case FIRE_HORN:
|
|
|
|
|
case WOODEN_HARP:
|
|
|
|
|
case MAGIC_HARP:
|
|
|
|
|
case BUGLE:
|
|
|
|
|
case LEATHER_DRUM:
|
|
|
|
|
case DRUM_OF_EARTHQUAKE:
|
|
|
|
|
case HORN_OF_PLENTY: /* not a musical instrument */
|
|
|
|
|
k = 3; /* instrument or unknown horn of plenty */
|
|
|
|
|
default:
|
|
|
|
|
k = 4; /* 'other' tool */
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case FOOD_CLASS:
|
|
|
|
|
/* [what about separating "partly eaten" within each group?] */
|
|
|
|
|
switch (otyp) {
|
|
|
|
|
case SLIME_MOLD:
|
|
|
|
|
k = 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* [maybe separate one-bite foods from rations and such?] */
|
|
|
|
|
k = obj->globby ? 6 : 2;
|
|
|
|
|
break;
|
|
|
|
|
case TIN:
|
|
|
|
|
k = 3;
|
|
|
|
|
break;
|
|
|
|
|
case EGG:
|
|
|
|
|
k = 4;
|
|
|
|
|
break;
|
|
|
|
|
case CORPSE:
|
|
|
|
|
k = 5;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* other classes don't have subclasses; we assign a nonzero
|
|
|
|
|
value because sortloot() uses 0 to mean 'not yet classified' */
|
|
|
|
|
k = 1; /* any non-zero would do */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
sort_item->subclass = (xchar) k;
|
|
|
|
|
/* discovery status */
|
|
|
|
|
k = !obj->dknown ? 1 /* unseen */
|
|
|
|
|
: (objects[otyp].oc_name_known || !OBJ_DESCR(objects[otyp])) ? 4
|
|
|
|
|
: (objects[otyp].oc_uname)? 3 /* named (partially discovered) */
|
|
|
|
|
: 2; /* undiscovered */
|
|
|
|
|
sort_item->disco = (xchar) k;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* sortloot() formatting routine; for alphabetizing, not shown to user */
|
|
|
|
|
STATIC_OVL char *
|
|
|
|
|
loot_xname(obj)
|
|
|
|
|
struct obj *obj;
|
|
|
|
|
{
|
|
|
|
|
struct obj saveo;
|
|
|
|
|
boolean save_debug;
|
|
|
|
|
char *res, *save_oname;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Deal with things that xname() includes as a prefix. We don't
|
|
|
|
|
* want such because they change alphabetical ordering. First,
|
|
|
|
|
* remember 'obj's current settings.
|
|
|
|
|
*/
|
|
|
|
|
saveo.odiluted = obj->odiluted;
|
|
|
|
|
saveo.blessed = obj->blessed, saveo.cursed = obj->cursed;
|
|
|
|
|
saveo.spe = obj->spe;
|
|
|
|
|
saveo.owt = obj->owt;
|
|
|
|
|
save_oname = has_oname(obj) ? ONAME(obj) : 0;
|
|
|
|
|
save_debug = flags.debug;
|
|
|
|
|
/* suppress "diluted" for potions and "holy/unholy" for water;
|
|
|
|
|
sortloot() will deal with them using other criteria than name */
|
|
|
|
|
if (obj->oclass == POTION_CLASS) {
|
|
|
|
|
obj->odiluted = 0;
|
|
|
|
|
if (obj->otyp == POT_WATER)
|
|
|
|
|
obj->blessed = 0, obj->cursed = 0;
|
|
|
|
|
}
|
|
|
|
|
/* make "wet towel" and "moist towel" format as "towel" so that all
|
|
|
|
|
three group together */
|
|
|
|
|
if (obj->otyp == TOWEL)
|
|
|
|
|
obj->spe = 0;
|
|
|
|
|
/* group "<size> glob of <foo>" by <foo> rather than by <size> */
|
|
|
|
|
if (obj->globby)
|
|
|
|
|
obj->owt = 200; /* 200: weight of combined glob from ten creatures
|
|
|
|
|
(five or fewer is "small", more than fifteen is
|
|
|
|
|
"large", in between has no prefix) */
|
|
|
|
|
/* suppress user-assigned name */
|
|
|
|
|
if (save_oname && !obj->oartifact)
|
|
|
|
|
ONAME(obj) = 0;
|
|
|
|
|
/* avoid wizard mode formatting variations */
|
|
|
|
|
if (wizard) { /* flags.debug */
|
|
|
|
|
/* paranoia: before toggling off wizard mode, guard against a
|
|
|
|
|
panic in xname() producing a normal mode panic save file */
|
|
|
|
|
program_state.something_worth_saving = 0;
|
|
|
|
|
flags.debug = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = cxname_singular(obj);
|
|
|
|
|
|
|
|
|
|
if (save_debug) {
|
|
|
|
|
flags.debug = TRUE;
|
|
|
|
|
program_state.something_worth_saving = 1;
|
|
|
|
|
}
|
|
|
|
|
/* restore the object */
|
|
|
|
|
if (obj->oclass == POTION_CLASS) {
|
|
|
|
|
obj->odiluted = saveo.odiluted;
|
|
|
|
|
if (obj->otyp == POT_WATER)
|
|
|
|
|
obj->blessed = saveo.blessed, obj->cursed = saveo.cursed;
|
|
|
|
|
}
|
|
|
|
|
if (obj->otyp == TOWEL) {
|
|
|
|
|
obj->spe = saveo.spe;
|
|
|
|
|
/* give "towel" a suffix that will force wet ones to come first,
|
|
|
|
|
moist ones next, and dry ones last regardless of whether
|
|
|
|
|
they've been flagged as having spe known */
|
|
|
|
|
Strcat(res, is_wet_towel(obj) ? ((obj->spe >= 3) ? "x" : "y") : "z");
|
|
|
|
|
}
|
|
|
|
|
if (obj->globby) {
|
|
|
|
|
obj->owt = saveo.owt;
|
|
|
|
|
/* we've suppressed the size prefix (above); there normally won't
|
|
|
|
|
be more than one of a given creature type because they coalesce,
|
|
|
|
|
but globs with different bless/curse state won't merge so it is
|
|
|
|
|
feasible to have multiple at the same location; add a suffix to
|
|
|
|
|
get such sorted by size (small first) */
|
|
|
|
|
Strcat(res, (obj->owt <= 100) ? "a"
|
|
|
|
|
: (obj->owt <= 300) ? "b"
|
|
|
|
|
: (obj->owt <= 500) ? "c"
|
|
|
|
|
: "d");
|
|
|
|
|
}
|
|
|
|
|
if (save_oname && !obj->oartifact)
|
|
|
|
|
ONAME(obj) = save_oname;
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set by sortloot() for use by sortloot_cmp(); reset by sortloot when done */
|
|
|
|
|
static unsigned sortlootmode = 0;
|
|
|
|
|
|
|
|
|
|
/* qsort comparison routine for sortloot() */
|
|
|
|
|
STATIC_OVL int CFDECLSPEC
|
|
|
|
|
@@ -57,57 +271,46 @@ const genericptr vptr2;
|
|
|
|
|
struct sortloot_item *sli1 = (struct sortloot_item *) vptr1,
|
|
|
|
|
*sli2 = (struct sortloot_item *) vptr2;
|
|
|
|
|
struct obj *obj1 = sli1->obj,
|
|
|
|
|
*obj2 = sli2->obj,
|
|
|
|
|
sav1, sav2;
|
|
|
|
|
char *cls1, *cls2, nam1[BUFSZ], nam2[BUFSZ];
|
|
|
|
|
*obj2 = sli2->obj;
|
|
|
|
|
char *nam1, *nam2;
|
|
|
|
|
int val1, val2, c, namcmp;
|
|
|
|
|
|
|
|
|
|
/* order by object class like inventory display */
|
|
|
|
|
if ((sortlootmode & SORTLOOT_PACK) != 0) {
|
|
|
|
|
cls1 = index(flags.inv_order, obj1->oclass);
|
|
|
|
|
cls2 = index(flags.inv_order, obj2->oclass);
|
|
|
|
|
if (cls1 != cls2)
|
|
|
|
|
return (int) (cls1 - cls2);
|
|
|
|
|
/* order by object class unless we're doing by-invlet without sortpack */
|
|
|
|
|
if ((sortlootmode & (SORTLOOT_PACK | SORTLOOT_INVLET))
|
|
|
|
|
!= SORTLOOT_INVLET) {
|
|
|
|
|
/* Classify each object at most once no matter how many
|
|
|
|
|
comparisons it is involved in. */
|
|
|
|
|
if (!sli1->class)
|
|
|
|
|
loot_classify(sli1, obj1);
|
|
|
|
|
if (!sli2->class)
|
|
|
|
|
loot_classify(sli2, obj2);
|
|
|
|
|
|
|
|
|
|
if ((sortlootmode & SORTLOOT_INVLET) != 0) {
|
|
|
|
|
; /* skip sub-classes when sorting by packorder+invlet */
|
|
|
|
|
/* Sort by class. */
|
|
|
|
|
val1 = sli1->class;
|
|
|
|
|
val2 = sli2->class;
|
|
|
|
|
if (val1 != val2)
|
|
|
|
|
return (int) (val1 - val2);
|
|
|
|
|
|
|
|
|
|
/* for armor, group by sub-category */
|
|
|
|
|
} else if (obj1->oclass == ARMOR_CLASS) {
|
|
|
|
|
static int armcat[7 + 1];
|
|
|
|
|
|
|
|
|
|
if (!armcat[7]) {
|
|
|
|
|
/* one-time init; we want to control the order */
|
|
|
|
|
armcat[ARM_HELM] = 1; /* [2] */
|
|
|
|
|
armcat[ARM_GLOVES] = 2; /* [3] */
|
|
|
|
|
armcat[ARM_BOOTS] = 3; /* [4] */
|
|
|
|
|
armcat[ARM_SHIELD] = 4; /* [1] */
|
|
|
|
|
armcat[ARM_CLOAK] = 5; /* [5] */
|
|
|
|
|
armcat[ARM_SHIRT] = 6; /* [6] */
|
|
|
|
|
armcat[ARM_SUIT] = 7; /* [0] */
|
|
|
|
|
armcat[7] = 8;
|
|
|
|
|
}
|
|
|
|
|
val1 = armcat[objects[obj1->otyp].oc_armcat];
|
|
|
|
|
val2 = armcat[objects[obj2->otyp].oc_armcat];
|
|
|
|
|
/* skip sub-classes when ordering by sortpack+invlet */
|
|
|
|
|
if ((sortlootmode & SORTLOOT_INVLET) == 0) {
|
|
|
|
|
/* Class matches; sort by subclass. */
|
|
|
|
|
val1 = sli1->subclass;
|
|
|
|
|
val2 = sli2->subclass;
|
|
|
|
|
if (val1 != val2)
|
|
|
|
|
return val1 - val2;
|
|
|
|
|
|
|
|
|
|
/* for weapons, group by ammo (arrows, bolts), launcher (bows),
|
|
|
|
|
missile (dart, boomerang), stackable (daggers, knives, spears),
|
|
|
|
|
'other' (swords, axes, &c), polearm */
|
|
|
|
|
} else if (obj1->oclass == WEAPON_CLASS) {
|
|
|
|
|
val1 = objects[obj1->otyp].oc_skill;
|
|
|
|
|
val1 = (val1 < 0)
|
|
|
|
|
? (val1 >= -P_CROSSBOW && val1 <= -P_BOW) ? 1 : 3
|
|
|
|
|
: (val1 >= P_BOW && val1 <= P_CROSSBOW) ? 2
|
|
|
|
|
: (val1 == P_SPEAR || val1 == P_DAGGER
|
|
|
|
|
|| val1 == P_KNIFE) ? 4 : !is_pole(obj1) ? 5 : 6;
|
|
|
|
|
val2 = objects[obj2->otyp].oc_skill;
|
|
|
|
|
val2 = (val2 < 0)
|
|
|
|
|
? (val2 >= -P_CROSSBOW && val2 <= -P_BOW) ? 1 : 3
|
|
|
|
|
: (val2 >= P_BOW && val2 <= P_CROSSBOW) ? 2
|
|
|
|
|
: (val2 == P_SPEAR || val2 == P_DAGGER
|
|
|
|
|
|| val2 == P_KNIFE) ? 4 : !is_pole(obj2) ? 5 : 6;
|
|
|
|
|
/* Class and subclass match; sort by discovery status:
|
|
|
|
|
* first unseen, then seen but not named or discovered,
|
|
|
|
|
* then named, lastly discovered.
|
|
|
|
|
* 1) potion
|
|
|
|
|
* 2) pink potion
|
|
|
|
|
* 3) dark green potion called confusion
|
|
|
|
|
* 4) potion of healing
|
|
|
|
|
* Multiple entries within each group will be put into
|
|
|
|
|
* alphabetical order below.
|
|
|
|
|
*/
|
|
|
|
|
val1 = sli1->disco;
|
|
|
|
|
val2 = sli2->disco;
|
|
|
|
|
if (val1 != val2)
|
|
|
|
|
return val1 - val2;
|
|
|
|
|
}
|
|
|
|
|
@@ -136,28 +339,16 @@ const genericptr vptr2;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Sort object names in lexicographical order, ignoring quantity.
|
|
|
|
|
*
|
|
|
|
|
* Each obj gets formatted at most once (per sort) no matter how many
|
|
|
|
|
* comparisons it gets subjected to.
|
|
|
|
|
*/
|
|
|
|
|
/* Force diluted potions to come out after undiluted of same type;
|
|
|
|
|
obj->odiluted overloads obj->oeroded. */
|
|
|
|
|
sav1.odiluted = obj1->odiluted;
|
|
|
|
|
sav2.odiluted = obj2->odiluted;
|
|
|
|
|
if (obj1->oclass == POTION_CLASS)
|
|
|
|
|
obj1->odiluted = 0;
|
|
|
|
|
if (obj1->oclass == POTION_CLASS)
|
|
|
|
|
obj2->odiluted = 0;
|
|
|
|
|
/* Force holy and unholy water to sort adjacent to water rather
|
|
|
|
|
than among 'h's and 'u's. BUCX order will keep them distinct. */
|
|
|
|
|
Strcpy(nam1, cxname_singular(obj1));
|
|
|
|
|
if (obj1->otyp == POT_WATER && obj1->bknown
|
|
|
|
|
&& (obj1->blessed || obj1->cursed))
|
|
|
|
|
(void) strsubst(nam1, obj1->blessed ? "holy " : "unholy ", "");
|
|
|
|
|
Strcpy(nam2, cxname_singular(obj2));
|
|
|
|
|
if (obj2->otyp == POT_WATER && obj2->bknown
|
|
|
|
|
&& (obj2->blessed || obj2->cursed))
|
|
|
|
|
(void) strsubst(nam2, obj2->blessed ? "holy " : "unholy ", "");
|
|
|
|
|
obj1->odiluted = sav1.odiluted;
|
|
|
|
|
obj2->odiluted = sav2.odiluted;
|
|
|
|
|
|
|
|
|
|
nam1 = sli1->str;
|
|
|
|
|
if (!nam1)
|
|
|
|
|
nam1 = sli1->str = dupstr(loot_xname(obj1));
|
|
|
|
|
nam2 = sli2->str;
|
|
|
|
|
if (!nam2)
|
|
|
|
|
nam2 = sli2->str = dupstr(loot_xname(obj2));
|
|
|
|
|
if ((namcmp = strcmpi(nam1, nam2)) != 0)
|
|
|
|
|
return namcmp;
|
|
|
|
|
|
|
|
|
|
@@ -227,7 +418,7 @@ tiebreak:
|
|
|
|
|
* whether the list was already sorted as it got ready to do the
|
|
|
|
|
* sorting, so re-examining inventory or a pile of objects without
|
|
|
|
|
* having changed anything would gobble up less CPU than a full
|
|
|
|
|
* sort. But it had as least two problems (aside from the ordinary
|
|
|
|
|
* sort. But it had at least two problems (aside from the ordinary
|
|
|
|
|
* complement of bugs):
|
|
|
|
|
* 1) some players wanted to get the original order back when they
|
|
|
|
|
* changed the 'sortloot' option back to 'none', but the list
|
|
|
|
|
@@ -267,26 +458,38 @@ boolean FDECL((*filterfunc), (OBJ_P));
|
|
|
|
|
/* note: if there is a filter function, this might overallocate */
|
|
|
|
|
sliarray = (Loot *) alloc((n + 1) * sizeof *sliarray);
|
|
|
|
|
|
|
|
|
|
/* the 'keep cockatrice corpses' flag is overloaded with sort mode */
|
|
|
|
|
augment_filter = (mode & SORTLOOT_PETRIFY) ? TRUE : FALSE;
|
|
|
|
|
mode &= ~SORTLOOT_PETRIFY; /* remove flag, leaving mode */
|
|
|
|
|
/* populate aliarray[0..n-1] */
|
|
|
|
|
for (i = 0, o = *olist; o; ++i, o = by_nexthere ? o->nexthere : o->nobj) {
|
|
|
|
|
if (filterfunc && !(*filterfunc)(o)
|
|
|
|
|
/* caller may be asking us to override filterfunc (in order
|
|
|
|
|
to do a cockatrice corpse touch check during pickup even
|
|
|
|
|
if/when the filter rejects food class) */
|
|
|
|
|
&& (!augment_filter || o->otyp != CORPSE
|
|
|
|
|
|| !touch_petrifies(&mons[o->corpsenm])))
|
|
|
|
|
continue;
|
|
|
|
|
sliarray[i].obj = o, sliarray[i].indx = (int) i;
|
|
|
|
|
sliarray[i].str = (char *) 0;
|
|
|
|
|
sliarray[i].class = sliarray[i].subclass = sliarray[i].disco = 0;
|
|
|
|
|
}
|
|
|
|
|
n = i;
|
|
|
|
|
/* add a terminator so that we don't have to pass 'n' back to caller */
|
|
|
|
|
sliarray[n].obj = (struct obj *) 0, sliarray[n].indx = -1;
|
|
|
|
|
mode &= ~SORTLOOT_PETRIFY;
|
|
|
|
|
sliarray[n].str = (char *) 0;
|
|
|
|
|
sliarray[n].class = sliarray[n].subclass = sliarray[n].disco = 0;
|
|
|
|
|
|
|
|
|
|
/* do the sort; if no sorting is requested, we'll just return
|
|
|
|
|
a sortloot_item array reflecting the current ordering */
|
|
|
|
|
if (mode) {
|
|
|
|
|
if (mode && n > 1) {
|
|
|
|
|
sortlootmode = mode; /* extra input for sortloot_cmp() */
|
|
|
|
|
qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp);
|
|
|
|
|
sortlootmode = 0; /* reset static mode flags */
|
|
|
|
|
/* if sortloot_cmp formatted any objects, discard their strings now */
|
|
|
|
|
for (i = 0; i < n; ++i)
|
|
|
|
|
if (sliarray[i].str)
|
|
|
|
|
free((genericptr_t) sliarray[i].str), sliarray[i].str = 0;
|
|
|
|
|
}
|
|
|
|
|
return sliarray;
|
|
|
|
|
}
|
|
|
|
|
|