clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name hack.shk.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/games/hack/obj -resource-dir /usr/local/lib/clang/13.0.0 -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/games/hack/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/games/hack/hack.shk.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | #include <stdio.h> |
65 | #include <stdlib.h> |
66 | |
67 | #include "hack.h" |
68 | |
69 | #ifdef QUEST |
70 | int shlevel = 0; |
71 | struct monst *shopkeeper = 0; |
72 | struct obj *billobjs = 0; |
73 | |
74 | void |
75 | obfree(struct obj *obj, struct obj *merge) |
76 | { |
77 | free(obj); |
78 | } |
79 | |
80 | int |
81 | inshop(void) |
82 | { |
83 | return(0); |
84 | } |
85 | |
86 | void |
87 | shopdig(int a) |
88 | {} |
89 | |
90 | void |
91 | addtobill(struct obj *ign) |
92 | {} |
93 | |
94 | void |
95 | subfrombill(struct obj *ign) |
96 | {} |
97 | |
98 | void |
99 | splitbill(struct obj *ign, struct obj *ign2) |
100 | {} |
101 | |
102 | int |
103 | dopay(void) |
104 | { |
105 | return(0); |
106 | } |
107 | |
108 | void |
109 | paybill(void) |
110 | {} |
111 | |
112 | int |
113 | doinvbill(int a) |
114 | { |
115 | return(0); |
116 | } |
117 | |
118 | void |
119 | shkdead(struct monst *ign) |
120 | {} |
121 | |
122 | int |
123 | shkcatch(struct obj *ign) |
124 | { |
125 | return(0); |
126 | } |
127 | |
128 | int |
129 | shk_move(struct monst *ign) |
130 | { |
131 | return(0); |
132 | } |
133 | |
134 | void |
135 | replshk(struct monst *mtmp, struct monst *mtmp2) |
136 | {} |
137 | |
138 | char * |
139 | shkname(struct monst *ign) |
140 | { |
141 | return(""); |
142 | } |
143 | |
144 | #else /* QUEST */ |
145 | #include "hack.mfndpos.h" |
146 | #include "def.eshk.h" |
147 | |
148 | #define ESHK(mon) ((struct eshk *)(&(mon->mextra[0]))) |
149 | #define NOTANGRY(mon) mon->mpeaceful |
150 | #define ANGRY(mon) !NOTANGRY(mon) |
151 | |
152 | extern char plname[]; |
153 | |
154 | |
155 | |
156 | |
157 | static struct monst *shopkeeper = 0; |
158 | static struct bill_x *bill; |
159 | static int shlevel = 0; |
160 | struct obj *billobjs; |
161 | |
162 | static long int total; |
163 | static long int followmsg; |
164 | |
165 | |
166 | |
167 | |
168 | |
169 | |
170 | |
171 | char shtypes[] = { |
172 | RING_SYM, WAND_SYM, WEAPON_SYM, FOOD_SYM, SCROLL_SYM, |
173 | POTION_SYM, ARMOR_SYM, 0 |
174 | }; |
175 | |
176 | static char *shopnam[] = { |
177 | "engagement ring", "walking cane", "antique weapon", |
178 | "delicatessen", "second hand book", "liquor", |
179 | "used armor", "assorted antiques" |
180 | }; |
181 | |
182 | static void setpaid(void); |
183 | static void addupbill(void); |
184 | static void findshk(int); |
185 | static struct bill_x *onbill(struct obj *); |
186 | static void pay(long, struct monst *); |
187 | static int dopayobj(struct bill_x *); |
188 | static struct obj *bp_to_obj(struct bill_x *); |
189 | static int getprice(struct obj *); |
190 | static int realhunger(void); |
191 | |
192 | |
193 | char * |
194 | shkname(struct monst *mtmp) |
195 | { |
196 | return(ESHK(mtmp)->shknam); |
197 | } |
198 | |
199 | void |
200 | shkdead(struct monst *mtmp) |
201 | { |
202 | struct eshk *eshk = ESHK(mtmp); |
203 | |
204 | if(eshk->shoplevel == dlevel) |
205 | rooms[eshk->shoproom].rtype = 0; |
206 | if(mtmp == shopkeeper) { |
207 | setpaid(); |
208 | shopkeeper = 0; |
209 | bill = (struct bill_x *) -1000; |
210 | } |
211 | } |
212 | |
213 | void |
214 | replshk(struct monst *mtmp, struct monst *mtmp2) |
215 | { |
216 | if(mtmp == shopkeeper) { |
217 | shopkeeper = mtmp2; |
218 | bill = &(ESHK(shopkeeper)->bill[0]); |
219 | } |
220 | } |
221 | |
222 | |
223 | |
224 | static void |
225 | setpaid(void) |
226 | { |
227 | struct obj *obj; |
228 | struct monst *mtmp; |
229 | |
230 | for(obj = invent; obj; obj = obj->nobj) |
231 | obj->unpaid = 0; |
232 | for(obj = fobj; obj; obj = obj->nobj) |
233 | obj->unpaid = 0; |
234 | for(obj = fcobj; obj; obj = obj->nobj) |
235 | obj->unpaid = 0; |
236 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) |
237 | for(obj = mtmp->minvent; obj; obj = obj->nobj) |
238 | obj->unpaid = 0; |
239 | for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon) |
240 | for(obj = mtmp->minvent; obj; obj = obj->nobj) |
241 | obj->unpaid = 0; |
242 | while ((obj = billobjs)) { |
243 | billobjs = obj->nobj; |
244 | free(obj); |
245 | } |
246 | ESHK(shopkeeper)->billct = 0; |
247 | } |
248 | |
249 | |
250 | |
251 | static void |
252 | addupbill(void) |
253 | { |
254 | int ct = ESHK(shopkeeper)->billct; |
255 | struct bill_x *bp = bill; |
256 | |
257 | total = 0; |
258 | while(ct--){ |
259 | total += bp->price * bp->bquan; |
260 | bp++; |
261 | } |
262 | } |
263 | |
264 | int |
265 | inshop(void) |
266 | { |
267 | int roomno = inroom(u.ux,u.uy); |
268 | |
269 | |
270 | if(u.uinshop && |
271 | (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) { |
272 | if(shopkeeper) { |
273 | if(ESHK(shopkeeper)->billct) { |
274 | if(inroom(shopkeeper->mx, shopkeeper->my) |
275 | == u.uinshop - 1) |
276 | pline("Somehow you escaped the shop without paying!"); |
277 | addupbill(); |
278 | pline("You stole for a total worth of %ld zorkmids.", |
279 | total); |
280 | ESHK(shopkeeper)->robbed += total; |
281 | setpaid(); |
282 | if((rooms[ESHK(shopkeeper)->shoproom].rtype == GENERAL) |
283 | == (rn2(3) == 0)) |
284 | ESHK(shopkeeper)->following = 1; |
285 | } |
286 | shopkeeper = 0; |
287 | shlevel = 0; |
288 | } |
289 | u.uinshop = 0; |
290 | } |
291 | |
292 | |
293 | if(roomno >= 0) { |
294 | int rt = rooms[roomno].rtype; |
295 | struct monst *mtmp; |
296 | if(rt == ZOO) { |
297 | pline("Welcome to David's treasure zoo!"); |
298 | } else |
299 | if(rt == SWAMP) { |
300 | pline("It looks rather muddy down here."); |
301 | } else |
302 | if(rt == MORGUE) { |
303 | if(midnight()) |
304 | pline("Go away! Go away!"); |
305 | else |
306 | pline("You get an uncanny feeling ..."); |
307 | } else |
308 | rt = 0; |
309 | if(rt != 0) { |
310 | rooms[roomno].rtype = 0; |
311 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) |
312 | if(rt != ZOO || !rn2(3)) |
313 | mtmp->msleep = 0; |
314 | } |
315 | } |
316 | |
317 | |
318 | if(roomno >= 0 && rooms[roomno].rtype >= 8) { |
319 | if(shlevel != dlevel || !shopkeeper |
320 | || ESHK(shopkeeper)->shoproom != roomno) |
321 | findshk(roomno); |
322 | if(!shopkeeper) { |
323 | rooms[roomno].rtype = 0; |
324 | u.uinshop = 0; |
325 | } else if(!u.uinshop){ |
326 | if(!ESHK(shopkeeper)->visitct || |
327 | strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ)){ |
328 | |
329 | |
330 | ESHK(shopkeeper)->visitct = 0; |
331 | ESHK(shopkeeper)->following = 0; |
332 | (void) strlcpy(ESHK(shopkeeper)->customer,plname,PL_NSIZ); |
333 | NOTANGRY(shopkeeper) = 1; |
334 | } |
335 | if(!ESHK(shopkeeper)->following) { |
336 | boolean box, pick; |
337 | |
338 | pline("Hello %s! Welcome%s to %s's %s shop!", |
339 | plname, |
340 | ESHK(shopkeeper)->visitct++ ? " again" : "", |
341 | shkname(shopkeeper), |
342 | shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8] ); |
343 | box = carrying(ICE_BOX); |
344 | pick = carrying(PICK_AXE); |
345 | if(box || pick) { |
346 | if(dochug(shopkeeper)) { |
347 | u.uinshop = 0; |
348 | return(0); |
349 | } |
350 | pline("Will you please leave your %s outside?", |
351 | (box && pick) ? "box and pick-axe" : |
352 | box ? "box" : "pick-axe"); |
353 | } |
354 | } |
355 | u.uinshop = roomno + 1; |
356 | } |
357 | } |
358 | return(u.uinshop); |
359 | } |
360 | |
361 | static void |
362 | findshk(int roomno) |
363 | { |
364 | struct monst *mtmp; |
365 | |
366 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) |
367 | if(mtmp->isshk && ESHK(mtmp)->shoproom == roomno |
368 | && ESHK(mtmp)->shoplevel == dlevel) { |
369 | shopkeeper = mtmp; |
370 | bill = &(ESHK(shopkeeper)->bill[0]); |
371 | shlevel = dlevel; |
372 | if(ANGRY(shopkeeper) && |
373 | strncmp(ESHK(shopkeeper)->customer,plname,PL_NSIZ)) |
374 | NOTANGRY(shopkeeper) = 1; |
375 | |
376 | |
377 | return; |
378 | } |
379 | shopkeeper = 0; |
380 | shlevel = 0; |
381 | bill = (struct bill_x *) -1000; |
382 | } |
383 | |
384 | static struct bill_x * |
385 | onbill(struct obj *obj) |
386 | { |
387 | struct bill_x *bp; |
388 | |
389 | if(!shopkeeper) return(NULL); |
390 | for(bp = bill; bp < &bill[ESHK(shopkeeper)->billct]; bp++) |
391 | if(bp->bo_id == obj->o_id) { |
392 | if(!obj->unpaid) pline("onbill: paid obj on bill?"); |
393 | return(bp); |
394 | } |
395 | if(obj->unpaid) pline("onbill: unpaid obj not on bill?"); |
396 | return(NULL); |
397 | } |
398 | |
399 | |
400 | void |
401 | obfree(struct obj *obj, struct obj *merge) |
402 | { |
403 | struct bill_x *bp = onbill(obj); |
404 | struct bill_x *bpm; |
405 | |
406 | if(bp) { |
407 | if(!merge){ |
408 | bp->useup = 1; |
409 | obj->unpaid = 0; |
410 | obj->nobj = billobjs; |
411 | billobjs = obj; |
412 | return; |
413 | } |
414 | bpm = onbill(merge); |
415 | if(!bpm){ |
416 | |
417 | impossible("obfree: not on bill??"); |
418 | return; |
419 | } else { |
420 | |
421 | bpm->bquan += bp->bquan; |
422 | ESHK(shopkeeper)->billct--; |
423 | *bp = bill[ESHK(shopkeeper)->billct]; |
424 | } |
425 | } |
426 | free(obj); |
427 | } |
428 | |
429 | static void |
430 | pay(long tmp, struct monst *shkp) |
431 | { |
432 | long robbed = ESHK(shkp)->robbed; |
433 | |
434 | u.ugold -= tmp; |
435 | shkp->mgold += tmp; |
436 | flags.botl = 1; |
437 | if(robbed) { |
438 | robbed -= tmp; |
439 | if(robbed < 0) robbed = 0; |
440 | ESHK(shkp)->robbed = robbed; |
441 | } |
442 | } |
443 | |
444 | int |
445 | dopay(void) |
446 | { |
447 | long ltmp; |
448 | struct bill_x *bp; |
449 | struct monst *shkp; |
450 | int pass, tmp; |
451 | |
452 | multi = 0; |
453 | (void) inshop(); |
454 | for(shkp = fmon; shkp; shkp = shkp->nmon) |
455 | if(shkp->isshk && dist(shkp->mx,shkp->my) < 3) |
456 | break; |
457 | if(!shkp && u.uinshop && |
458 | inroom(shopkeeper->mx,shopkeeper->my) == ESHK(shopkeeper)->shoproom) |
459 | shkp = shopkeeper; |
460 | |
461 | if(!shkp) { |
462 | pline("There is nobody here to receive your payment."); |
463 | return(0); |
464 | } |
465 | ltmp = ESHK(shkp)->robbed; |
466 | if(shkp != shopkeeper && NOTANGRY(shkp)) { |
467 | if(!ltmp) { |
468 | pline("You do not owe %s anything.", monnam(shkp)); |
469 | } else |
470 | if(!u.ugold) { |
471 | pline("You have no money."); |
472 | } else { |
473 | long ugold = u.ugold; |
474 | |
475 | if(u.ugold > ltmp) { |
476 | pline("You give %s the %ld gold pieces he asked for.", |
477 | monnam(shkp), ltmp); |
478 | pay(ltmp, shkp); |
479 | } else { |
480 | pline("You give %s all your gold.", monnam(shkp)); |
481 | pay(u.ugold, shkp); |
482 | } |
483 | if(ugold < ltmp/2) { |
484 | pline("Unfortunately, he doesn't look satisfied."); |
485 | } else { |
486 | ESHK(shkp)->robbed = 0; |
487 | ESHK(shkp)->following = 0; |
488 | if(ESHK(shkp)->shoplevel != dlevel) { |
489 | |
490 | shkp->minvent = 0; |
491 | shkp->mgold = 0; |
492 | mondead(shkp); |
493 | } |
494 | } |
495 | } |
496 | return(1); |
497 | } |
498 | |
499 | if(!ESHK(shkp)->billct){ |
500 | pline("You do not owe %s anything.", monnam(shkp)); |
501 | if(!u.ugold){ |
502 | pline("Moreover, you have no money."); |
503 | return(1); |
504 | } |
505 | if(ESHK(shkp)->robbed){ |
506 | #define min(a,b) ((a<b)?a:b) |
507 | pline("But since his shop has been robbed recently,"); |
508 | pline("you %srepay %s's expenses.", |
509 | (u.ugold < ESHK(shkp)->robbed) ? "partially " : "", |
510 | monnam(shkp)); |
511 | pay(min(u.ugold, ESHK(shkp)->robbed), shkp); |
512 | ESHK(shkp)->robbed = 0; |
513 | return(1); |
514 | } |
515 | if(ANGRY(shkp)){ |
516 | pline("But in order to appease %s,", |
517 | amonnam(shkp, "angry")); |
518 | if(u.ugold >= 1000){ |
519 | ltmp = 1000; |
520 | pline(" you give him 1000 gold pieces."); |
521 | } else { |
522 | ltmp = u.ugold; |
523 | pline(" you give him all your money."); |
524 | } |
525 | pay(ltmp, shkp); |
526 | if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ) |
527 | || rn2(3)){ |
528 | pline("%s calms down.", Monnam(shkp)); |
529 | NOTANGRY(shkp) = 1; |
530 | } else pline("%s is as angry as ever.", |
531 | Monnam(shkp)); |
532 | } |
533 | return(1); |
534 | } |
535 | if(shkp != shopkeeper) { |
536 | impossible("dopay: not to shopkeeper?"); |
537 | if(shopkeeper) setpaid(); |
538 | return(0); |
539 | } |
540 | for(pass = 0; pass <= 1; pass++) { |
541 | tmp = 0; |
542 | while(tmp < ESHK(shopkeeper)->billct) { |
543 | bp = &bill[tmp]; |
544 | if(!pass && !bp->useup) { |
545 | tmp++; |
546 | continue; |
547 | } |
548 | if(!dopayobj(bp)) return(1); |
549 | bill[tmp] = bill[--ESHK(shopkeeper)->billct]; |
550 | } |
551 | } |
552 | pline("Thank you for shopping in %s's %s store!", |
553 | shkname(shopkeeper), |
554 | shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8]); |
555 | NOTANGRY(shopkeeper) = 1; |
556 | return(1); |
557 | } |
558 | |
559 | |
560 | |
561 | |
562 | static int |
563 | dopayobj(struct bill_x *bp) |
564 | { |
565 | struct obj *obj; |
566 | long ltmp; |
567 | |
568 | |
569 | obj = bp_to_obj(bp); |
570 | |
571 | if(!obj) { |
572 | impossible("Shopkeeper administration out of order."); |
573 | setpaid(); |
574 | return(0); |
575 | } |
576 | |
577 | if(!obj->unpaid && !bp->useup){ |
578 | impossible("Paid object on bill??"); |
579 | return(1); |
580 | } |
581 | obj->unpaid = 0; |
582 | ltmp = bp->price * bp->bquan; |
583 | if(ANGRY(shopkeeper)) ltmp += ltmp/3; |
584 | if(u.ugold < ltmp){ |
585 | pline("You don't have gold enough to pay %s.", |
586 | doname(obj)); |
587 | obj->unpaid = 1; |
588 | return(0); |
589 | } |
590 | pay(ltmp, shopkeeper); |
591 | pline("You bought %s for %ld gold piece%s.", |
592 | doname(obj), ltmp, plur(ltmp)); |
593 | if(bp->useup) { |
594 | struct obj *otmp = billobjs; |
595 | if(obj == billobjs) |
596 | billobjs = obj->nobj; |
597 | else { |
598 | while(otmp && otmp->nobj != obj) otmp = otmp->nobj; |
599 | if(otmp) otmp->nobj = obj->nobj; |
600 | else pline("Error in shopkeeper administration."); |
601 | } |
602 | free(obj); |
603 | } |
604 | return(1); |
605 | } |
606 | |
607 | |
608 | void |
609 | paybill(void) |
610 | { |
611 | if(shlevel == dlevel && shopkeeper && ESHK(shopkeeper)->billct){ |
612 | addupbill(); |
613 | if(total > u.ugold){ |
614 | shopkeeper->mgold += u.ugold; |
615 | u.ugold = 0; |
616 | pline("%s comes and takes all your possessions.", |
617 | Monnam(shopkeeper)); |
618 | } else { |
619 | u.ugold -= total; |
620 | shopkeeper->mgold += total; |
621 | pline("%s comes and takes the %ld zorkmids you owed him.", |
622 | Monnam(shopkeeper), total); |
623 | } |
624 | setpaid(); |
625 | } |
626 | } |
627 | |
628 | |
629 | static struct obj * |
630 | bp_to_obj(struct bill_x *bp) |
631 | { |
632 | struct obj *obj; |
633 | struct monst *mtmp; |
634 | unsigned id = bp->bo_id; |
635 | |
636 | if(bp->useup) |
637 | obj = o_on(id, billobjs); |
638 | else if(!(obj = o_on(id, invent)) && |
639 | !(obj = o_on(id, fobj)) && |
640 | !(obj = o_on(id, fcobj))) { |
641 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) |
642 | if ((obj = o_on(id, mtmp->minvent))) |
643 | break; |
644 | for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon) |
645 | if ((obj = o_on(id, mtmp->minvent))) |
646 | break; |
647 | } |
648 | return(obj); |
649 | } |
650 | |
651 | |
652 | void |
653 | addtobill(struct obj *obj) |
654 | { |
655 | struct bill_x *bp; |
656 | |
657 | if(!inshop() || |
658 | (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) || |
659 | (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y) || |
660 | onbill(obj) |
661 | ) return; |
662 | if(ESHK(shopkeeper)->billct == BILLSZ){ |
663 | pline("You got that for free!"); |
664 | return; |
665 | } |
666 | bp = &bill[ESHK(shopkeeper)->billct]; |
667 | bp->bo_id = obj->o_id; |
668 | bp->bquan = obj->quan; |
669 | bp->useup = 0; |
670 | bp->price = getprice(obj); |
671 | ESHK(shopkeeper)->billct++; |
672 | obj->unpaid = 1; |
673 | } |
674 | |
675 | void |
676 | splitbill(struct obj *obj, struct obj *otmp) |
677 | { |
678 | |
679 | struct bill_x *bp; |
680 | int tmp; |
681 | bp = onbill(obj); |
682 | if(!bp) { |
683 | impossible("splitbill: not on bill?"); |
684 | return; |
685 | } |
686 | if(bp->bquan < otmp->quan) { |
687 | impossible("Negative quantity on bill??"); |
688 | } |
689 | if(bp->bquan == otmp->quan) { |
690 | impossible("Zero quantity on bill??"); |
691 | } |
692 | bp->bquan -= otmp->quan; |
693 | |
694 | |
695 | if(ESHK(shopkeeper)->billct == BILLSZ) otmp->unpaid = 0; |
696 | else { |
697 | tmp = bp->price; |
698 | bp = &bill[ESHK(shopkeeper)->billct]; |
699 | bp->bo_id = otmp->o_id; |
700 | bp->bquan = otmp->quan; |
701 | bp->useup = 0; |
702 | bp->price = tmp; |
703 | ESHK(shopkeeper)->billct++; |
704 | } |
705 | } |
706 | |
707 | void |
708 | subfrombill(struct obj *obj) |
709 | { |
710 | long ltmp; |
711 | int tmp; |
712 | struct obj *otmp; |
713 | struct bill_x *bp; |
714 | |
715 | if(!inshop() || (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) || |
716 | (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y)) |
717 | return; |
718 | if((bp = onbill(obj)) != 0){ |
719 | obj->unpaid = 0; |
720 | if(bp->bquan > obj->quan){ |
721 | otmp = newobj(0); |
722 | *otmp = *obj; |
723 | bp->bo_id = otmp->o_id = flags.ident++; |
724 | otmp->quan = (bp->bquan -= obj->quan); |
725 | otmp->owt = 0; |
726 | otmp->onamelth = 0; |
727 | bp->useup = 1; |
728 | otmp->nobj = billobjs; |
729 | billobjs = otmp; |
730 | return; |
731 | } |
732 | ESHK(shopkeeper)->billct--; |
733 | *bp = bill[ESHK(shopkeeper)->billct]; |
734 | return; |
735 | } |
736 | if(obj->unpaid){ |
737 | pline("%s didn't notice.", Monnam(shopkeeper)); |
738 | obj->unpaid = 0; |
739 | return; |
740 | } |
741 | |
742 | if(shopkeeper->msleep || shopkeeper->mfroz || |
743 | inroom(shopkeeper->mx,shopkeeper->my) != ESHK(shopkeeper)->shoproom) |
744 | return; |
745 | if(ESHK(shopkeeper)->billct == BILLSZ || |
746 | ((tmp = shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype-8]) && tmp != obj->olet) |
747 | || strchr("_0", obj->olet)) { |
748 | pline("%s seems not interested.", Monnam(shopkeeper)); |
749 | return; |
750 | } |
751 | ltmp = getprice(obj) * obj->quan; |
752 | if(ANGRY(shopkeeper)) { |
753 | ltmp /= 3; |
754 | NOTANGRY(shopkeeper) = 1; |
755 | } else ltmp /= 2; |
756 | if(ESHK(shopkeeper)->robbed){ |
757 | if((ESHK(shopkeeper)->robbed -= ltmp) < 0) |
758 | ESHK(shopkeeper)->robbed = 0; |
759 | pline("Thank you for your contribution to restock this recently plundered shop."); |
760 | return; |
761 | } |
762 | if(ltmp > shopkeeper->mgold) |
763 | ltmp = shopkeeper->mgold; |
764 | pay(-ltmp, shopkeeper); |
765 | if(!ltmp) |
766 | pline("%s gladly accepts %s but cannot pay you at present.", |
767 | Monnam(shopkeeper), doname(obj)); |
768 | else |
769 | pline("You sold %s and got %ld gold piece%s.", doname(obj), ltmp, |
770 | plur(ltmp)); |
771 | } |
772 | |
773 | |
774 | int |
775 | doinvbill(int mode) |
776 | { |
777 | struct bill_x *bp; |
778 | struct obj *obj; |
779 | long totused, thisused; |
780 | char buf[BUFSZ]; |
781 | |
782 | if(mode == 0) { |
783 | int cnt = 0; |
784 | |
785 | if(shopkeeper) |
786 | for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) |
787 | if(bp->useup || |
788 | ((obj = bp_to_obj(bp)) && obj->quan < bp->bquan)) |
789 | cnt++; |
790 | return(cnt); |
791 | } |
792 | |
793 | if(!shopkeeper) { |
794 | impossible("doinvbill: no shopkeeper?"); |
795 | return(0); |
796 | } |
797 | |
798 | set_pager(0); |
799 | if(page_line("Unpaid articles already used up:") || page_line("")) |
800 | goto quit; |
801 | |
802 | totused = 0; |
803 | for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) { |
804 | obj = bp_to_obj(bp); |
805 | if(!obj) { |
806 | impossible("Bad shopkeeper administration."); |
807 | goto quit; |
808 | } |
809 | if(bp->useup || bp->bquan > obj->quan) { |
810 | int cnt, oquan, uquan; |
811 | |
812 | oquan = obj->quan; |
813 | uquan = (bp->useup ? bp->bquan : bp->bquan - oquan); |
814 | thisused = bp->price * uquan; |
815 | totused += thisused; |
816 | obj->quan = uquan; |
817 | (void) snprintf(buf, sizeof buf, "x - %s", doname(obj)); |
818 | obj->quan = oquan; |
819 | for(cnt = 0; buf[cnt]; cnt++); |
820 | while(cnt < 50) |
821 | buf[cnt++] = ' '; |
822 | (void) snprintf(&buf[cnt], sizeof buf - cnt, |
823 | " %5ld zorkmids", thisused); |
824 | if(page_line(buf)) |
825 | goto quit; |
826 | } |
827 | } |
828 | (void) snprintf(buf, sizeof buf, "Total:%50ld zorkmids", totused); |
829 | if(page_line("") || page_line(buf)) |
830 | goto quit; |
831 | set_pager(1); |
832 | return(0); |
833 | quit: |
834 | set_pager(2); |
835 | return(0); |
836 | } |
837 | |
838 | static int |
839 | getprice(struct obj *obj) |
840 | { |
841 | int tmp, ac; |
842 | |
843 | switch(obj->olet){ |
844 | case AMULET_SYM: |
845 | tmp = 10*rnd(500); |
846 | break; |
847 | case TOOL_SYM: |
848 | tmp = 10*rnd((obj->otyp == EXPENSIVE_CAMERA) ? 150 : 30); |
849 | break; |
850 | case RING_SYM: |
851 | tmp = 10*rnd(100); |
852 | break; |
853 | case WAND_SYM: |
854 | tmp = 10*rnd(100); |
855 | break; |
856 | case SCROLL_SYM: |
857 | tmp = 10*rnd(50); |
858 | #ifdef MAIL |
859 | if(obj->otyp == SCR_MAIL) |
860 | tmp = rnd(5); |
861 | #endif /* MAIL */ |
862 | break; |
863 | case POTION_SYM: |
864 | tmp = 10*rnd(50); |
865 | break; |
866 | case FOOD_SYM: |
867 | tmp = 10*rnd(5 + (2000/realhunger())); |
868 | break; |
869 | case GEM_SYM: |
870 | tmp = 10*rnd(20); |
871 | break; |
872 | case ARMOR_SYM: |
873 | ac = ARM_BONUS(obj); |
874 | if(ac <= -10) |
875 | ac = -9; |
876 | tmp = 100 + ac*ac*rnd(10+ac); |
877 | break; |
878 | case WEAPON_SYM: |
879 | if(obj->otyp < BOOMERANG) |
880 | tmp = 5*rnd(10); |
881 | else if(obj->otyp == LONG_SWORD || |
882 | obj->otyp == TWO_HANDED_SWORD) |
883 | tmp = 10*rnd(150); |
884 | else tmp = 10*rnd(75); |
885 | break; |
886 | case CHAIN_SYM: |
887 | pline("Strange ..., carrying a chain?"); |
888 | case BALL_SYM: |
889 | tmp = 10; |
890 | break; |
891 | default: |
892 | tmp = 10000; |
893 | } |
894 | return(tmp); |
895 | } |
896 | |
897 | |
898 | static int |
899 | realhunger(void) |
900 | { |
901 | int tmp = u.uhunger; |
902 | struct obj *otmp = invent; |
903 | |
904 | while(otmp){ |
905 | if(otmp->olet == FOOD_SYM && !otmp->unpaid) |
906 | tmp += objects[otmp->otyp].nutrition; |
907 | otmp = otmp->nobj; |
908 | } |
909 | return((tmp <= 0) ? 1 : tmp); |
910 | } |
911 | |
912 | int |
913 | shkcatch(struct obj *obj) |
914 | { |
915 | struct monst *shkp = shopkeeper; |
916 | |
917 | if(u.uinshop && shkp && !shkp->mfroz && !shkp->msleep && |
918 | u.dx && u.dy && |
919 | inroom(u.ux+u.dx, u.uy+u.dy) + 1 == u.uinshop && |
920 | shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y && |
921 | u.ux == ESHK(shkp)->shd.x && u.uy == ESHK(shkp)->shd.y) { |
922 | pline("%s nimbly catches the %s.", Monnam(shkp), xname(obj)); |
923 | obj->nobj = shkp->minvent; |
924 | shkp->minvent = obj; |
925 | return(1); |
926 | } |
927 | return(0); |
928 | } |
929 | |
930 | |
931 | |
932 | |
933 | int |
934 | shk_move(struct monst *shkp) |
935 | { |
936 | struct monst *mtmp; |
937 | struct permonst *mdat = shkp->data; |
938 | xchar gx,gy,omx,omy,nx,ny,nix,niy; |
939 | schar appr,i; |
940 | int udist; |
941 | int z; |
942 | schar shkroom,chi,chcnt,cnt; |
943 | boolean uondoor, satdoor, avoid, badinv; |
| 1 | 'uondoor' declared without an initial value | |
|
944 | coord poss[9]; |
945 | int info[9]; |
946 | struct obj *ib = 0; |
947 | |
948 | omx = shkp->mx; |
949 | omy = shkp->my; |
950 | |
951 | if((udist = dist(omx,omy)) < 3) { |
| 2 | | Assuming the condition is false | |
|
| |
952 | if(ANGRY(shkp)) { |
953 | (void) hitu(shkp, d(mdat->damn, mdat->damd)+1); |
954 | return(0); |
955 | } |
956 | if(ESHK(shkp)->following) { |
957 | if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)){ |
958 | pline("Hello %s! I was looking for %s.", |
959 | plname, ESHK(shkp)->customer); |
960 | ESHK(shkp)->following = 0; |
961 | return(0); |
962 | } |
963 | if(!ESHK(shkp)->robbed) { |
964 | ESHK(shkp)->following = 0; |
965 | return(0); |
966 | } |
967 | if(moves > followmsg+4) { |
968 | pline("Hello %s! Didn't you forget to pay?", |
969 | plname); |
970 | followmsg = moves; |
971 | } |
972 | if(udist < 2) |
973 | return(0); |
974 | } |
975 | } |
976 | |
977 | shkroom = inroom(omx,omy); |
978 | appr = 1; |
979 | gx = ESHK(shkp)->shk.x; |
980 | gy = ESHK(shkp)->shk.y; |
981 | satdoor = (gx == omx && gy == omy); |
| 4 | | Assuming 'gx' is not equal to 'omx' | |
|
982 | if(ESHK(shkp)->following || ((z = holetime()) >= 0 && z*z <= udist)){ |
| 5 | | Assuming field 'following' is 0 | |
|
| 6 | | Assuming the condition is false | |
|
983 | gx = u.ux; |
984 | gy = u.uy; |
985 | if(shkroom < 0 || shkroom != inroom(u.ux,u.uy)) |
986 | if(udist > 4) |
987 | return(-1); |
988 | } else if(ANGRY(shkp)) { |
| 7 | | Assuming field 'mpeaceful' is not equal to 0 | |
|
| |
989 | long saveBlind = Blind; |
990 | Blind = 0; |
991 | if(shkp->mcansee && !Invis && cansee(omx,omy)) { |
992 | gx = u.ux; |
993 | gy = u.uy; |
994 | } |
995 | Blind = saveBlind; |
996 | avoid = FALSE; |
997 | } else { |
998 | #define GDIST(x,y) ((x-gx)*(x-gx)+(y-gy)*(y-gy)) |
999 | if(Invis) |
| 9 | | Assuming field 'p_flgs' is not equal to 0 | |
|
| |
1000 | avoid = FALSE; |
1001 | else { |
1002 | uondoor = (u.ux == ESHK(shkp)->shd.x && |
1003 | u.uy == ESHK(shkp)->shd.y); |
1004 | if(uondoor) { |
1005 | if(ESHK(shkp)->billct) |
1006 | pline("Hello %s! Will you please pay before leaving?", |
1007 | plname); |
1008 | badinv = (carrying(PICK_AXE) || carrying(ICE_BOX)); |
1009 | if(satdoor && badinv) |
1010 | return(0); |
1011 | avoid = !badinv; |
1012 | } else { |
1013 | avoid = (u.uinshop && dist(gx,gy) > 8); |
1014 | badinv = FALSE; |
1015 | } |
1016 | |
1017 | if(((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid) |
1018 | && GDIST(omx,omy) < 3){ |
1019 | if(!badinv && !online(omx,omy)) |
1020 | return(0); |
1021 | if(satdoor) |
1022 | appr = gx = gy = 0; |
1023 | } |
1024 | } |
1025 | } |
1026 | if(omx == gx && omy == gy) |
1027 | return(0); |
1028 | if(shkp->mconf) { |
| 11 | | Assuming field 'mconf' is 0 | |
|
| |
1029 | avoid = FALSE; |
1030 | appr = 0; |
1031 | } |
1032 | nix = omx; |
1033 | niy = omy; |
1034 | cnt = mfndpos(shkp,poss,info,ALLOW_SSM); |
1035 | if(avoid && uondoor) { |
1036 | for(i=0; i<cnt; i++) |
1037 | if(!(info[(int)i] & NOTONL)) goto notonl_ok; |
1038 | avoid = FALSE; |
1039 | notonl_ok: |
1040 | ; |
1041 | } |
1042 | chi = -1; |
1043 | chcnt = 0; |
1044 | for(i=0; i<cnt; i++){ |
| 13 | | Assuming 'i' is < 'cnt' | |
|
| 14 | | Loop condition is true. Entering loop body | |
|
1045 | nx = poss[(int)i].x; |
1046 | ny = poss[(int)i].y; |
1047 | if(levl[(int)nx][(int)ny].typ == ROOM |
| 15 | | Assuming field 'typ' is equal to ROOM | |
|
1048 | || shkroom != ESHK(shkp)->shoproom |
1049 | || ESHK(shkp)->following) { |
1050 | #ifdef STUPID |
1051 | |
1052 | int zz; |
1053 | #endif /* STUPID */ |
1054 | if(uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) { |
| 16 | | Branch condition evaluates to a garbage value |
|
1055 | nix = nx; niy = ny; chi = i; break; |
1056 | } |
1057 | if(avoid && (info[(int)i] & NOTONL)) |
1058 | continue; |
1059 | if((!appr && !rn2(++chcnt)) || |
1060 | #ifdef STUPID |
1061 | (appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny)) |
1062 | #else |
1063 | (appr && GDIST(nx,ny) < GDIST(nix,niy)) |
1064 | #endif /* STUPID */ |
1065 | ) { |
1066 | nix = nx; |
1067 | niy = ny; |
1068 | chi = i; |
1069 | } |
1070 | } |
1071 | } |
1072 | if(nix != omx || niy != omy){ |
1073 | if(info[(int)chi] & ALLOW_M){ |
1074 | mtmp = m_at(nix,niy); |
1075 | if(hitmm(shkp,mtmp) == 1 && rn2(3) && |
1076 | hitmm(mtmp,shkp) == 2) return(2); |
1077 | return(0); |
1078 | } else if(info[(int)chi] & ALLOW_U){ |
1079 | (void) hitu(shkp, d(mdat->damn, mdat->damd)+1); |
1080 | return(0); |
1081 | } |
1082 | shkp->mx = nix; |
1083 | shkp->my = niy; |
1084 | pmon(shkp); |
1085 | if(ib) { |
1086 | freeobj(ib); |
1087 | mpickobj(shkp, ib); |
1088 | } |
1089 | return(1); |
1090 | } |
1091 | return(0); |
1092 | } |
1093 | |
1094 | |
1095 | void |
1096 | shopdig(int fall) |
1097 | { |
1098 | if(!fall) { |
1099 | if(u.utraptype == TT_PIT) |
1100 | pline("\"Be careful, sir, or you might fall through the floor.\""); |
1101 | else |
1102 | pline("\"Please, do not damage the floor here.\""); |
1103 | } else if(dist(shopkeeper->mx, shopkeeper->my) < 3) { |
1104 | struct obj *obj, *obj2; |
1105 | |
1106 | pline("%s grabs your backpack!", shkname(shopkeeper)); |
1107 | for(obj = invent; obj; obj = obj2) { |
1108 | obj2 = obj->nobj; |
1109 | if(obj->owornmask) continue; |
1110 | freeinv(obj); |
1111 | obj->nobj = shopkeeper->minvent; |
1112 | shopkeeper->minvent = obj; |
1113 | if(obj->unpaid) |
1114 | subfrombill(obj); |
1115 | } |
1116 | } |
1117 | } |
1118 | #endif /* QUEST */ |
1119 | |
1120 | int |
1121 | online(int x, int y) |
1122 | { |
1123 | return(x==u.ux || y==u.uy || |
1124 | (x-u.ux)*(x-u.ux) == (y-u.uy)*(y-u.uy)); |
1125 | } |
1126 | |
1127 | |
1128 | int |
1129 | follower(struct monst *mtmp) |
1130 | { |
1131 | return( mtmp->mtame || strchr("1TVWZi&, ", mtmp->data->mlet) |
1132 | #ifndef QUEST |
1133 | || (mtmp->isshk && ESHK(mtmp)->following) |
1134 | #endif /* QUEST */ |
1135 | ); |
1136 | } |