void top_level_diversion::output(node *nd, int retain_size, vunits vs, vunits post_vs, hunits width) { no_space_mode = 0; vunits next_trap_pos; trap *next_trap = find_next_trap(&next_trap_pos); if (before_first_page && begin_page()) fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); vertical_size v(vs, post_vs); for (node *tem = nd; tem != 0; tem = tem->next) tem->set_vertical_size(&v); last_post_line_extra_space = v.post_extra.to_units(); if (!retain_size) { v.pre = vs; v.post = post_vs; } vertical_position += v.pre; vertical_position += v.pre_extra; the_output->print_line(page_offset, vertical_position, nd, v.pre + v.pre_extra, v.post_extra, width); vertical_position += v.post_extra; if (vertical_position > high_water_mark) high_water_mark = vertical_position; if (vertical_position_traps_flag && vertical_position >= page_length) begin_page(); else if (vertical_position_traps_flag && next_trap != 0 && vertical_position >= next_trap_pos) { nl_reg_contents = vertical_position.to_units(); truncated_space = v.post; spring_trap(next_trap->nm); } else if (v.post > V0) { vertical_position += v.post; if (vertical_position_traps_flag && next_trap != 0 && vertical_position >= next_trap_pos) { truncated_space = vertical_position - next_trap_pos; vertical_position = next_trap_pos; nl_reg_contents = vertical_position.to_units(); spring_trap(next_trap->nm); } else if (vertical_position_traps_flag && vertical_position >= page_length) begin_page(); else nl_reg_contents = vertical_position.to_units(); } else nl_reg_contents = vertical_position.to_units(); }
void top_level_diversion::space(vunits n, int forced) { if (no_space_mode) { if (!forced) return; else no_space_mode = 0; } if (before_first_page) { begin_page(n); return; } vunits next_trap_pos; trap *next_trap = find_next_trap(&next_trap_pos); vunits y = vertical_position + n; if (curenv->get_vertical_spacing().to_units()) curenv->seen_space += n.to_units() / curenv->get_vertical_spacing().to_units(); if (vertical_position_traps_flag && next_trap != 0 && y >= next_trap_pos) { vertical_position = next_trap_pos; nl_reg_contents = vertical_position.to_units(); truncated_space = y - vertical_position; spring_trap(next_trap->nm); } else if (y < V0) { vertical_position = V0; nl_reg_contents = vertical_position.to_units(); } else if (vertical_position_traps_flag && y >= page_length && n >= V0) begin_page(y - page_length); else { vertical_position = y; nl_reg_contents = vertical_position.to_units(); } }
/** * Try to disarm a trap. * @param disarmer Player disarming the trap. * @param trap Trap to disarm. * @return 1 if trap was disarmed, 0 otherwise. */ int trap_disarm(object *disarmer, object *trap) { object *env = trap->env; int disarmer_level = CONTR(disarmer)->exp_ptr[EXP_AGILITY]->level; if ((trap->level <= disarmer_level && rndm_chance(10)) || !(rndm(0, (MAX(2, MIN(20, trap->level - disarmer_level + 5 - disarmer->stats.Dex / 2)) - 1)))) { new_draw_info_format(NDI_UNIQUE, disarmer, "You successfuly remove the %s (lvl %d)!", trap->name, trap->level); remove_ob(trap); check_walk_off(trap, NULL, MOVE_APPLY_VANISHED); set_trapped_flag(env); return 1; } else { new_draw_info_format(NDI_UNIQUE, disarmer, "You fail to remove the %s (lvl %d).", trap->name, trap->level); if (trap->level > disarmer_level * 1.4f || rndm(0, 2)) { if (!(rndm(0, (MAX(2, disarmer_level - trap->level + disarmer->stats.Dex / 2 - 6)) - 1))) { new_draw_info(NDI_UNIQUE, disarmer, "In fact, you set it off!"); spring_trap(trap, disarmer); } } return 0; } }
void macro_diversion::space(vunits n, int) { if (vertical_position_traps_flag && !diversion_trap.is_null() && diversion_trap_pos > vertical_position && diversion_trap_pos <= vertical_position + n) { truncated_space = vertical_position + n - diversion_trap_pos; n = diversion_trap_pos - vertical_position; spring_trap(diversion_trap); } else if (n + vertical_position < V0) n = -vertical_position; mac->append(new diverted_space_node(n)); vertical_position += n; }
// Returns non-zero if it sprung a top-of-page trap. // The optional parameter is for the .trunc register. int top_level_diversion::begin_page(vunits n) { if (exit_started) { if (page_count == last_page_count ? curenv->is_empty() : (done_end_macro && (seen_last_page_ejector || began_page_in_end_macro))) cleanup_and_exit(0); if (!done_end_macro) began_page_in_end_macro = 1; } if (last_page_number > 0 && page_number == last_page_number) cleanup_and_exit(0); if (!the_output) init_output(); ++page_count; if (have_next_page_number) { page_number = next_page_number; have_next_page_number = 0; } else if (before_first_page == 1) page_number = 1; else page_number++; // spring the top of page trap if there is one vunits next_trap_pos; vertical_position = -vresolution; trap *next_trap = find_next_trap(&next_trap_pos); vertical_position = V0; high_water_mark = V0; ejecting_page = 0; // If before_first_page was 2, then the top of page transition was undone // using eg .nr nl 0-1. See nl_reg::set_value. if (before_first_page != 2) the_output->begin_page(page_number, page_length); before_first_page = 0; nl_reg_contents = vertical_position.to_units(); if (vertical_position_traps_flag && next_trap != 0 && next_trap_pos == V0) { truncated_space = n; spring_trap(next_trap->nm); return 1; } else return 0; }
void macro_diversion::output(node *nd, int retain_size, vunits vs, vunits post_vs, hunits width) { no_space_mode = 0; vertical_size v(vs, post_vs); while (nd != 0) { nd->set_vertical_size(&v); node *temp = nd; nd = nd->next; if (temp->interpret(mac)) delete temp; else { #if 1 temp->freeze_space(); #endif mac->append(temp); } } last_post_line_extra_space = v.post_extra.to_units(); if (!retain_size) { v.pre = vs; v.post = post_vs; } if (width > max_width) max_width = width; vunits x = v.pre + v.pre_extra + v.post + v.post_extra; if (vertical_position_traps_flag && !diversion_trap.is_null() && diversion_trap_pos > vertical_position && diversion_trap_pos <= vertical_position + x) { vunits trunc = vertical_position + x - diversion_trap_pos; if (trunc > v.post) trunc = v.post; v.post -= trunc; x -= trunc; truncated_space = trunc; spring_trap(diversion_trap); } mac->append(new vertical_size_node(-v.pre)); mac->append(new vertical_size_node(v.post)); mac->append('\n'); vertical_position += x; if (vertical_position - v.post > high_water_mark) high_water_mark = vertical_position - v.post; }
/* * Check an object for a trap - Thoric */ ch_ret check_for_trap( char_data * ch, obj_data * obj, int flag ) { if( obj->contents.empty( ) ) return rNONE; ch_ret retcode = rNONE; list < obj_data * >::iterator iobj; for( iobj = obj->contents.begin( ); iobj != obj->contents.end( ); ++iobj ) { obj_data *check = *iobj; if( check->item_type == ITEM_TRAP && IS_SET( check->value[3], flag ) ) { retcode = spring_trap( ch, check ); if( retcode != rNONE ) return retcode; } } return retcode; }
/* * Check the room for a trap - Thoric */ ch_ret check_room_for_traps( char_data * ch, int flag ) { if( !ch ) return rERROR; if( !ch->in_room || ch->in_room->objects.empty( ) ) return rNONE; ch_ret retcode = rNONE; list < obj_data * >::iterator iobj; for( iobj = ch->in_room->objects.begin( ); iobj != ch->in_room->objects.end( ); ++iobj ) { obj_data *check = *iobj; if( check->item_type == ITEM_TRAP && IS_SET( check->value[3], flag ) ) { retcode = spring_trap( ch, check ); if( retcode != rNONE ) return retcode; } } return retcode; }
/** * 'victim' moves onto 'trap' (trap has FLAG_WALK_ON or FLAG_FLY_ON set) or * 'victim' leaves 'trap' (trap has FLAG_WALK_OFF or FLAG_FLY_OFF) set. * * I added the flags parameter to give the single events more information * about whats going on: * * Most important is the "MOVE_APPLY_VANISHED" flag. * If set, a object has left a tile but "vanished" and not moved (perhaps * it exploded or something). This means that some events are not * triggered like trapdoors or teleporter traps for example which have a * "FLY/MOVE_OFF" set. This will avoid that they touch invalid objects. * @param trap Object victim moved on. * @param victim The object that moved on trap. * @param originator Player, monster or other object that caused 'victim' * to move onto 'trap'. Will receive messages caused by this action. May * be NULL, however, some types of traps require an originator to * function. * @param flags Flags. */ void move_apply(object *trap, object *victim, object *originator, int flags) { static int recursion_depth = 0; /* move_apply() is the most likely candidate for causing unwanted and * possibly unlimited recursion. */ /* The following was changed because it was causing perfeclty correct * maps to fail. 1) it's not an error to recurse: * rune detonates, summoning monster. monster lands on nearby rune. * nearby rune detonates. This sort of recursion is expected and * proper. This code was causing needless crashes. */ if (recursion_depth >= 500) { LOG(llevDebug, "WARNING: move_apply(): aborting recursion [trap arch %s, name %s; victim arch %s, name %s]\n", trap->arch->name, trap->name, victim->arch->name, victim->name); return; } if (trap->head) { trap = trap->head; } /* Trigger the TRIGGER event */ if (trigger_event(EVENT_TRIGGER, victim, trap, originator, NULL, 0, 0, 0, SCRIPT_FIX_NOTHING)) { return; } recursion_depth++; switch (trap->type) { /* these objects can trigger other objects connected to them. * We need to check them at map loading time and other special * events to be sure to have a 100% working map state. */ case BUTTON: case PEDESTAL: update_button(trap); break; case TRIGGER_BUTTON: case TRIGGER_PEDESTAL: case TRIGGER_ALTAR: check_trigger(trap, victim); break; case CHECK_INV: check_inv(victim, trap); break; /* these objects trigger to but they are "instant". * We don't need to check them when loading. */ case ALTAR: /* sacrifice victim on trap */ apply_altar(trap, victim, originator); break; case CONVERTER: if (!(flags & MOVE_APPLY_VANISHED)) { convert_item(victim, trap); } break; case PLAYERMOVER: break; /* should be walk_on/fly_on only */ case SPINNER: if (victim->direction) { if ((victim->direction = victim->direction + trap->direction) > 8) { victim->direction = (victim->direction % 8) + 1; } update_turn_face(victim); } break; case DIRECTOR: if (victim->direction) { victim->direction = trap->direction; update_turn_face(victim); } break; /* no need to hit anything */ case MMISSILE: if (IS_LIVE(victim) && !(flags&MOVE_APPLY_VANISHED)) { tag_t trap_tag = trap->count; hit_player(victim, trap->stats.dam, trap, AT_MAGIC); if (!was_destroyed(trap, trap_tag)) { remove_ob(trap); } check_walk_off(trap, NULL, MOVE_APPLY_VANISHED); } break; case THROWN_OBJ: if (trap->inv == NULL || (flags & MOVE_APPLY_VANISHED)) { break; } /* fallthrough */ case ARROW: /* bad bug: monster throw a object, make a step forwards, step on object , * trigger this here and get hit by own missile - and will be own enemy. * Victim then is his own enemy and will start to kill herself (this is * removed) but we have not synced victim and his missile. To avoid senseless * action, we avoid hits here */ if ((IS_LIVE(victim) && trap->speed) && trap->owner != victim) { hit_with_arrow(trap, victim); } break; case CONE: case LIGHTNING: break; case BULLET: if ((QUERY_FLAG(victim, FLAG_NO_PASS) || IS_LIVE(victim)) && !(flags & MOVE_APPLY_VANISHED)) { check_fired_arch(trap); } break; case TRAPDOOR: { int max, sound_was_played; object *ab; if ((flags & MOVE_APPLY_VANISHED)) { break; } if (!trap->value) { sint32 tot; for (ab = trap->above, tot = 0; ab != NULL; ab = ab->above) { if (!QUERY_FLAG(ab, FLAG_FLYING)) { tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying; } } if (!(trap->value = (tot > trap->weight) ? 1 : 0)) { break; } SET_ANIMATION(trap, (NUM_ANIMATIONS(trap) / NUM_FACINGS(trap)) * trap->direction + trap->value); update_object(trap, UP_OBJ_FACE); } for (ab = trap->above, max = 100, sound_was_played = 0; --max && ab && !QUERY_FLAG(ab, FLAG_FLYING); ab = ab->above) { if (!sound_was_played) { play_sound_map(trap->map, trap->x, trap->y, SOUND_FALL_HOLE, SOUND_NORMAL); sound_was_played = 1; } if (ab->type == PLAYER) { new_draw_info(NDI_UNIQUE, ab, "You fall into a trapdoor!"); } transfer_ob(ab, EXIT_X(trap), EXIT_Y(trap), trap->last_sp, ab, trap); } break; } case PIT: /* Pit not open? */ if ((flags & MOVE_APPLY_VANISHED) || trap->stats.wc > 0) { break; } play_sound_map(victim->map, victim->x, victim->y, SOUND_FALL_HOLE, SOUND_NORMAL); if (victim->type == PLAYER) { new_draw_info(NDI_UNIQUE, victim, "You fall through the hole!\n"); } transfer_ob(victim->head ? victim->head : victim, EXIT_X(trap), EXIT_Y(trap), trap->last_sp, victim, trap); break; case EXIT: /* If no map path specified, we assume it is the map path of the exit. */ if (!EXIT_PATH(trap)) { FREE_AND_ADD_REF_HASH(EXIT_PATH(trap), trap->map->path); } if (!(flags & MOVE_APPLY_VANISHED) && victim->type == PLAYER && EXIT_PATH(trap) && EXIT_Y(trap) != -1 && EXIT_X(trap) != -1) { /* Basically, don't show exits leading to random maps the players output. */ if (trap->msg && strncmp(EXIT_PATH(trap), "/!", 2) && strncmp(EXIT_PATH(trap), "/random/", 8)) { new_draw_info(NDI_NAVY, victim, trap->msg); } enter_exit(victim, trap); } break; case SHOP_MAT: if (!(flags & MOVE_APPLY_VANISHED)) { apply_shop_mat(trap, victim); } break; /* Drop a certain amount of gold, and have one item identified */ case IDENTIFY_ALTAR: if (!(flags & MOVE_APPLY_VANISHED)) { apply_identify_altar(victim, trap, originator); } break; case SIGN: /* Only player should be able read signs */ if (victim->type == PLAYER) { apply_sign(victim, trap); } break; case CONTAINER: if (victim->type == PLAYER) { (void) esrv_apply_container(victim, trap); } break; case RUNE: if (!(flags & MOVE_APPLY_VANISHED) && trap->level && IS_LIVE(victim)) { spring_trap(trap, victim); } break; #if 0 /* we don't have this atm. */ case DEEP_SWAMP: if (!(flags & MOVE_APPLY_VANISHED)) { walk_on_deep_swamp(trap, victim); } break; #endif default: LOG(llevDebug, "name %s, arch %s, type %d with fly/walk on/off not handled in move_apply()\n", trap->name, trap->arch->name, trap->type); break; } recursion_depth--; }