add some new, easier achievements
Introduce eight achievements that can be attained by more players. Entered Gnomish Mines - self explanatory Entered Mine Town - the town portion, not just the level Entered a shop - any tended shop on any level Entered a temple - likewise for temple Consulted the Oracle - bought at least one major or minor oracle Read a Discworld Novel - read at least one passage Entered Sokoban - like mines Entered the Big Room - not always possible since not always present The novel and bigroom ones aren't always achieveable since novels are only guaranteed if a book or scroll shop gets created and bigroom is only guaranteed in wizard mode. No one ever claimed that every possible achievement can be attained in a single game. (If one for entering the Fort Ludios level--or perhaps entering the Fort itself-- eventually gets add, that won't be possible in every game either.) The mine town one probably needs some tweaking. Two of the town's seven variants have no town boundary (despite a rectangular area of pre-defined map) and at present simply arriving on either of those levels is enough to be credited with the entered-town achievement. Bump EDITLEVEL because u.uachieved[] has increased in size. This time it has been expanded to the maximum that xlogfile's bitmask of achievements can handle, enough for up to 9 more achievements without another EDITLEVEL increment.
This commit is contained in:
@@ -792,12 +792,12 @@ boolean pre, wiztower;
|
||||
static const char Unachieve[] = "%s achievement revoked.";
|
||||
|
||||
if (Is_mineend_level(&u.uz)) {
|
||||
if (remove_achievement(ACH_LUCK))
|
||||
pline(Unachieve, "Mine's end");
|
||||
if (remove_achievement(ACH_MINE_PRIZE))
|
||||
pline(Unachieve, "Mine's-end");
|
||||
g.context.achieveo.mines_prize_oid = 0;
|
||||
} else if (Is_sokoend_level(&u.uz)) {
|
||||
if (remove_achievement(ACH_SOKO))
|
||||
pline(Unachieve, "Sokoban end");
|
||||
if (remove_achievement(ACH_SOKO_PRIZE))
|
||||
pline(Unachieve, "Sokoban-end");
|
||||
g.context.achieveo.soko_prize_oid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
22
src/do.c
22
src/do.c
@@ -1624,12 +1624,6 @@ boolean at_stairs, falling, portal;
|
||||
/* special levels can have a custom arrival message */
|
||||
deliver_splev_message();
|
||||
|
||||
/* give room entrance message, if any */
|
||||
check_special_room(FALSE);
|
||||
|
||||
/* deliver objects traveling with player */
|
||||
obj_delivery(TRUE);
|
||||
|
||||
/* Check whether we just entered Gehennom. */
|
||||
if (!In_hell(&u.uz0) && Inhell) {
|
||||
if (Is_valley(&u.uz)) {
|
||||
@@ -1701,9 +1695,18 @@ boolean at_stairs, falling, portal;
|
||||
mtmp->msleeping = 0;
|
||||
}
|
||||
}
|
||||
} else if (In_mines(&u.uz)) {
|
||||
if (newdungeon)
|
||||
record_achievement(ACH_MINE);
|
||||
} else if (In_sokoban(&u.uz)) {
|
||||
if (newdungeon)
|
||||
record_achievement(ACH_SOKO);
|
||||
} else {
|
||||
if (new && Is_rogue_level(&u.uz))
|
||||
if (new && Is_rogue_level(&u.uz)) {
|
||||
You("enter what seems to be an older, more primitive world.");
|
||||
} else if (new && Is_bigroom(&u.uz)) {
|
||||
record_achievement(ACH_BGRM);
|
||||
}
|
||||
/* main dungeon message from your quest leader */
|
||||
if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest")
|
||||
&& !(u.uevent.qcompleted || u.uevent.qexpelled
|
||||
@@ -1727,6 +1730,11 @@ boolean at_stairs, falling, portal;
|
||||
if ((annotation = get_annotation(&u.uz)) != 0)
|
||||
You("remember this level as %s.", annotation);
|
||||
|
||||
/* give room entrance message, if any */
|
||||
check_special_room(FALSE);
|
||||
/* deliver objects traveling with player */
|
||||
obj_delivery(TRUE);
|
||||
|
||||
/* assume this will always return TRUE when changing level */
|
||||
(void) in_out_region(u.ux, u.uy);
|
||||
(void) pickup(1);
|
||||
|
||||
13
src/hack.c
13
src/hack.c
@@ -2198,7 +2198,7 @@ boolean pick;
|
||||
check_special_room(FALSE);
|
||||
if (IS_SINK(levl[u.ux][u.uy].typ) && Levitation)
|
||||
dosinkfall();
|
||||
if (!g.in_steed_dismounting) { /* if dismounting, we'll check again later */
|
||||
if (!g.in_steed_dismounting) { /* if dismounting, check again later */
|
||||
boolean pit;
|
||||
|
||||
/* if levitation is due to time out at the end of this
|
||||
@@ -2462,7 +2462,7 @@ register boolean newlev;
|
||||
/* possibly deliver a one-time room entry message */
|
||||
void
|
||||
check_special_room(newlev)
|
||||
register boolean newlev;
|
||||
boolean newlev;
|
||||
{
|
||||
register struct monst *mtmp;
|
||||
char *ptr;
|
||||
@@ -2475,6 +2475,12 @@ register boolean newlev;
|
||||
if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */
|
||||
return; /* no entrance messages necessary */
|
||||
|
||||
if (!g.context.achieveo.minetn_reached
|
||||
&& In_mines(&u.uz) && in_town(u.ux, u.uy)) {
|
||||
record_achievement(ACH_TOWN);
|
||||
g.context.achieveo.minetn_reached = TRUE;
|
||||
}
|
||||
|
||||
/* Did we just enter a shop? */
|
||||
if (*u.ushops_entered)
|
||||
u_entered_shop(u.ushops_entered);
|
||||
@@ -2504,6 +2510,7 @@ register boolean newlev;
|
||||
case MORGUE:
|
||||
if (midnight()) {
|
||||
const char *run = locomotion(g.youmonst.data, "Run");
|
||||
|
||||
pline("%s away! %s away!", run, run);
|
||||
} else
|
||||
You("have an uncanny feeling...");
|
||||
@@ -2528,6 +2535,7 @@ register boolean newlev;
|
||||
break;
|
||||
case DELPHI: {
|
||||
struct monst *oracle = monstinroom(&mons[PM_ORACLE], roomno);
|
||||
|
||||
if (oracle) {
|
||||
if (!oracle->mpeaceful)
|
||||
verbalize("You're in Delphi, %s.", g.plname);
|
||||
@@ -2586,7 +2594,6 @@ register boolean newlev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1755,14 +1755,38 @@ int final; /* used "behind the curtain" by enl_foo() macros */
|
||||
case ACH_NUDE:
|
||||
enl_msg(You_, "have gone", "went", " without any armor", "");
|
||||
break;
|
||||
case ACH_LUCK:
|
||||
enl_msg(You_, "have ", "", "completed the Gnomish Mines", "");
|
||||
case ACH_MINE:
|
||||
you_have_X("entered the Gnomish Mines");
|
||||
break;
|
||||
case ACH_TOWN:
|
||||
you_have_X("entered Mine Town");
|
||||
break;
|
||||
case ACH_SHOP:
|
||||
you_have_X("entered a shop");
|
||||
break;
|
||||
case ACH_TMPL:
|
||||
you_have_X("entered a temple");
|
||||
break;
|
||||
case ACH_ORCL:
|
||||
you_have_X("consulted the Oracle of Delphi");
|
||||
break;
|
||||
case ACH_NOVL:
|
||||
you_have_X("read from a Discworld novel");
|
||||
break;
|
||||
case ACH_SOKO:
|
||||
enl_msg(You_, "have ", "", "completed Sokoban", "");
|
||||
you_have_X("entered Sokoban");
|
||||
break;
|
||||
case ACH_SOKO_PRIZE: /* hard to reach guaranteed bag or amulet */
|
||||
you_have_X("completed Sokoban");
|
||||
break;
|
||||
case ACH_MINE_PRIZE: /* hidden guaranteed luckstone */
|
||||
you_have_X("completed the Gnomish Mines");
|
||||
break;
|
||||
case ACH_BGRM:
|
||||
you_have_X("entered the Big Room");
|
||||
break;
|
||||
case ACH_MEDU:
|
||||
enl_msg(You_, "have ", "", "defeated Medusa", "");
|
||||
you_have_X("defeated Medusa");
|
||||
break;
|
||||
case ACH_BELL:
|
||||
/* alternate phrasing for present vs past and also for
|
||||
@@ -1788,8 +1812,7 @@ int final; /* used "behind the curtain" by enl_foo() macros */
|
||||
" the Book of the Dead", "");
|
||||
break;
|
||||
case ACH_INVK:
|
||||
enl_msg(You_, "have ", "",
|
||||
"gained access to Moloch's Sanctum", "");
|
||||
you_have_X("gained access to Moloch's Sanctum");
|
||||
break;
|
||||
case ACH_AMUL:
|
||||
/* alternate wording for ascended (always past tense) since
|
||||
@@ -1805,10 +1828,10 @@ int final; /* used "behind the curtain" by enl_foo() macros */
|
||||
be redundant and ascending makes both be redundant, but
|
||||
we display all that apply */
|
||||
case ACH_ENDG:
|
||||
enl_msg(You_, "have ", "", "reached the Elemental Planes", "");
|
||||
you_have_X("reached the Elemental Planes");
|
||||
break;
|
||||
case ACH_ASTR:
|
||||
enl_msg(You_, "have ", "", "reached the Astral Plane", "");
|
||||
you_have_X("reached the Astral Plane");
|
||||
break;
|
||||
case ACH_UWIN:
|
||||
/* the ultimate achievement... */
|
||||
|
||||
@@ -839,11 +839,11 @@ struct obj *obj;
|
||||
/* "special achievements"; revealed in end of game disclosure and
|
||||
dumplog, originally just recorded in XLOGFILE */
|
||||
if (is_mines_prize(obj)) {
|
||||
record_achievement(ACH_LUCK);
|
||||
record_achievement(ACH_MINE_PRIZE);
|
||||
g.context.achieveo.mines_prize_oid = 0; /* done with luckstone o_id */
|
||||
obj->nomerge = 0;
|
||||
} else if (is_soko_prize(obj)) {
|
||||
record_achievement(ACH_SOKO);
|
||||
record_achievement(ACH_SOKO_PRIZE);
|
||||
g.context.achieveo.soko_prize_oid = 0; /* done with bag/amulet o_id */
|
||||
obj->nomerge = 0;
|
||||
}
|
||||
|
||||
@@ -402,6 +402,7 @@ int roomno;
|
||||
|
||||
if ((priest = findpriest((char) roomno)) != 0) {
|
||||
/* tended */
|
||||
record_achievement(ACH_TMPL);
|
||||
|
||||
epri_p = EPRI(priest);
|
||||
shrined = has_shrine(priest);
|
||||
|
||||
@@ -525,6 +525,8 @@ struct monst *oracl;
|
||||
}
|
||||
money2mon(oracl, (long) u_pay);
|
||||
g.context.botl = 1;
|
||||
if (!u.uevent.major_oracle && !u.uevent.minor_oracle)
|
||||
record_achievement(ACH_ORCL);
|
||||
add_xpts = 0; /* first oracle of each type gives experience points */
|
||||
if (u_pay == minor_cost) {
|
||||
outrumor(1, BY_ORACLE);
|
||||
|
||||
@@ -564,6 +564,7 @@ char *enterstring;
|
||||
u.ushops[0] = '\0';
|
||||
return;
|
||||
}
|
||||
record_achievement(ACH_SHOP);
|
||||
|
||||
eshkp->bill_p = &(eshkp->bill[0]);
|
||||
|
||||
|
||||
@@ -465,7 +465,8 @@ register struct obj *spellbook;
|
||||
}
|
||||
}
|
||||
|
||||
if (g.context.spbook.delay && !confused && spellbook == g.context.spbook.book
|
||||
if (g.context.spbook.delay && !confused
|
||||
&& spellbook == g.context.spbook.book
|
||||
/* handle the sequence: start reading, get interrupted, have
|
||||
g.context.spbook.book become erased somehow, resume reading it */
|
||||
&& booktype != SPE_BLANK_PAPER) {
|
||||
@@ -490,6 +491,7 @@ register struct obj *spellbook;
|
||||
check_unpaid(spellbook);
|
||||
makeknown(booktype);
|
||||
if (!u.uevent.read_tribute) {
|
||||
record_achievement(ACH_NOVL);
|
||||
/* give bonus of 20 xp and 4*20+0 pts */
|
||||
more_experienced(20, 0);
|
||||
newexplevel();
|
||||
|
||||
63
src/topten.c
63
src/topten.c
@@ -70,7 +70,7 @@ static void FDECL(writeentry, (FILE *, struct toptenentry *));
|
||||
static void FDECL(writexlentry, (FILE *, struct toptenentry *, int));
|
||||
static long NDECL(encodexlogflags);
|
||||
static long NDECL(encodeconduct);
|
||||
static long NDECL(encodeachieve);
|
||||
static long FDECL(encodeachieve, (BOOLEAN_P));
|
||||
#endif
|
||||
static void FDECL(free_ttlist, (struct toptenentry *));
|
||||
static int FDECL(classmon, (char *, BOOLEAN_P));
|
||||
@@ -365,7 +365,8 @@ int how;
|
||||
Fprintf(rfile, "%cwhile=%s", XLOG_SEP,
|
||||
g.multi_reason ? g.multi_reason : "helpless");
|
||||
Fprintf(rfile, "%cconduct=0x%lx%cturns=%ld%cachieve=0x%lx", XLOG_SEP,
|
||||
encodeconduct(), XLOG_SEP, g.moves, XLOG_SEP, encodeachieve());
|
||||
encodeconduct(), XLOG_SEP, g.moves, XLOG_SEP,
|
||||
encodeachieve(FALSE));
|
||||
Fprintf(rfile, "%crealtime=%ld%cstarttime=%ld%cendtime=%ld", XLOG_SEP,
|
||||
(long) urealtime.realtime, XLOG_SEP,
|
||||
(long) ubirthday, XLOG_SEP, (long) urealtime.finish_time);
|
||||
@@ -426,54 +427,26 @@ encodeconduct()
|
||||
}
|
||||
|
||||
static long
|
||||
encodeachieve()
|
||||
encodeachieve(secondlong)
|
||||
boolean secondlong; /* False: handle achievements 1..31, True: 32..62 */
|
||||
{
|
||||
int i, ilimit;
|
||||
int i, achidx, offset;
|
||||
long r = 0L;
|
||||
|
||||
/*
|
||||
* Other potential achievements to track (some already recorded
|
||||
* for other purposes such as automatic level annotations or
|
||||
* quest progress):
|
||||
* entered mines branch,
|
||||
* chatted with the Oracle,
|
||||
* read a Discworld novel,
|
||||
* entered Sokoban's first level,
|
||||
* entered Bigroom level,
|
||||
* got quest summons,
|
||||
* entered quest branch,
|
||||
* chatted with leader,
|
||||
* entered second quest level,
|
||||
* entered last quest level,
|
||||
* defeated nemesis (not same as acquiring Bell or artifact),
|
||||
* completed quest (again, not the same as getting the items),
|
||||
* entered rogue level,
|
||||
* entered Fort Ludios level/branch,
|
||||
* entered Medusa level,
|
||||
* entered castle level,
|
||||
* opened castle drawbridge,
|
||||
* obtained castle wand,
|
||||
* entered valley level,
|
||||
* [assorted demon lairs?],
|
||||
* entered Vlad's tower branch,
|
||||
* defeated Vlad (not same as acquiring Candelabrum),
|
||||
* entered Wizard's tower area within relevant level,
|
||||
* defeated Wizard,
|
||||
* found vibrating square,
|
||||
* entered sanctum level,
|
||||
* [defeated Riders],
|
||||
* located the correct high altar (for initial alignment or current
|
||||
* one or both?) on the astral level.
|
||||
* Too many to include them all in a 32-bit mask, but that could
|
||||
* handle a lot of them. Defeated <foo> can be seen via the vanquished
|
||||
* monsters list and many or all of the entered <bar> can be seen via
|
||||
* the dungeon overview but both of those things go away as soon as
|
||||
* the program exits.
|
||||
* 32: portable limit for 'long'.
|
||||
* Force 32 even on configurations that are using 64 bit longs.
|
||||
*
|
||||
* We use signed long and limit ourselves to 31 bits since tools
|
||||
* that post-process xlogfile might not be able to cope with
|
||||
* 'unsigned long'.
|
||||
*/
|
||||
ilimit = min(N_ACH, 32 - 1); /* 32: portable limit for 'long' */
|
||||
for (i = 0; i < ilimit && u.uachieved[i]; ++i)
|
||||
r |= 1L << (u.uachieved[i] - 1);
|
||||
|
||||
offset = secondlong ? (32 - 1) : 0;
|
||||
for (i = 0; u.uachieved[i]; ++i) {
|
||||
achidx = u.uachieved[i] - offset;
|
||||
if (achidx > 0 && achidx < 32) /* value 1..31 sets bit 0..30 */
|
||||
r |= 1L << (achidx - 1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user