public void AddNewRoom(int originalRoom, Exit.Direction direction) { btnNew_Click(null, null); RoomTemplate newRoom = _area.Rooms[(_area.Rooms.Count - 1)]; RoomTemplate oldRoom = null; for (int i = 0; i < _area.Rooms.Count; i++ ) { if (_area.Rooms[i].IndexNumber == originalRoom) { oldRoom = _area.Rooms[i]; break; } } if (oldRoom != null) { if (oldRoom.ExitData[(int)direction] == null) { oldRoom.ExitData[(int)direction] = new Exit(); } oldRoom.ExitData[(int)direction].IndexNumber = newRoom.IndexNumber; if (newRoom.ExitData[(int)Exit.ReverseDirection(direction)] == null) { newRoom.ExitData[(int)Exit.ReverseDirection(direction)] = new Exit(); } newRoom.ExitData[(int)Exit.ReverseDirection(direction)].IndexNumber = oldRoom.IndexNumber; } }
/// <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() + "."; } }
public Exit GetExitData() { if (_delete) { return null; } Exit exit = new Exit(); exit.Description = txtDescription.Text; int val; Int32.TryParse(txtFlags.Text, out val); exit.ExitFlags = (Exit.ExitFlag)val; int key; Int32.TryParse(txtKeyIndexNumber.Text, out key); exit.Key = key; exit.Keyword = txtKeyword.Text; int indexNumber; Int32.TryParse(txtIndexNumber.Text, out indexNumber); exit.IndexNumber = indexNumber; return exit; }
/* void room_iterate( RoomIndex *rb[], void ( *func ) ( ), void *cdata ) { register int i; for ( i = 0; i < WORLD_SIZE; i++ ) { RoomIndex *temp; temp = room_find( rb, i ); if ( temp ) ( *func ) ( i, temp, cdata ); } } */ /* void hash_iterate( HASH_HEADER *ht, void ( *func ) ( ), void *cdata ) { int i; for ( i = 0; i < ht.Klistlen; i++ ) { void *temp; register int Key; Key = ht.Keylist[i]; temp = hash_find( ht, Key ); ( *func )( Key, temp, cdata ); if ( ht.Keylist[i] != Key ) // They must have deleted this room i--; // Hit this slot again. } } */ /// <summary> /// Checks whether an exit is valid. /// </summary> /// <param name="exit"></param> /// <returns></returns> static int ExitOk( Exit exit ) { if( ( !exit ) || !( exit.TargetRoom ) ) { return 0; } return 1; }
/// <summary> /// Loads the entire MUD database including all classes, races, areas, helps, sytem data, etc. /// </summary> public void LoadDatabase() { DatabaseIsBooting = true; Log.Trace( DateTime.Now.ToShortDateString() + " BOOT: -------------------------[ Boot Log ]-------------------------" ); Log.Trace("Validating that player directories exist."); for (Char letter = 'a'; letter <= 'z'; letter++) { String directory = FileLocation.PlayerDirectory + letter; if (!Directory.Exists(directory)) { Log.Trace("Creating directory: " + directory + "."); Directory.CreateDirectory(directory); } } Log.Trace("Player directories validated."); Log.Trace( "Loading Database.SystemData." ); Sysdata.Load(); SystemData.CurrentTime = DateTime.Now; SystemData.GameBootTime = SystemData.CurrentTime; // Set time and weather. Log.Trace( "Setting time and weather." ); SystemData.SetWeather(); Log.Trace("Loading static rooms."); StaticRooms.Load(); Log.Trace("Loaded " + StaticRooms.Count + " static rooms."); Log.Trace("Loading spells."); Spell.LoadSpells(); Log.Trace("Loaded " + Spell.SpellList.Count + " spells."); Log.Trace("Loading skills."); Skill.LoadSkills(); Log.Trace("Loaded " + Skill.SkillList.Count + " skills."); Log.Trace( "Loading races." ); Race.LoadRaces(); Log.Trace( "Loaded " + Race.Count + " races." ); Log.Trace( "Initializing skill Levels." ); { int cclass; foreach (KeyValuePair<String, Skill> kvp in Skill.SkillList) { for (cclass = 0; cclass < CharClass.ClassList.Length; cclass++) kvp.Value.ClassAvailability[ cclass ] = Limits.LEVEL_LESSER_GOD; } foreach (KeyValuePair<String, Spell> kvp in Spell.SpellList) { for (cclass = 0; cclass < CharClass.ClassList.Length; cclass++) kvp.Value.SpellCircle[cclass] = Limits.MAX_CIRCLE + 3; } } Log.Trace( "Loading classes." ); CharClass.LoadClasses(true); Log.Trace( "Loaded " + CharClass.Count + " classes." ); Log.Trace("Assigning spell circles."); AssignSpellCircles(); Log.Trace("Assigned spell circles."); Log.Trace( "Loading socials." ); SocialList = Socials.Load(); Log.Trace( "Loaded " + Social.Count + " socials." ); Log.Trace( "Loading bans." ); LoadBans(); Log.Trace( "Loaded " + BanList.Count + " bans." ); Log.Trace( "Loading help entries." ); HelpList = Help.Load(FileLocation.SystemDirectory + FileLocation.HelpFile); Log.Trace( "Loaded " + Help.Count + " help entries." ); Log.Trace( "Loading screens." ); Screen.Load(FileLocation.SystemDirectory + FileLocation.ScreenFile, FileLocation.BlankSystemFileDirectory + FileLocation.ScreenFile); Log.Trace( "Loaded " + Screen.Count + " screens." ); // Chatbots have to be loaded before mobs. Log.Trace( "Loading chatbots." ); ChatterBot.Load(); Log.Trace( "Loaded " + ChatterBot.Count + " chatbots." ); // Read in all the area files. Log.Trace( "Reading in area files..." ); LoadAreaFiles(); Log.Trace( "Loaded " + Area.Count + " areas." ); string buf = String.Format( "Loaded {0} mobs, {1} objects, {2} rooms, {3} shops, {4} helps, {5} resets, and {6} quests.", MobTemplate.Count, ObjTemplate.Count, Room.Count, Shop.Count, Help.Count, Reset.Count, QuestData.Count ); Log.Trace( buf ); Log.Trace( "Loading guilds." ); Guild.LoadGuilds(); Log.Trace( "Loaded " + Guild.Count + " guilds." ); Log.Trace( "Loading corpses." ); CorpseList = CorpseData.Load(); Log.Trace( "Loaded " + CorpseData.Count + " corpses." ); Log.Trace( "Loading crimes." ); Crime.Load(); Log.Trace( "Loaded " + Crime.Count + " crimes." ); Log.Trace( "Loading fraglist." ); FraglistData.Fraglist.Load(); Log.Trace( "Loading issues." ); Issue.Load(); Log.Trace( "Loaded " + Issue.Count + " issues." ); Log.Trace("Loading bounties."); Bounty.Load(); Log.Trace("Loaded " + Bounty.Count + " bounties."); Log.Trace("Initializing movement parameters."); Movement.Initialize(); Log.Trace("Movement parameters initialized."); // Only compile spells that have attached code. Otherwise use default handlers. Log.Trace("Compiling spells."); int good = 0; int bad = 0; foreach (KeyValuePair<String, Spell> kvp in Spell.SpellList) { if( !String.IsNullOrEmpty(kvp.Value.Code)) { if (!SpellFunction.CompileSpell(kvp.Value)) { ++bad; } else { ++good; } } } Log.Trace("Done compiling spells. " + good + " were successful, " + bad + " failed."); // Links up exits and makes rooms runtime-ready so we can access them. Log.Trace( "Linking exits." ); LinkExits(); // This has to be after LinkExits(). Log.Trace("Loading zone connections."); ZoneConnectionList = ZoneConnection.Load(); // Link zones together based on file. foreach (ZoneConnection connection in ZoneConnectionList) { RoomTemplate room1 = Room.GetRoom(connection.FirstRoomNumber); RoomTemplate room2 = Room.GetRoom(connection.SecondRoomNumber); Exit.Direction direction = connection.FirstToSecondDirection; if (room1 != null && room2 != null && direction != Exit.Direction.invalid) { Exit exit = new Exit(); exit.TargetRoom = room2; exit.IndexNumber = connection.SecondRoomNumber; room1.ExitData[(int)direction] = exit; exit = new Exit(); exit.TargetRoom = room1; exit.IndexNumber = connection.FirstRoomNumber; room2.ExitData[(int)Exit.ReverseDirection(direction)] = exit; Log.Trace("Connected " + room1.Area.Name + " to " + room2.Area.Name + " at " + room1.IndexNumber); } else { Log.Error("Unable to connect room " + connection.FirstRoomNumber + " to " + connection.SecondRoomNumber + " in direction " + connection.FirstToSecondDirection); } } Log.Trace("Loaded " + ZoneConnectionList.Count + " zone connections."); DatabaseIsBooting = false; Log.Trace( "Resetting areas." ); AreaUpdate(); Log.Trace( "Creating events." ); Event.CreateEvent(Event.EventType.save_corpses, Event.TICK_SAVE_CORPSES, null, null, null); Event.CreateEvent(Event.EventType.save_sysdata, Event.TICK_SAVE_SYSDATA, null, null, null); Event.CreateEvent(Event.EventType.violence_update, Event.TICK_COMBAT_UPDATE, null, null, null); Event.CreateEvent(Event.EventType.area_update, Event.TICK_AREA, null, null, null); Event.CreateEvent(Event.EventType.room_update, Event.TICK_ROOM, null, null, null); Event.CreateEvent(Event.EventType.object_special, Event.TICK_OBJECT, null, null, null); Event.CreateEvent(Event.EventType.mobile_update, Event.TICK_MOBILE, null, null, null); Event.CreateEvent(Event.EventType.weather_update, Event.TICK_WEATHER, null, null, null); Event.CreateEvent(Event.EventType.char_update, Event.TICK_CHAR_UPDATE, null, null, null); Event.CreateEvent(Event.EventType.object_update, Event.TICK_OBJ_UPDATE, null, null, null); Event.CreateEvent(Event.EventType.aggression_update, Event.TICK_AGGRESS, null, null, null); Event.CreateEvent( Event.EventType.memorize_update, Event.TICK_MEMORIZE, null, null, null ); Event.CreateEvent( Event.EventType.hit_gain, Event.TICK_HITGAIN, null, null, null ); Event.CreateEvent( Event.EventType.mana_gain, Event.TICK_MANAGAIN, null, null, null ); Event.CreateEvent( Event.EventType.move_gain, Event.TICK_MOVEGAIN, null, null, null ); Event.CreateEvent( Event.EventType.heartbeat, Event.TICK_WEATHER, null, null, null ); return; }
private void btnNewRoom_Click(object sender, EventArgs e) { int currentRoom = _room.IndexNumber; int roomNumber = _parent.AddNewRoomFromExit(); this.txtIndexNumber.Text = roomNumber.ToString(); // Create reverse-direction exit by default. Exit.Direction dir = Exit.ReverseDirection(_direction); for( int i = 0; i < _area.Rooms.Count; i++ ) { if (_area.Rooms[i].IndexNumber == roomNumber) { if (_area.Rooms[i].ExitData != null && _area.Rooms[i].ExitData[(int)dir] == null) { Exit exit = new Exit(); exit.IndexNumber = currentRoom; _area.Rooms[i].ExitData[(int)dir] = exit; } return; } } }
/// <summary> /// Generates a zone file. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void generateZoneToolStripMenuItem_Click(object sender, EventArgs e) { SaveFileDialog dialog = new SaveFileDialog(); dialog.Filter = "xml files (*.xml)|*.xml"; if (dialog.ShowDialog() == DialogResult.OK) { int vnum = Int32.Parse(txtStartVnum.Text); Area area = new Area(); area.AreaFlags[Area.AREA_WORLDMAP.Group] = Area.AREA_WORLDMAP.Vector; area.Width = _bitmap.Width; area.Height = _bitmap.Height; area.Author = txtAuthor.Text; area.Builders = txtAuthor.Text; area.Name = txtZoneName.Text; for (int y = 0; y < _bitmap.Height; y++) { for (int x = 0; x < _bitmap.Width; x++) { Color col = _bitmap.GetPixel(x, y); MiniRoomTemplate temp = GetTemplate(col); RoomTemplate room = new RoomTemplate(); room.Title = temp.Title; room.Description = temp.Description; room.TerrainType = temp.Terrain; room.IndexNumber = vnum + x + (y * _bitmap.Width); // Only add exits and add the room to the zone if the room is not impassable. // // TODO: Don't create exits that point to impassable rooms. Color pixel; MiniRoomTemplate target; if (room.TerrainType != TerrainType.underground_impassable || (x == 0 && y == 0)) { if (x > 0) { pixel = _bitmap.GetPixel(x-1, y); target = GetTemplate(pixel); if (target.Terrain != TerrainType.underground_impassable) { Exit exit = new Exit(); exit.IndexNumber = vnum + x + (y * _bitmap.Width) - 1; room.ExitData[(int)Exit.Direction.west] = exit; } } if (x < (_bitmap.Width - 1)) { pixel = _bitmap.GetPixel(x+1, y); target = GetTemplate(pixel); if (target.Terrain != TerrainType.underground_impassable) { Exit exit = new Exit(); exit.IndexNumber = vnum + x + (y * _bitmap.Width) + 1; room.ExitData[(int)Exit.Direction.east] = exit; } } if (y > 0) { pixel = _bitmap.GetPixel(x, y-1); target = GetTemplate(pixel); if (target.Terrain != TerrainType.underground_impassable) { Exit exit = new Exit(); exit.IndexNumber = vnum + x + ((y - 1) * _bitmap.Width); room.ExitData[(int)Exit.Direction.north] = exit; } } if( y < (_bitmap.Height - 1 )) { pixel = _bitmap.GetPixel(x, y+1); target = GetTemplate(pixel); if (target.Terrain != TerrainType.underground_impassable) { Exit exit = new Exit(); exit.IndexNumber = vnum + x + ((y + 1) * _bitmap.Width); room.ExitData[(int)Exit.Direction.south] = exit; } } area.Rooms.Add(room); } } } area.Save(dialog.FileName); } }
/// <summary> /// Utility function that gets a room's exit for a particular direction. /// </summary> /// <param name="door"></param> /// <returns></returns> public Exit GetExit(Exit.Direction door) { // Exit direction could have been stored somewhere as an invalid value, // i.e. as a bad integer on a wall value. Check for it. if (!Enum.IsDefined(typeof(Exit.Direction), door)) { return null; } return ExitData[(int)door]; }
private void ShowExitDlg(Exit.Direction direction) { if( roomList.SelectedIndex != -1 ) { EditExit exitdlg = new EditExit(_parent, _area); exitdlg.UpdateWindowContents( _area.Rooms[ roomList.SelectedIndex ], direction ); DialogResult result = exitdlg.ShowDialog(); if( result == DialogResult.OK ) { Exit exitData = exitdlg.GetExitData(); _area.Rooms[roomList.SelectedIndex].ExitData[(int)direction] = exitData; UpdateExitButtons(_area.Rooms[roomList.SelectedIndex]); this._parent.UpdateRoomMap(); } } else { MessageBox.Show( "You can't edit exits without first selecting or creating a room." ); } }
/// <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; }