/// <summary> /// Updates the data in the window. We pass in a room and a direction /// because we may or may not change the data depending on whether we /// click OK or Cancel. /// </summary> /// <param name="room"></param> /// <param name="direction"></param> public void UpdateWindowContents(RoomTemplate room, Exit.Direction direction) { _room = room; _direction = direction; Exit exit = _room.ExitData[(int)direction]; if (exit != null) { lblEditStatus.Text = "Editing " + direction.ToString() + " exit in room " + room.IndexNumber.ToString() + "."; txtDescription.Text = exit.Description; txtFlags.Text = exit.ExitFlags.ToString(); txtKeyIndexNumber.Text = exit.Key.ToString(); txtKeyword.Text = exit.Keyword; txtIndexNumber.Text = exit.IndexNumber.ToString(); } else { lblEditStatus.Text = "Creating new " + direction.ToString() + " exit in room " + room.IndexNumber.ToString() + "."; } }
/// <summary> /// Movement function. Handles all processing related to walking/flying/moving from one room to another. /// </summary> /// <param name="door"></param> public void Move( Exit.Direction door ) { Exit exit; Room toRoom; Room target; Bitvector moved = PC.PLAYER_MOVED; string text; string text2; bool riding = false; bool disbelief = false; bool illusion = false; if (door == Exit.Direction.invalid) { return; } if( InRoom == null ) { Log.Trace( "Null from room in CharData.Move" ); SendText("There's nowhere for you to move from - you aren't anywhere!"); return; } // Prevents infinite move loop in maze zone when group has 2 leaders if (HasActionBit(moved)) { return; } if(IsAffected( Affect.AFFECT_MINOR_PARA ) || IsAffected( Affect.AFFECT_BOUND ) || IsAffected( Affect.AFFECT_HOLD ) ) { SendText( "You can't move!\r\n" ); return; } if (Riding && (Riding.IsAffected(Affect.AFFECT_BOUND) || Riding.IsAffected(Affect.AFFECT_HOLD) || Riding.IsAffected(Affect.AFFECT_MINOR_PARA))) { SendText( "Your ride can't move.\r\n" ); return; } // More likely to go NSEW than any other dirs if( IsAffected( Affect.AFFECT_MISDIRECTION ) ) { if (MUDMath.NumberRange(1, 2) == 1) { door = (Exit.Direction)MUDMath.NumberRange(0, 3); } else { door = Database.RandomDoor(); } } Room inRoom = InRoom; RemoveAffect(Affect.AFFECT_HIDE); if( !( exit = inRoom.GetExit(door)) || !( toRoom = Room.GetRoom(exit.IndexNumber) ) || ( toRoom.TerrainType == TerrainType.underground_impassable ) || ( toRoom.WorldmapTerrainType == ExtendedTerrain.EXT_ZONEMARKER ) || ( Level < Limits.LEVEL_AVATAR && ( exit.HasFlag( Exit.ExitFlag.secret ) || exit.HasFlag(Exit.ExitFlag.blocked)))) { SendText( "Alas, you cannot go that way.\r\n" ); return; } if( FlightLevel != 0 && !toRoom.IsFlyable() ) { SendText( "Alas, you cannot fly there.\r\n" ); return; } // For trapped objects in the room that trigger on certain actions foreach( Object obj in InRoom.Contents ) { if( obj.Trap == null ) continue; if( obj.Trap.CheckTrigger( Trap.TriggerType.move ) ) { SetOffTrap( obj ); if (CurrentPosition == Position.dead) { return; } } else if( door != Exit.Direction.invalid ) { if (obj.Trap.CheckTrigger(Movement.TrapDirectionFlag[(int)door])) { SetOffTrap( obj ); if (CurrentPosition == Position.dead) { return; } } } } // Being walled doesen't mean they can't go there, it just means that we // need to check for wall functions. if (!IsAffected(Affect.AFFECT_CLIMBING) && inRoom.ExitData[(int)door].HasFlag(Exit.ExitFlag.walled)) { foreach( Object wall in InRoom.Contents ) { if( wall.ItemType != ObjTemplate.ObjectType.wall || wall.Values[ 0 ] != (int)door ) continue; if( wall.ObjIndexData.IndexNumber == StaticObjects.OBJECT_NUMBER_WALL_ILLUSION ) { illusion = true; // Test for disbelief int dchance = GetCurrInt() / 2 + Level - wall.Values[ 2 ]; if( Fighting ) dchance /= 2; if( GetRace() == Race.RACE_OGRE || GetRace() == Race.RACE_CENTAUR ) dchance /= 4; if( MUDMath.NumberPercent() < dchance ) { // Disbelief SocketConnection.Act( "You disbelieve $p&n!", this, wall, null, SocketConnection.MessageTarget.character ); disbelief = true; } } if( wall.Values[ 1 ] == 0 && !disbelief ) { if( !illusion || CanSeeObj( this, wall ) ) { SocketConnection.Act("You bump into $p&n.", this, wall, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n bumps into $p&n.", this, wall, null, SocketConnection.MessageTarget.room); if( wall.ObjIndexData.IndexNumber == StaticObjects.OBJECT_NUMBER_WALL_ICE ) { Combat.InflictSpellDamage(this, this, MUDMath.Dice(2, (wall.Values[2] / 2)), "wall of ice", AttackType.DamageType.cold); if (CurrentPosition == Position.dead) return; } else if( wall.ObjIndexData.IndexNumber == StaticObjects.OBJECT_NUMBER_WALL_FORCE ) { CurrentMoves -= MUDMath.Dice( 2, 15 ); SendText( "You feel drained of energy!\r\n" ); SendText( "The force of the wall knocks you down!\r\n" ); CurrentPosition = Position.sitting; WaitState( MUDMath.Dice( 2, 9 ) ); } } //end if !illusion else { SendText( "Alas, you cannot go that way.\r\n" ); } return; } if( disbelief ) { SocketConnection.Act(StringConversion.WallDecayString(StaticObjects.OBJECT_NUMBER_WALL_ILLUSION), this, wall, null, SocketConnection.MessageTarget.all); wall.RemoveFromWorld(); inRoom.ExitData[ (int)door ].RemoveFlag( Exit.ExitFlag.walled ); } else if( !illusion ) { SocketConnection.Act("You just walked through $p&n.", this, wall, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n just walked through $p&n.", this, wall, null, SocketConnection.MessageTarget.room); if( wall.ObjIndexData.IndexNumber == StaticObjects.OBJECT_NUMBER_WALL_FIRE ) { Combat.InflictSpellDamage(this, this, MUDMath.Dice(wall.Values[2], 5), "wall of fire", AttackType.DamageType.fire); if (CurrentPosition == Position.dead) return; } else if( wall.ObjIndexData.IndexNumber == StaticObjects.OBJECT_NUMBER_WALL_SPARKS ) { Combat.InflictSpellDamage(this, this, MUDMath.Dice(3, wall.Values[2]), "wall of sparks", AttackType.DamageType.fire); if (CurrentPosition == Position.dead) return; } else if( wall.ObjIndexData.IndexNumber == StaticObjects.OBJECT_NUMBER_LIGHTNING_CURTAIN ) { Combat.InflictSpellDamage(this, this, MUDMath.Dice(wall.Values[2], 5), "lightning curtain", AttackType.DamageType.electricity); if (CurrentPosition == Position.dead) return; } if( wall.ObjIndexData.IndexNumber == StaticObjects.OBJECT_NUMBER_WALL_MIST ) { if (!Magic.SpellSavingThrow(wall.Values[2], this, AttackType.DamageType.poison)) { Affect af = new Affect(Affect.AffectType.spell, "poison", wall.Values[2], Affect.Apply.strength, (0 - 2), Affect.AFFECT_POISON); CombineAffect(af); SendText( "&+GYou don't feel very well.&n\r\n" ); } Combat.InflictSpellDamage(this, this, MUDMath.Dice(4, wall.Values[2]), "wall of mist", AttackType.DamageType.poison); if (CurrentPosition == Position.dead) return; } } } } if( exit.HasFlag( Exit.ExitFlag.closed ) ) { if( Riding ) { if( !Riding.IsAffected( Affect.AFFECT_PASS_DOOR ) && !HasInnate( Race.RACE_PASSDOOR ) && !Riding.IsImmortal() ) { SocketConnection.Act("The $d is closed so your mount is unable to pass.", this, null, exit.Keyword, SocketConnection.MessageTarget.character); return; } if( exit.HasFlag( Exit.ExitFlag.passproof ) && !Riding.IsImmortal() ) { SocketConnection.Act( "Your mount is unable to pass through the $d. Ouch!", this, null, exit.Keyword, SocketConnection.MessageTarget.character); return; } } else { if( !IsAffected( Affect.AFFECT_PASS_DOOR ) && !HasInnate( Race.RACE_PASSDOOR ) && !IsImmortal() ) { SocketConnection.Act("The $d is closed.", this, null, exit.Keyword, SocketConnection.MessageTarget.character); return; } if (exit.HasFlag(Exit.ExitFlag.passproof) && !IsImmortal() ) { SocketConnection.Act( "You are unable to pass through the $d. Ouch!", this, null, exit.Keyword, SocketConnection.MessageTarget.character); return; } } } if (Riding && Riding.CurrentPosition < Position.standing) { SendText( "Your ride doesn't want to move right now.\r\n" ); return; } if( toRoom.IsPrivate() ) { SendText( "That room is private right now.\r\n" ); return; } // Race.RACE_SWIM means you're an aquatic race... and fish can't walk on land. if( Riding ) { if( !toRoom.IsWater() && Riding.HasInnate( Race.RACE_SWIM ) ) { SendText( "Your mount flaps around but can't move!\r\n" ); return; } } else { if( !toRoom.IsWater() && HasInnate( Race.RACE_SWIM ) ) { SendText( "You flap around but you can't move!\r\n" ); return; } } // Allow all mobs to go wherever they want? Not allowing them to would really // screw up the track code, but that's probably all screwed up already anyhow. if( !IsNPC() ) { if( ( InRoom.IsMidair() && InRoom.FallChance == 0 ) || ( toRoom.IsMidair() && toRoom.FallChance == 0 ) ) { if( InRoom.FallChance != 0 ) { Event.CheckFall(InRoom, toRoom, this); } if( Riding ) { if( !Riding.CanFly() && door != Exit.Direction.down ) { SendText( "Your mount can't fly.\r\n" ); return; } } else { // Changed to allow going down always in an air sector. if( !CanFly() && door != Exit.Direction.down ) { SendText( "You can't fly.\r\n" ); return; } } } // Water terrain code, check for boats and swimming. Flyers don't need to swim if( ( ( Riding && !Riding.CanFly() ) || ( !Riding && !CanFly() ) ) && ( toRoom.IsWater() || inRoom.IsWater() ) ) { bool found = false; if( Riding && !Riding.IsNPC() ) { if( ( (PC)Riding ).SkillAptitude[ "swim" ] != 0 ) { found = true; Riding.PracticeSkill( "swim" ); } } else if( !IsNPC() ) { if (((PC)this).SkillAptitude["swim"] != 0) { found = true; PracticeSkill( "swim" ); } } // Check for a boat first, uses less effort than swimming. foreach( Object obj in Carrying ) { if( obj.ItemType == ObjTemplate.ObjectType.boat ) { found = true; break; } } if( Riding != null && ( Riding.HasInnate( Race.RACE_WATERWALK ) || Riding.HasInnate( Race.RACE_SWIM ) ) ) { found = true; } if( HasInnate( Race.RACE_WATERWALK ) || HasInnate( Race.RACE_SWIM ) ) { found = true; } if( !found ) { SendText( "You can't go there without a boat.\r\n" ); return; } } if( Riding != null ) { if( ( inRoom.TerrainType == TerrainType.underwater_has_ground || toRoom.TerrainType == TerrainType.underwater_has_ground ) && !Riding.HasInnate( Race.RACE_SWIM ) && ( !Riding.IsNPC() && ((PC)this).SkillAptitude["swim"] == 0)) { SendText( "Your mount needs to be able to swim better to go there.\r\n" ); return; } } else { if( ( inRoom.TerrainType == TerrainType.underwater_has_ground || toRoom.TerrainType == TerrainType.underwater_has_ground ) && !HasInnate( Race.RACE_SWIM ) && ((PC)this).SkillAptitude["swim"] == 0) { SendText( "You need to be able to swim better to go there.\r\n" ); PracticeSkill( "swim" ); return; } else if( (toRoom.TerrainType == TerrainType.ocean || inRoom.TerrainType == TerrainType.ocean || toRoom.TerrainType == TerrainType.underground_ocean || inRoom.TerrainType == TerrainType.underground_ocean ) && (!IsImmortal() || !HasActionBit(PC.PLAYER_GODMODE))) { SendText("The ocean is much too turbulent for your swimming ability.\r\n"); return; } } int move; // Half of move loss comes from crossing the current terrain and half comes from crossing the destination terrain // since they're technically moving from midpoint to midpoint. if ((int)inRoom.TerrainType < RoomTemplate.TERRAIN_MAX && (int)toRoom.TerrainType < RoomTemplate.TERRAIN_MAX ) { move = ( Movement.MovementLoss[ inRoom.TerrainType ] + Movement.MovementLoss[ toRoom.TerrainType ] ) / 2; int swimAbility = Level * 2 + 15; if( !IsNPC() && HasSkill("swim")) { swimAbility = ((PC)this).SkillAptitude["swim"]; } if (toRoom.IsWater()) { // Movement loss can increase by up to 95% based on swim skill. move += (move * ((Limits.MAX_SKILL_ADEPT - swimAbility)) / 100); } if (InRoom.IsWater()) { // Movement loss can increase by up to 95% based on swim skill. move += (move * ((Limits.MAX_SKILL_ADEPT - swimAbility)) / 100); } } else { move = 4; } // Flying persons lose constant minimum movement. if (CanFly() || IsAffected(Affect.AFFECT_LEVITATE)) { move = 1; } if ((Riding)) { if (this != Riding.Rider) { Log.Error(String.Format( "{0} riding {1}, who is not mounted!", Name, Riding.Name ) ); } else { riding = true; } } if( ( CurrentMoves < move ) && ( !IsImmortal() ) ) { SendText( "You are too tired to move another step.\r\n" ); if( ( Rider ) && riding ) { Rider.SendText( "Your mount is too tired to carry you there.\r\n" ); } return; } WaitState( 1 ); CurrentMoves -= move; if( ( Rider ) && riding ) { } } if (!CheckSneak() && !HasActionBit(PC.PLAYER_WIZINVIS) && !IsAffected( Affect.AFFECT_IS_FLEEING ) ) { if( ( ( inRoom.TerrainType == TerrainType.swimmable_water ) || ( inRoom.TerrainType == TerrainType.underwater_has_ground ) ) && ( ( toRoom.TerrainType == TerrainType.swimmable_water ) || ( toRoom.TerrainType == TerrainType.underwater_has_ground ) ) ) { SocketConnection.Act("$n&n swims $T.", this, null, door.ToString(), SocketConnection.MessageTarget.room); } else { foreach( CharData watchCh in InRoom.People ) { if (watchCh == this || watchCh.FlightLevel != FlightLevel) continue; Visibility visibility = Look.HowSee(watchCh, this); switch( visibility ) { case Visibility.visible: if( !Riding ) { text2 = String.Format( "{0}&n {1} {2}.\r\n", ShowNameTo( watchCh, true ), ( FlightLevel != 0 ) ? "flies" : Race.RaceList[ GetRace() ].WalkMessage, door.ToString() ); watchCh.SendText( text2 ); } else { text2 = String.Format( "{0}&n rides {1}&n {2}.\r\n", ShowNameTo( watchCh, true ), Riding.ShowNameTo(watchCh, false), door.ToString() ); watchCh.SendText( text2 ); } break; case Visibility.sense_infravision: text2 = String.Format( "&+LA &n&+rred shape &+Lleaves {0} in the &+Wd&n&+war&+Lkness.\r\n&n", door.ToString()); watchCh.SendText( text2 ); break; case Visibility.invisible: if( Riding ) { if (Look.HowSee(watchCh, Riding) == Visibility.visible) { text2 = String.Format( "{0}&n {1} {2}.\r\n", Riding.ShowNameTo(watchCh, true), ( FlightLevel != 0 ) ? "flies" : Race.RaceList[ GetRace() ].WalkMessage, door.ToString() ); watchCh.SendText( text2 ); } } break; default: break; } } } } // Check for guild golems if( inRoom.HasFlag( RoomTemplate.ROOM_GUILDROOM ) ) { int chId = 0; Guild.Rank chRank = 0; // Find a golem foreach( CharData roomCharacter in InRoom.People ) { if( !roomCharacter.IsNPC() && !MUDString.NameContainedIn( "_guildgolem_", roomCharacter.Name ) ) continue; int id = Guild.GolemGuildID( roomCharacter ); Exit.Direction dir = Movement.GolemGuardDirection( roomCharacter ); if( id > 0 && dir > Exit.Direction.invalid ) { // We have a golem guarding an exit if (!IsNPC() && ((PC)this).GuildMembership != null) { chId = ((PC)this).GuildMembership.ID; chRank = ((PC)this).GuildRank; } if (dir == door && (id != chId || chRank < Guild.Rank.parole) && CurrentPosition > Position.reclining) { SocketConnection.Act("$N&n roughly shoves you to the floor as you attempt to pass.", this, null, roomCharacter, SocketConnection.MessageTarget.character); SocketConnection.Act("$N&n shoves $n&n to the floor.", this, null, roomCharacter, SocketConnection.MessageTarget.room); CurrentPosition = Position.reclining; return; } if (dir == door && ((PC)this).GuildRank >= Guild.Rank.officer) { SocketConnection.Act("$N&n salutes smartly as you pass.", this, null, roomCharacter, SocketConnection.MessageTarget.character); SocketConnection.Act("$N&n salutes at $n&n.", this, null, roomCharacter, SocketConnection.MessageTarget.room); } else if( dir == door ) { SocketConnection.Act("$N&n nods as you pass.", this, null, roomCharacter, SocketConnection.MessageTarget.character); SocketConnection.Act("$N&n nods at $n&n.", this, null, roomCharacter, SocketConnection.MessageTarget.room); } } //end if } ///end for } // end guild golems RemoveFromRoom(); AddToRoom( toRoom ); if( IsAffected( Affect.AFFECT_IS_FLEEING ) ) { text = String.Format( "move_char: {0} has fled to room {1}.", Name, InRoom.IndexNumber ); ImmortalChat.SendImmortalChat( null, ImmortalChat.IMMTALK_SPAM, 0, text ); } if( !CheckSneak() ) { if( Riding ) { text = String.Format( "$n&n enters from {0}, riding $N&n.", Exit.ReverseDirectionName[ (int)door ] ); SocketConnection.Act(text, this, null, Riding, SocketConnection.MessageTarget.room); } else if( !Rider ) { // Changed: Don't show invis people entering room. foreach( CharData watchCh in InRoom.People ) { Visibility sight; if ((sight = Look.HowSee(watchCh, this)) != 0 && watchCh != this && watchCh.FlightLevel == FlightLevel ) { // If visible to char (& not char), show msg. if( sight == Visibility.visible ) { // If they can see the person enter clearly.. text2 = String.Format( "{0}&n {1} in from {2}.\r\n", ShowNameTo( watchCh, true ), ( FlightLevel != 0 ) ? "flies" : Race.RaceList[ GetRace() ].WalkMessage, Exit.ReverseDirectionName[(int)door]); watchCh.SendText( text2 ); } else if( sight == Visibility.sense_infravision ) { // Otherwise, show a vague message.. text2 = String.Format( "&+LA &n&+rred shape &+Lenters from {0}.\r\n&n", Exit.ReverseDirectionName[(int)door]); watchCh.SendText( text2 ); } } } } } /* Because of the addition of the deleted flag, we can do this */ if( !IsImmortal() && GetRace() == Race.RACE_VAMPIRE && toRoom.TerrainType == TerrainType.underwater_has_ground ) { SendText( "Arrgh! Large body of water!\r\n" ); SocketConnection.Act("$n&n thrashes underwater!", this, null, null, SocketConnection.MessageTarget.room); Combat.InflictDamage(this, this, 20, String.Empty, ObjTemplate.WearLocation.none, AttackType.DamageType.drowning); } else if( !IsImmortal() && ( toRoom.TerrainType == TerrainType.underwater_has_ground && !IsAffected( Affect.AFFECT_BREATHE_UNDERWATER ) && !HasInnate( Race.RACE_WATERBREATH ) ) ) { SendText( "You can't breathe!\r\n" ); SocketConnection.Act("$n&n sputters and chokes!", this, null, null, SocketConnection.MessageTarget.room); Combat.InflictDamage(this, this, 2, String.Empty, ObjTemplate.WearLocation.none, AttackType.DamageType.drowning); } //* Why have mobiles see the room? if( Socket != null ) { CommandType.Interpret(this, "look auto"); } SetActionBit(moved ); // Handle following. for( int i = InRoom.People.Count -1; i >= 0; i--) { CharData followChar = InRoom.People[i]; if (followChar.Master == this && followChar.CurrentPosition == Position.standing && followChar.Wait == 0 && followChar.FlightLevel == FlightLevel && CanSee(followChar, this)) { SocketConnection.Act("You follow $N&n.", followChar, null, this, SocketConnection.MessageTarget.character); followChar.Move(door); } else if (followChar == Rider) { followChar.Move(door); } } RemoveActionBit(moved); // Okay, now that they're in to room, check to see if they've just invaded a // hometown Crime.CheckInvader(this); // Check to see if a person falls out of this room if( InRoom.ExitData[ 5 ] && ( target = Room.GetRoom(InRoom.ExitData[ 5 ].IndexNumber) ) ) { if( InRoom.TerrainType == TerrainType.air || InRoom.TerrainType == TerrainType.plane_of_air || InRoom.TerrainType == TerrainType.underground_no_ground || InRoom.FallChance != 0 ) Event.CheckFall(InRoom, target, this); } // prog_entry_trigger( ch ); // prog_greet_trigger( ch ); return; }