Skip to content

Commit 82f38fe

Browse files
committed
The #steal command now auto-selects the only possible adjacent target.
Quality of life, matching #order: stealing always required picking the victim with the position cursor, even when only one monster stood next to the hero. #steal now targets that monster directly and only falls back to the cursor prompt when there are zero or several candidates. * uhitm.c: add find_steal_target(), modeled on sounds.c's find_commandable_pet(). It scans the eight adjacent squares for spottable monsters and returns the candidate only when exactly one exists. Pets and Izchak never qualify, so they cannot shadow a real victim into the prompt path; long worm segments are deduped by monster pointer. Candidacy is judged only on player-observable state (no minvent check, which would leak whether a monster carries anything before a turn is spent). dosteal() tries the helper first and keeps the existing getpos() flow as the fallback.
1 parent a13647f commit 82f38fe

2 files changed

Lines changed: 55 additions & 16 deletions

File tree

‎doc/evilhack-changelog.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5550,4 +5550,5 @@ The following changes to date are:
55505550
- Learned teleport away now follows the wand of teleportation AI rules
55515551
- Fix: pets ordered not to drop items still dropped unwielded weapons
55525552
- Fix: monster spellbook reads blanked the book one study early
5553+
- The #steal command now auto-selects the only possible adjacent target
55535554

‎src/uhitm.c‎

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ STATIC_DCL boolean FDECL(known_hitum, (struct monst *, struct obj *, int *,
1111
STATIC_DCL boolean FDECL(theft_petrifies, (struct obj *));
1212
STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *));
1313
STATIC_DCL struct obj *FDECL(really_steal, (struct obj *, struct monst *));
14+
STATIC_DCL struct monst *NDECL(find_steal_target);
1415
STATIC_DCL boolean FDECL(should_cleave, (void));
1516
STATIC_DCL boolean FDECL(hitum_cleave, (struct monst *, struct attack *));
1617
STATIC_DCL boolean FDECL(hitum, (struct monst *, struct attack *));
@@ -3076,6 +3077,39 @@ struct attack *mattk;
30763077
}
30773078
}
30783079

3080+
/* Find the single valid adjacent steal target if exactly one exists.
3081+
Returns the monster if found, NULL if zero or multiple */
3082+
STATIC_OVL struct monst *
3083+
find_steal_target()
3084+
{
3085+
struct monst *mtmp, *found = (struct monst *) 0;
3086+
int dx, dy;
3087+
3088+
for (dx = -1; dx <= 1; dx++) {
3089+
for (dy = -1; dy <= 1; dy++) {
3090+
if (!dx && !dy)
3091+
continue;
3092+
if (!isok(u.ux + dx, u.uy + dy))
3093+
continue;
3094+
mtmp = m_at(u.ux + dx, u.uy + dy);
3095+
/* a long worm can occupy several adjacent spots */
3096+
if (!mtmp || mtmp == found)
3097+
continue;
3098+
if (!canspotmon(mtmp))
3099+
continue;
3100+
/* skip targets the steal code always refuses */
3101+
if (mtmp->mtame)
3102+
continue;
3103+
if (mtmp->isshk && !strcmp(shkname(mtmp), "Izchak"))
3104+
continue;
3105+
if (found)
3106+
return (struct monst *) 0; /* more than one */
3107+
found = mtmp;
3108+
}
3109+
}
3110+
return found;
3111+
}
3112+
30793113
/* #steal command - Rogue/Convict thievery via extended command,
30803114
replaces the old forcefight-triggered thievery mechanic */
30813115
int
@@ -3108,25 +3142,29 @@ dosteal()
31083142
return 0;
31093143
}
31103144

3111-
/* Target selection */
3112-
cc.x = u.ux;
3113-
cc.y = u.uy;
3114-
if (getpos(&cc, FALSE, "the monster you want to steal from") < 0)
3115-
return 0; /* Aborted - no turn cost */
3145+
/* If exactly one valid adjacent target exists, auto-select it */
3146+
mtmp = find_steal_target();
3147+
if (!mtmp) {
3148+
/* Cursor-based targeting */
3149+
cc.x = u.ux;
3150+
cc.y = u.uy;
3151+
if (getpos(&cc, FALSE, "the monster you want to steal from") < 0)
3152+
return 0; /* Aborted - no turn cost */
31163153

3117-
if (!isok(cc.x, cc.y))
3118-
return 0;
3154+
if (!isok(cc.x, cc.y))
3155+
return 0;
31193156

3120-
mtmp = m_at(cc.x, cc.y);
3121-
if (!mtmp || !canspotmon(mtmp)) {
3122-
pline("There's no one there to steal from.");
3123-
return 0;
3124-
}
3157+
mtmp = m_at(cc.x, cc.y);
3158+
if (!mtmp || !canspotmon(mtmp)) {
3159+
pline("There's no one there to steal from.");
3160+
return 0;
3161+
}
31253162

3126-
/* Adjacency check */
3127-
if (distu(cc.x, cc.y) > 2) {
3128-
pline("You're too far away to steal from %s.", mon_nam(mtmp));
3129-
return 0;
3163+
/* Adjacency check */
3164+
if (distu(cc.x, cc.y) > 2) {
3165+
pline("You're too far away to steal from %s.", mon_nam(mtmp));
3166+
return 0;
3167+
}
31303168
}
31313169

31323170
/* Izchak is off-limits */

0 commit comments

Comments
 (0)