put the object at the given location */
| 2302 | |
| 2303 | /* put the object at the given location */ |
| 2304 | void |
| 2305 | place_object(struct obj *otmp, coordxy x, coordxy y) |
| 2306 | { |
| 2307 | struct obj *otmp2; |
| 2308 | |
| 2309 | if (!isok(x, y)) { /* validate location */ |
| 2310 | void (*func)(const char *, ...) PRINTF_F_PTR(1, 2); |
| 2311 | |
| 2312 | func = (x < 0 || y < 0 || x > COLNO - 1 || y > ROWNO - 1) ? panic |
| 2313 | : impossible; |
| 2314 | (*func)("place_object: \"%s\" [%d] off map <%d,%d>", |
| 2315 | safe_typename(otmp->otyp), otmp->where, x, y); |
| 2316 | |
| 2317 | /* we'll only get to here if we've issued a warning (and fuzzer |
| 2318 | is not running since it escalates impossible to panic), so |
| 2319 | x,y has failed isok() but is within array bounds for the map; |
| 2320 | in other words, x specifies column 0 which should not happen |
| 2321 | but we let the game keep going */ |
| 2322 | } |
| 2323 | if (otmp->where != OBJ_FREE) |
| 2324 | panic("place_object: obj \"%s\" [%d] not free", |
| 2325 | safe_typename(otmp->otyp), otmp->where); |
| 2326 | |
| 2327 | assert(x >= 0 && x < COLNO && y >= 0 && y < ROWNO); |
| 2328 | otmp2 = svl.level.objects[x][y]; |
| 2329 | |
| 2330 | obj_no_longer_held(otmp); |
| 2331 | if (otmp->otyp == BOULDER) { |
| 2332 | if (!otmp2 || otmp2->otyp != BOULDER) |
| 2333 | block_point(x, y); /* vision */ |
| 2334 | } |
| 2335 | |
| 2336 | /* non-boulder object goes under boulders so that map will show boulder |
| 2337 | here without display code needing to traverse pile chain to find one */ |
| 2338 | if (otmp2 && otmp2->otyp == BOULDER && otmp->otyp != BOULDER) { |
| 2339 | /* 3.6.3: put otmp under last consecutive boulder rather than under |
| 2340 | just the first one */ |
| 2341 | while (otmp2->nexthere && otmp2->nexthere->otyp == BOULDER) |
| 2342 | otmp2 = otmp2->nexthere; |
| 2343 | otmp->nexthere = otmp2->nexthere; |
| 2344 | otmp2->nexthere = otmp; |
| 2345 | } else { |
| 2346 | /* put on top of current pile */ |
| 2347 | otmp->nexthere = otmp2; |
| 2348 | svl.level.objects[x][y] = otmp; |
| 2349 | } |
| 2350 | |
| 2351 | /* set the object's new location */ |
| 2352 | otmp->ox = x; |
| 2353 | otmp->oy = y; |
| 2354 | otmp->where = OBJ_FLOOR; |
| 2355 | |
| 2356 | /* if placed outside of shop, no_charge is no longer applicable */ |
| 2357 | if (otmp->no_charge && !costly_spot(x, y) |
| 2358 | && !costly_adjacent(find_objowner(otmp, x, y), x, y)) |
| 2359 | otmp->no_charge = 0; |
| 2360 | |
| 2361 | /* add to floor chain */ |
no test coverage detected