/* Cheap hack of process_exit from overland.c for ships */ ch_ret process_shipexit( char_data * ch, short map, short x, short y, int dir ) { int sector = get_terrain( map, x, y ), move; room_index *from_room; ship_data *ship = ch->on_ship; ch_ret retcode; short fx, fy, fmap; from_room = ch->in_room; fx = ch->mx; fy = ch->my; fmap = ch->cmap; retcode = rNONE; if( ch->has_pcflag( PCFLAG_MAPEDIT ) ) { ch->print( "Get off the ship before you start editing.\r\n" ); return rSTOP; } if( sector == SECT_EXIT ) { mapexit_data *mexit; room_index *toroom = NULL; mexit = check_mapexit( map, x, y ); if( mexit != NULL ) { if( mexit->tomap != -1 ) /* Means exit goes to another map */ { if( !can_move_ship( ch, get_terrain( mexit->tomap, mexit->therex, mexit->therey ) ) ) return rSTOP; enter_map( ch, NULL, mexit->therex, mexit->therey, mexit->tomap ); if( ch->mount ) enter_map( ch->mount, NULL, mexit->therex, mexit->therey, mexit->tomap ); list < char_data * >::iterator ich; size_t chars = from_room->people.size( ); size_t count = 0; for( ich = from_room->people.begin( ); ich != from_room->people.end( ), ( count < chars ); ) { char_data *fch = *ich; ++ich; ++count; if( fch != ch /* loop room bug fix here by Thoric */ && fch->master == ch && ( fch->position == POS_STANDING || fch->position == POS_MOUNTED ) && fch->mx == fx && fch->my == fy && fch->cmap == fmap ) { if( !fch->isnpc( ) ) { act( AT_ACTION, "The ship sails $T.", fch, NULL, dir_name[dir], TO_CHAR ); process_exit( fch, fch->cmap, x, y, dir, false ); } else enter_map( fch, NULL, mexit->therex, mexit->therey, mexit->tomap ); } } return rSTOP; } if( !( toroom = get_room_index( mexit->vnum ) ) ) { bug( "%s: Target vnum %d for map exit does not exist!", __FUNCTION__, mexit->vnum ); ch->print( "Ooops. Something bad happened. Contact the immortals ASAP.\r\n" ); return rSTOP; } if( !can_move_ship( ch, toroom->sector_type ) ) return rSTOP; if( !str_cmp( ch->name, ship->owner ) ) act_printf( AT_ACTION, ch, NULL, dir_name[dir], TO_ROOM, "%s sails off to the $T.", ship->name.c_str( ) ); ch->on_ship->room = toroom->vnum; leave_map( ch, NULL, toroom ); list < char_data * >::iterator ich; size_t chars = from_room->people.size( ); size_t count = 0; for( ich = from_room->people.begin( ); ich != from_room->people.end( ), ( count < chars ); ) { char_data *fch = *ich; ++ich; ++count; if( fch != ch /* loop room bug fix here by Thoric */ && fch->master == ch && fch->position == POS_STANDING && fch->mx == fx && fch->my == fy && fch->cmap == fmap ) { if( !fch->isnpc( ) ) { act( AT_ACTION, "The ship sails $T.", fch, NULL, dir_name[dir], TO_CHAR ); process_shipexit( fch, fch->cmap, x, y, dir ); } else leave_map( fch, ch, toroom ); } } return rSTOP; } } switch ( dir ) { default: ch->print( "Alas, you cannot go that way...\r\n" ); return rSTOP; case DIR_NORTH: if( y == -1 ) { ch->print( "You cannot sail any further north!\r\n" ); return rSTOP; } break; case DIR_EAST: if( x == MAX_X ) { ch->print( "You cannot sail any further east!\r\n" ); return rSTOP; } break; case DIR_SOUTH: if( y == MAX_Y ) { ch->print( "You cannot sail any further south!\r\n" ); return rSTOP; } break; case DIR_WEST: if( x == -1 ) { ch->print( "You cannot sail any further west!\r\n" ); return rSTOP; } break; case DIR_NORTHEAST: if( x == MAX_X || y == -1 ) { ch->print( "You cannot sail any further northeast!\r\n" ); return rSTOP; } break; case DIR_NORTHWEST: if( x == -1 || y == -1 ) { ch->print( "You cannot sail any further northwest!\r\n" ); return rSTOP; } break; case DIR_SOUTHEAST: if( x == MAX_X || y == MAX_Y ) { ch->print( "You cannot sail any further southeast!\r\n" ); return rSTOP; } break; case DIR_SOUTHWEST: if( x == -1 || y == MAX_Y ) { ch->print( "You cannot sail any further southwest!\r\n" ); return rSTOP; } break; } if( !can_move_ship( ch, sector ) ) return rSTOP; move = sect_show[sector].move; if( ship->fuel < move && !ch->is_immortal( ) ) { ch->print( "Your ship is too low on magical energy to sail further ahead.\r\n" ); return rSTOP; } if( !ch->is_immortal( ) && !str_cmp( ch->name, ship->owner ) ) ship->fuel -= move; if( !str_cmp( ch->name, ship->owner ) ) act_printf( AT_ACTION, ch, NULL, dir_name[dir], TO_ROOM, "%s sails off to the $T.", ship->name.c_str( ) ); ch->mx = x; ch->my = y; ship->mx = x; ship->my = y; if( !str_cmp( ch->name, ship->owner ) ) { const char *txt = rev_exit( dir ); act_printf( AT_ACTION, ch, NULL, NULL, TO_ROOM, "%s sails in from the %s.", ship->name.c_str( ), txt ); } list < char_data * >::iterator ich; size_t chars = from_room->people.size( ); size_t count = 0; for( ich = from_room->people.begin( ); ich != from_room->people.end( ), ( count < chars ); ) { char_data *fch = *ich; ++ich; ++count; if( fch != ch /* loop room bug fix here by Thoric */ && fch->master == ch && ( fch->position == POS_STANDING || fch->position == POS_MOUNTED ) && fch->mx == fx && fch->my == fy ) { if( !fch->isnpc( ) ) { act( AT_ACTION, "The ship sails $T.", fch, NULL, dir_name[dir], TO_CHAR ); process_exit( fch, fch->cmap, x, y, dir, false ); } else { fch->mx = x; fch->my = y; } } } interpret( ch, "look" ); return retcode; }
/* Rehacked by Samson - had to clean up the mess */ ch_ret move_ship( char_data * ch, exit_data * pexit, int direction ) { ship_data *ship = ch->on_ship; ch_ret retcode; short door; int newx, newy, move; retcode = rNONE; if( ch->has_pcflag( PCFLAG_ONMAP ) || ch->has_actflag( ACT_ONMAP ) ) { newx = ch->mx; newy = ch->my; switch ( direction ) { default: break; case DIR_NORTH: newy = ch->my - 1; break; case DIR_EAST: newx = ch->mx + 1; break; case DIR_SOUTH: newy = ch->my + 1; break; case DIR_WEST: newx = ch->mx - 1; break; case DIR_NORTHEAST: newx = ch->mx + 1; newy = ch->my - 1; break; case DIR_NORTHWEST: newx = ch->mx - 1; newy = ch->my - 1; break; case DIR_SOUTHEAST: newx = ch->mx + 1; newy = ch->my + 1; break; case DIR_SOUTHWEST: newx = ch->mx - 1; newy = ch->my + 1; break; } if( newx == ch->mx && newy == ch->my ) return rSTOP; retcode = process_shipexit( ch, ch->cmap, newx, newy, direction ); return retcode; } room_index *in_room = ch->in_room; room_index *from_room = in_room; room_index *to_room; if( !pexit || !( to_room = pexit->to_room ) ) { ch->print( "Alas, you cannot sail that way.\r\n" ); check_sneaks( ch ); return rSTOP; } door = pexit->vdir; /* * Overland Map stuff - Samson 7-31-99 */ /* * Upgraded 4-28-00 to allow mounts and charmies to follow PC - Samson */ if( IS_EXIT_FLAG( pexit, EX_OVERLAND ) ) { if( pexit->mx < 0 || pexit->mx >= MAX_X || pexit->my < 0 || pexit->my >= MAX_Y ) { bug( "%s: Room #%d - Invalid exit coordinates: %d %d", __FUNCTION__, in_room->vnum, pexit->mx, pexit->my ); ch->print( "Oops. Something is wrong with this map exit - notify the immortals.\r\n" ); check_sneaks( ch ); return rSTOP; } if( !ch->isnpc( ) ) { enter_map( ch, pexit, pexit->mx, pexit->my, -1 ); if( ch->mount ) enter_map( ch->mount, pexit, pexit->mx, pexit->my, -1 ); list < char_data * >::iterator ich; size_t chars = from_room->people.size( ); size_t count = 0; for( ich = from_room->people.begin( ); ich != from_room->people.end( ), ( count < chars ); ) { char_data *fch = *ich; ++ich; ++count; if( fch != ch /* loop room bug fix here by Thoric */ && fch->master == ch && ( fch->position == POS_STANDING || fch->position == POS_MOUNTED ) ) { if( !fch->isnpc( ) ) { act( AT_ACTION, "The ship sails $T.", fch, NULL, dir_name[direction], TO_CHAR ); move_char( fch, pexit, 0, direction, false ); } else enter_map( fch, pexit, pexit->mx, pexit->my, -1 ); } } } else { if( !IS_EXIT_FLAG( pexit, EX_NOMOB ) ) { enter_map( ch, pexit, pexit->mx, pexit->my, -1 ); if( ch->mount ) enter_map( ch->mount, pexit, pexit->mx, pexit->my, -1 ); list < char_data * >::iterator ich; size_t chars = from_room->people.size( ); size_t count = 0; for( ich = from_room->people.begin( ); ich != from_room->people.end( ), ( count < chars ); ) { char_data *fch = *ich; ++ich; ++count; if( fch != ch /* loop room bug fix here by Thoric */ && fch->master == ch && ( fch->position == POS_STANDING || fch->position == POS_MOUNTED ) ) { if( !fch->isnpc( ) ) { act( AT_ACTION, "The ship sails $T.", fch, NULL, dir_name[direction], TO_CHAR ); move_char( fch, pexit, 0, direction, false ); } else enter_map( fch, pexit, pexit->mx, pexit->my, -1 ); } } } } check_sneaks( ch ); return rSTOP; } if( !can_move_ship( ch, pexit->to_room->sector_type ) ) { check_sneaks( ch ); return rSTOP; } if( IS_EXIT_FLAG( pexit, EX_PORTAL ) ) { ch->print( "You cannot sail a ship through that!!\r\n" ); check_sneaks( ch ); return rSTOP; } if( !ch->is_immortal( ) && !ch->isnpc( ) && ch->in_room->area != to_room->area ) { if( ch->level < to_room->area->low_hard_range ) { switch ( to_room->area->low_hard_range - ch->level ) { case 1: ch->print( "&[tell]A voice in your mind says, 'You are nearly ready to go that way...'\r\n" ); break; case 2: ch->print( "&[tell]A voice in your mind says, 'Soon you shall be ready to travel down this path... soon.'\r\n" ); break; case 3: ch->print( "&[tell]A voice in your mind says, 'You are not ready to go down that path... yet.'\r\n" ); break; default: ch->print( "&[tell]A voice in your mind says, 'You are not ready to go down that path.'\r\n" ); } check_sneaks( ch ); return rSTOP; } else if( ch->level > to_room->area->hi_hard_range ) { ch->print( "&[tell]A voice in your mind says, 'There is nothing more for you down that path.'" ); check_sneaks( ch ); return rSTOP; } } /* * Tunnels in water sectors only check for ships, not people since they're generally too small to matter */ if( to_room->tunnel > 0 ) { int count = 0; list < ship_data * >::iterator other; for( other = shiplist.begin( ); other != shiplist.end( ); ++other ) { ship_data *shp = *other; if( shp->room == to_room->vnum ) ++count; if( count >= to_room->tunnel ) { ch->print( "There are too many ships ahead to pass.\r\n" ); check_sneaks( ch ); return rSTOP; } } } move = sect_show[in_room->sector_type].move; if( ship->fuel < move && !ch->is_immortal( ) ) { ch->print( "Your ship is too low on magical energy to sail further ahead.\r\n" ); return rSTOP; } if( !str_cmp( ch->name, ship->owner ) && !ch->is_immortal( ) ) ship->fuel -= move; rprog_leave_trigger( ch ); if( ch->char_died( ) ) return global_retcode; if( !str_cmp( ch->name, ship->owner ) ) act_printf( AT_ACTION, ch, NULL, dir_name[door], TO_ROOM, "%s sails off to the $T.", ship->name.c_str( ) ); ch->from_room( ); if( ch->mount ) { rprog_leave_trigger( ch->mount ); if( ch->char_died( ) ) return global_retcode; if( ch->mount ) { ch->mount->from_room( ); if( !ch->mount->to_room( to_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __FUNCTION__, __LINE__ ); } } if( !ch->to_room( to_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __FUNCTION__, __LINE__ ); ship->room = to_room->vnum; check_sneaks( ch ); if( !str_cmp( ch->name, ship->owner ) ) { const char *txt = rev_exit( door ); act_printf( AT_ACTION, ch, NULL, NULL, TO_ROOM, "%s sails in from the %s.", ship->name.c_str( ), txt ); } list < char_data * >::iterator ich; size_t chars = from_room->people.size( ); size_t count = 0; for( ich = from_room->people.begin( ); ich != from_room->people.end( ), ( count < chars ); ) { char_data *fch = *ich; ++ich; ++count; if( fch != ch /* loop room bug fix here by Thoric */ && fch->master == ch && ( fch->position == POS_STANDING || fch->position == POS_MOUNTED ) ) { act( AT_ACTION, "The ship sails $T.", fch, NULL, dir_name[door], TO_CHAR ); move_char( fch, pexit, 0, direction, false ); } } interpret( ch, "look" ); return retcode; }
/* * Generic use ranged attack function -Thoric & Tricops */ ch_ret ranged_attack( char_data * ch, string argument, obj_data * weapon, obj_data * projectile, short dt, short range ) { string arg, arg1, temp; if( !argument.empty( ) && argument[0] == '\'' ) { one_argument( argument, temp ); argument = temp; } argument = one_argument( argument, arg ); argument = one_argument( argument, arg1 ); if( arg.empty( ) ) { ch->print( "Where? At who?\r\n" ); return rNONE; } /* * get an exit or a victim */ short dir = -1; exit_data *pexit; char_data *victim = nullptr; if( !( pexit = find_door( ch, arg, true ) ) ) { if( !( victim = ch->get_char_room( arg ) ) ) { ch->print( "Aim in what direction?\r\n" ); return rNONE; } else { if( ch->who_fighting( ) == victim ) { ch->print( "They are too close to release that type of attack!\r\n" ); return rNONE; } } } else dir = pexit->vdir; /* * check for ranged attacks from private rooms, etc */ if( !victim ) { if( ch->in_room->flags.test( ROOM_PRIVATE ) || ch->in_room->flags.test( ROOM_SOLITARY ) ) { ch->print( "You cannot perform a ranged attack from a private room.\r\n" ); return rNONE; } if( ch->in_room->tunnel > 0 ) { if( ( int )ch->in_room->people.size( ) >= ch->in_room->tunnel ) { ch->print( "This room is too cramped to perform such an attack.\r\n" ); return rNONE; } } } skill_type *skill = nullptr; if( IS_VALID_SN( dt ) ) skill = skill_table[dt]; if( pexit && !pexit->to_room ) { ch->print( "Are you expecting to fire through a wall!?\r\n" ); return rNONE; } /* * Check for obstruction */ if( pexit && IS_EXIT_FLAG( pexit, EX_CLOSED ) ) { if( IS_EXIT_FLAG( pexit, EX_SECRET ) || IS_EXIT_FLAG( pexit, EX_DIG ) ) ch->print( "Are you expecting to fire through a wall!?\r\n" ); else ch->print( "Are you expecting to fire through a door!?\r\n" ); return rNONE; } /* * Keeps em from firing through a wall but can still fire through an arrow slit or window, Marcus */ if( pexit ) { if( ( IS_EXIT_FLAG( pexit, EX_FORTIFIED ) || IS_EXIT_FLAG( pexit, EX_HEAVY ) || IS_EXIT_FLAG( pexit, EX_MEDIUM ) || IS_EXIT_FLAG( pexit, EX_LIGHT ) || IS_EXIT_FLAG( pexit, EX_CRUMBLING ) ) && !IS_EXIT_FLAG( pexit, EX_WINDOW ) && !IS_EXIT_FLAG( pexit, EX_ASLIT ) ) { ch->print( "Are you expecting to fire through a wall!?\r\n" ); return rNONE; } } char_data *vch = nullptr; if( pexit && !arg1.empty( ) ) { if( !( vch = scan_for_vic( ch, pexit, arg1 ) ) ) { ch->print( "You cannot see your target.\r\n" ); return rNONE; } /* * don't allow attacks on mobs that are in a no-missile room --Shaddai */ if( vch->in_room->flags.test( ROOM_NOMISSILE ) ) { ch->print( "You can't get a clean shot off.\r\n" ); return rNONE; } /* * can't properly target someone heavily in battle */ if( vch->num_fighting > MAX_FIGHT ) { ch->print( "There is too much activity there for you to get a clear shot.\r\n" ); return rNONE; } } if( vch ) { if( !vch->CAN_PKILL( ) || !ch->CAN_PKILL( ) ) { ch->print( "You can't do that!\r\n" ); return rNONE; } if( vch && is_safe( ch, vch ) ) return rNONE; } room_index *was_in_room = ch->in_room; const char *stxt = "burst of energy"; if( projectile ) { projectile->separate( ); if( pexit ) { if( weapon ) { act( AT_GREY, "You fire $p $T.", ch, projectile, dir_name[dir], TO_CHAR ); act( AT_GREY, "$n fires $p $T.", ch, projectile, dir_name[dir], TO_ROOM ); } else { act( AT_GREY, "You throw $p $T.", ch, projectile, dir_name[dir], TO_CHAR ); act( AT_GREY, "$n throw $p $T.", ch, projectile, dir_name[dir], TO_ROOM ); } } else { if( weapon ) { act( AT_GREY, "You fire $p at $N.", ch, projectile, victim, TO_CHAR ); act( AT_GREY, "$n fires $p at $N.", ch, projectile, victim, TO_NOTVICT ); act( AT_GREY, "$n fires $p at you!", ch, projectile, victim, TO_VICT ); } else { act( AT_GREY, "You throw $p at $N.", ch, projectile, victim, TO_CHAR ); act( AT_GREY, "$n throws $p at $N.", ch, projectile, victim, TO_NOTVICT ); act( AT_GREY, "$n throws $p at you!", ch, projectile, victim, TO_VICT ); } } } else if( skill ) { if( skill->noun_damage && skill->noun_damage[0] != '\0' ) stxt = skill->noun_damage; else stxt = skill->name; /* * a plain "spell" flying around seems boring */ if( !str_cmp( stxt, "spell" ) ) stxt = "magical burst of energy"; if( skill->type == SKILL_SPELL ) { if( pexit ) { act( AT_MAGIC, "You release $t $T.", ch, aoran( stxt ), dir_name[dir], TO_CHAR ); act( AT_MAGIC, "$n releases $s $t $T.", ch, stxt, dir_name[dir], TO_ROOM ); } else { act( AT_MAGIC, "You release $t at $N.", ch, aoran( stxt ), victim, TO_CHAR ); act( AT_MAGIC, "$n releases $s $t at $N.", ch, stxt, victim, TO_NOTVICT ); act( AT_MAGIC, "$n releases $s $t at you!", ch, stxt, victim, TO_VICT ); } } } else { bug( "%s: no projectile, no skill dt %d", __func__, dt ); return rNONE; } /* * victim in same room */ if( victim ) { check_illegal_pk( ch, victim ); check_attacker( ch, victim ); return ranged_got_target( ch, victim, weapon, projectile, 0, dt, stxt, AT_MAGIC ); } /* * assign scanned victim */ victim = vch; /* * reverse direction text from move_char */ const char *dtxt = rev_exit( pexit->vdir ); int dist = 0; while( dist <= range ) { ch->from_room( ); if( !ch->to_room( pexit->to_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ ); if( IS_EXIT_FLAG( pexit, EX_CLOSED ) ) { /* * whadoyahknow, the door's closed */ if( projectile ) ch->printf( "&wYou see your %s pierce a door in the distance to the %s.", projectile->myobj( ).c_str( ), dir_name[dir] ); else ch->printf( "&wYou see your %s hit a door in the distance to the %s.", stxt, dir_name[dir] ); if( projectile ) act_printf( AT_GREY, ch, projectile, nullptr, TO_ROOM, "$p flies in from %s and implants itself solidly in the %sern door.", dtxt, dir_name[dir] ); else act_printf( AT_GREY, ch, nullptr, nullptr, TO_ROOM, "%s flies in from %s and implants itself solidly in the %sern door.", aoran( stxt ), dtxt, dir_name[dir] ); break; } /* * no victim? pick a random one */ if( !victim ) { list < char_data * >::iterator ich; for( ich = ch->in_room->people.begin( ); ich != ch->in_room->people.end( ); ++ich ) { vch = *ich; if( ( ( ch->isnpc( ) && !vch->isnpc( ) ) || ( !ch->isnpc( ) && vch->isnpc( ) ) ) && number_bits( 1 ) == 0 ) { victim = vch; break; } } if( victim && is_safe( ch, victim ) ) { ch->from_room( ); if( !ch->to_room( was_in_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ ); return rNONE; } } /* * In the same room as our victim? */ if( victim && ch->in_room == victim->in_room ) { if( projectile ) act( AT_GREY, "$p flies in from $T.", ch, projectile, dtxt, TO_ROOM ); else act( AT_GREY, "$t flies in from $T.", ch, aoran( stxt ), dtxt, TO_ROOM ); /* * get back before the action starts */ ch->from_room( ); if( !ch->to_room( was_in_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ ); check_illegal_pk( ch, victim ); check_attacker( ch, victim ); return ranged_got_target( ch, victim, weapon, projectile, dist, dt, stxt, AT_GREY ); } if( dist == range ) { if( projectile ) { act( AT_GREY, "Your $t falls harmlessly to the ground to the $T.", ch, projectile->myobj( ).c_str( ), dir_name[dir], TO_CHAR ); act( AT_GREY, "$p flies in from $T and falls harmlessly to the ground here.", ch, projectile, dtxt, TO_ROOM ); if( projectile->in_obj ) projectile->from_obj( ); if( projectile->carried_by ) projectile->from_char( ); projectile->to_room( ch->in_room, ch ); } else { act( AT_MAGIC, "Your $t fizzles out harmlessly to the $T.", ch, stxt, dir_name[dir], TO_CHAR ); act( AT_MAGIC, "$t flies in from $T and fizzles out harmlessly.", ch, aoran( stxt ), dtxt, TO_ROOM ); } break; } if( !( pexit = ch->in_room->get_exit( dir ) ) ) { if( projectile ) { act( AT_GREY, "Your $t hits a wall and bounces harmlessly to the ground to the $T.", ch, projectile->myobj( ).c_str( ), dir_name[dir], TO_CHAR ); act( AT_GREY, "$p strikes the $Tsern wall and falls harmlessly to the ground.", ch, projectile, dir_name[dir], TO_ROOM ); if( projectile->in_obj ) projectile->from_obj( ); if( projectile->carried_by ) projectile->from_char( ); projectile->to_room( ch->in_room, ch ); } else { act( AT_MAGIC, "Your $t harmlessly hits a wall to the $T.", ch, stxt, dir_name[dir], TO_CHAR ); act( AT_MAGIC, "$t strikes the $Tsern wall and falls harmlessly to the ground.", ch, aoran( stxt ), dir_name[dir], TO_ROOM ); } break; } if( projectile ) act( AT_GREY, "$p flies in from $T.", ch, projectile, dtxt, TO_ROOM ); else act( AT_MAGIC, "$t flies in from $T.", ch, aoran( stxt ), dtxt, TO_ROOM ); ++dist; } ch->from_room( ); if( !ch->to_room( was_in_room ) ) log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ ); if( projectile->carried_by == ch ) projectile->extract( ); return rNONE; }