Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Expanding CodeDragon's Chapter 1 Serverfiles

Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Hi everyone:

I´ve been working on CodeDragon´s release recently and after asking him permission I decided to open this thread. The aim of this project is to learn how the sources work and to fix and expand this awesome release TOGETHER WITH THE COMMUNITY.

EDIT[11-1-14]: I deleted all the fixes since none is actually contributing. Please, read this post:

Since none has contributed but CodeDragon and it takes a lot of time to explain and update my changes, I have decided to stop posting fixes. I still work on this release and I will post it one I finish it (everything but the userlist packet, sorry. It is private), but I wont update this post with code, only screenshots.

What I added so far:

* Improved the healing system. Now its fully funcional.

* Improved the player damage calculations to be more like the vanilla game. Headshot detected properly.

* Added Team Death Match to CQC and UO/BG.

* Added Conquest.

* Flags are working.

* Ammo recharge works.

* You can place any item on the ground and use it (TMA has to be debugged)

* The launcher packet is now configurable. So you can update the client easily.

* Level check for the Itemshop added.

* Level check for joining a room added.

* Fixed notice manager

* Added some config parameters: bombTime, dinar and exp rate, maximum team difference

* Added the classic coupon system. You can add new codes in the database.

* Added some missing packets: death confirmed, logout packet.


Im working on vehicles a.t.m. Once I finish them Ill move to clan system and then I will fix a couple of bugs in CQC and some bugs about the lobby update. The last step will consist on more security checks and optimization.
 
Last edited:
◝(⁰▿⁰)◜Smile◝ (⁰▿⁰)◜
Developer
Joined
May 29, 2007
Messages
2,167
Reaction score
899
Re: Expanding CodeDragon´s Chapter 1 sources

Thanks for posting! Before you post in this topic, please consider if this post is useful. If it's not don't reply to this. If you need help you can post your questions in the help section. I'll report every post that isn't useful in this topic! This thread is only for contributions and not for (childish) feedback.
 
Newbie Spellweaver
Joined
Dec 4, 2014
Messages
22
Reaction score
9
Re: Expanding CodeDragon´s Chapter 1 sources

I'd love to join this project!

Since I'm rather busy with exams right now I won't be very active until 01/16 though :(
 
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

Actually I should be studying too but I was too tired this evening.

More "fixes":

* Fixed a bug about the server not updating the DB properly when leveling up:

AlterEmu\Game\Entities\User.cs The insertion was incorrrect: rows missing in the DB
Code:
 Databases.Game.Insert("game_levels_gained", new Dictionary<string, object>() {
                    { "id", this.ID },
                    {"game_id", this.Displayname },
                    { "current_level", currentLevel},
                    { "levels_gained", levelsGained },
                    { "timestamp", nowTimeStamp }
                });

[DB] the levels_gained table has been modified: Now it has 5 rows: id, game_id, current_level, levels_gained, timestamp.

ID is an int type row. game_id has been changed from int to Text. Now the log works like this: id (player id matching the DB index), game_id (nickname of the player, can be changed to use user id lol), current_level (player´s level), levels_gained (number of levels gained during the level up, most times 1), timestamp (date in unix format).

* Fixed a bug in the level up event. The player could lose the money earned if he logged out the game without buying anything (anything that updated the DB info, to be more accurate).

AlterEmu\Game\Entities\User.cs Added a direct DB insertion. I don´t know why, updating user.Money didn´t update the DB if the player logged off.

Add this line just before the lof query to update game_levels_gained
Code:
 Databases.Game.AsyncQuery("UPDATE user_details SET money=" + this.Money + " WHERE id=" + this.ID);


* Added dinar rate and XP rate to the configuration file (.ini).

AlterEmu\Game\Config.cs
Code:
using Core.IO;
using System;


namespace Game {
    class Config {
        public static string AUTH_SERVER_IP = "127.0.0.1";
        public static byte SERVER_ID = 0;
        public static string SERVER_KEY = "SERVER-KEY";
        public static string SERVER_NAME = "AlterEmu";
        public static string SERVER_IP = "";
        public static int MAXIMUM_ROOM_COUNT = 5;
        public static int MAXIMUM_TEAM_DIFFRENCE = 1;
        public static double EXPRATE = 1.0;
        public static double DINARRATE = 1.0;
        public static uint LEVEL_UP_MONEY_REWARD = 25000u;
        public static string[] GAME_DATABASE;


        public static bool Read()
        {
            INIFile configFile = new INIFile("config");
            bool result = false;
            if (configFile.Exists())
            {
                AUTH_SERVER_IP = configFile.Read("auth-server", "ip");
                SERVER_KEY = configFile.Read("auth-server", "key");
                SERVER_NAME = configFile.Read("server", "name");
                SERVER_IP = configFile.Read("server", "bindip");


                //Game configuration


                string _expRate = configFile.Read("game-configuration", "exprate");
                string _dinarRate = configFile.Read("game-configuration", "dinarrate");


                 double.TryParse(_expRate, out EXPRATE);
                 double.TryParse(_dinarRate, out DINARRATE);


                 if (EXPRATE == 0 || DINARRATE == 0)
                 {
                     Log.Instance.WriteError("Exprate or dinarrate values are 0 or not a number " + _expRate + "/" + _dinarRate);
                     Log.Instance.WriteError("Using default values");
                     EXPRATE = 1.0;
                     DINARRATE = 1.0;
                 }
                 else
                 {
                     //Just in case some dumbass tries to put a negative number
                     EXPRATE = Math.Abs(EXPRATE);
                     DINARRATE = Math.Abs(DINARRATE);
                 }
 
               


                GAME_DATABASE = new string[]
                {
                    configFile.Read("game-database", "host"),
                    configFile.Read("game-database", "port"),
                    configFile.Read("game-database", "username"),
                    configFile.Read("game-database", "password"),
                    configFile.Read("game-database", "database")
                };
                result = true;
            }
            return result;
        }
    }
}

AlterEmu\Game\Entities\Player.cs

Code:
  this.XPEarned = (long)Math.Ceiling(fltXPEarned * Config.EXPRATE);
  this.MoneyEarned = (long)Math.Ceiling(fltDinarEarned * Config.DINARRATE);


.INI file: Added the new configuration parameters. I set them up to some crazy values for testing.
REMEMBER THEY ARE DOUBLE VALUES
Code:
[auth-server]
ip=127.0.0.1
key=UNUSED
[server]
name=AlterEmu
bindip=127.0.0.1
[game-database]
host=127.0.0.1
port=3306
username=root
password=
database=alterwarfinal
[game-configuration]
exprate=1500.0
dinarrate=1500.0


See u on friday!
 
◝(⁰▿⁰)◜Smile◝ (⁰▿⁰)◜
Developer
Joined
May 29, 2007
Messages
2,167
Reaction score
899
Fixing ghost rooms when you are the last player

Fixing the ghost rooms with 0 players after you leave the room as last player.

Open: RoomLeave.cs

Find:
Code:
if (r != null) {
Replace With:
Code:
if (r != null && r.Players.Count > 0) {
 
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

Thanks CodeDragon! Later I´ll update the first post with all the changes done so far. I´m also implementing a simple ban check. I hope I can post it here soon.

EDIT: Added all the changes made until now to the first post.

EDIT2: This project is still alive and running. I´m just too busy with exams a.t.m.
 
Last edited:
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

Sorry for double-posting but I´ve made a lot of changes to the code and I felt like a post was needed after 2 weeks.

First of all I´M VERY SORRY, the NOTICE MANAGER WAS BUGGY. I just fixed it. The format of the messages sent were wrong and the data management was a disaster.

FIXED NOTICE MANAGER:
AlterEmu\Game\Managers\NoticeManager.cs

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

using Game.Enums;
using Game.Networking;

using MySql.Data.MySqlClient;


namespace Game.Managers
{
    class NoticeManager
    {
        List<string> ActiveNotices = new List<string>();
      
        public NoticeManager()
        {

          

        }


        public bool Load()
        {

            MySqlCommand cmd = new MySqlCommand("SELECT * FROM notices", Databases.Game.connection);
            MySqlDataReader Reader = cmd.ExecuteReader();

            int _inactiveNotices = 0;

             if(Reader.HasRows)
             {
                 
                 while(Reader.Read())
                 {
                     byte _id = Reader.GetByte("id");
                     string _message = Reader.GetString("message");
                     byte _active = Reader.GetByte("active");

                      if(_active == 1)
                      {
                          ActiveNotices.Add(_message);
                      }
                      else
                          _inactiveNotices++;
                 }

                 Log.Instance.WriteLine("Notice manager found " + ActiveNotices.Count.ToString() + " active notices");
                 Reader.Close();

                  if(ActiveNotices.Count > 0)
                  {
                      System.Timers.Timer Timer = new System.Timers.Timer();
                      Timer.Enabled = true;
                      Timer.Interval = 600000;
                      Timer.Elapsed += (sender, e) => NoticeLoop(sender, e, ActiveNotices);
                  }
             }
             else
             {
                 Reader.Close();
                 Log.Instance.WriteError("Notice manager couldn´t parse the notice table");
                 return false;

             }

           


            return true;
        }
        private static void NoticeLoop(object sender, ElapsedEventArgs e, List<string> messages)
        {
        
            Random Random = new Random();


            int _index = Random.Next(0, messages.Count());

            string _message = MessageTranslator("Notice: " + messages[_index]);

            Core.Networking.OutPacket Notice = new Packets.Chat("Server", ChatType.Notice2, _message, 100, "NULL");
            Managers.ChannelManager.Instance.SendAllLobbies(Notice.BuildEncrypted());
        }



        public static string MessageTranslator(string _message)
        {

            string _codedMessage = _message.Insert(0, ">>" + Convert.ToChar(0x1D));
            _codedMessage = _codedMessage.Replace(Convert.ToChar(0x20), Convert.ToChar(0x1D));

            

            return _codedMessage;
        }
       
        private static NoticeManager instance = null;
        public static NoticeManager Instance { get { if (instance == null) instance = new NoticeManager(); return instance; } set { } }
       
    }
}

DATABASE: The notice table was completely rebuilt

notice tables has 3 rows; id, message, active. id is a tinyint, message is a string and active is another tinyint. I uploaded an SQL dump


Maximum team difference to start a room rebuilt. Now you can configure it easily from the INI files.
CodeDragon, if you ever read this, I´m very curious about the code you used to calculate the team difference (powering and then square rooting to get the original team difference).

These modifications also allow you to configure the bomb time from the INI files too.


AlterEmu\Game\Config.cs


Code:
using Core.IO;
using System;

namespace Game {
    class Config {
        public static string AUTH_SERVER_IP = "127.0.0.1";
        public static byte SERVER_ID = 0;
        public static string SERVER_KEY = "SERVER-KEY";
        public static string SERVER_NAME = "AlterEmu";
        public static string SERVER_IP = "";
        public static int MAXIMUM_ROOM_COUNT = 5;
        public static short MAXIMUM_TEAM_DIFFERENCE = 1;
        public static double EXPRATE = 1.0;
        public static double DINARRATE = 1.0;
        public static uint LEVEL_UP_MONEY_REWARD = 25000u;
        public static string[] GAME_DATABASE;
        public static long BOMBTIME = 45000;

        public static bool Read()
        {
            INIFile configFile = new INIFile("config");
            bool result = false;
            if (configFile.Exists())
            {
                AUTH_SERVER_IP = configFile.Read("auth-server", "ip");
                SERVER_KEY = configFile.Read("auth-server", "key");
                SERVER_NAME = configFile.Read("server", "name");
                SERVER_IP = configFile.Read("server", "bindip");

                //Game configuration

                string _expRate = configFile.Read("game-configuration", "exprate");
                string _dinarRate = configFile.Read("game-configuration", "dinarrate");
                string _bombTime = configFile.Read("game-configuration", "bombtime");
                string _maximumTeamDifference = configFile.Read("game-configuration", "team_difference");

                 double.TryParse(_expRate, out EXPRATE);
                 double.TryParse(_dinarRate, out DINARRATE);
                 long.TryParse(_bombTime, out BOMBTIME);
                 Int16.TryParse(_maximumTeamDifference, out MAXIMUM_TEAM_DIFFERENCE);

                 if (EXPRATE == 0 || DINARRATE == 0)
                 {
                     Log.Instance.WriteError("Exprate or dinarrate values are 0 or not a number " + _expRate + "/" + _dinarRate);
                     Log.Instance.WriteError("Using default values");
                     EXPRATE = 1.0;
                     DINARRATE = 1.0;
                 }
                 else
                 {
                     //Just in case some dumbass tries to put a negative number
                     EXPRATE = Math.Abs(EXPRATE);
                     DINARRATE = Math.Abs(DINARRATE);
                 }

                 if (BOMBTIME == 0)
                 {
                     Log.Instance.WriteError("Invalid bomb time or the time is 0 " + _bombTime);
                     Log.Instance.WriteError("Using default value");
                     BOMBTIME = 45000;
                 }
                 else
                     BOMBTIME = Math.Abs(BOMBTIME);  //Trolling is not allowed ;)

                 if (MAXIMUM_TEAM_DIFFERENCE == 0)
                 {
                     Log.Instance.WriteError("Invalid team difference or team difference is 0 " + _maximumTeamDifference);
                     Log.Instance.WriteError("Using default value");
                     MAXIMUM_TEAM_DIFFERENCE = 1;
                 }
                 else
                     MAXIMUM_TEAM_DIFFERENCE = Math.Abs(MAXIMUM_TEAM_DIFFERENCE);

                GAME_DATABASE = new string[]
                {
                    configFile.Read("game-database", "host"),
                    configFile.Read("game-database", "port"),
                    configFile.Read("game-database", "username"),
                    configFile.Read("game-database", "password"),
                    configFile.Read("game-database", "database")
                };
                result = true;
            }
            return result;
        }
    }
}


AlterEmu\Game\Handlers\Game\Lobby\Start.cs

Code:
using System;
using System.Linq;
using Game.Enums;
using Game.Managers;

namespace Game.Handlers.Game {
    class Start : Networking.GameDataHandler {
        protected override void Handle() {
            if (Room.Master == Player.Id) {
                if (Room.State == Enums.RoomState.Waiting) {
                    lock (Room._playerLock) {
                        if (Room.Players.All(p => p.Value.Ready)) {
                            var debTeam = Room.Players.Select(n => n.Value).Where(n => n.Team == Enums.Team.Derbaran).Count();
                            var niuTeam = Room.Players.Select(n => n.Value).Where(n => n.Team == Enums.Team.NIU).Count();

                       /*     int diff = (int)Math.Sqrt(Math.Pow(debTeam - niuTeam, 2));
                           
                            //Codedragon method: 1. debTeam - niuTeam
                            //  2.  difference^2
                            //  3.  Square root of 2
                            // The result is the same of debTeam - niu Team
                            // Was it a check?????


                         
                            if (Config.MAXIMUM_TEAM_DIFFERENCE >= diff) {
                                respond = updateLobby = true;
                                type = Enums.GameSubs.StartReply;
                                Room.State = Enums.RoomState.Playing;
                                Set(2, Room.Map);
                                Room.Start();
                            }
                        */

                            //DarkRaptor Method: In WarRock you can always start a room if player difference is 1, BUT only if you aren´t alone!!!

                            int _curTeamDifference = debTeam - niuTeam;

                             if(_curTeamDifference <= Config.MAXIMUM_TEAM_DIFFERENCE && (debTeam > 0) && (niuTeam > 0))
                             {
                                 respond = updateLobby = true;
                                 type = Enums.GameSubs.StartReply;
                                 Room.State = Enums.RoomState.Playing;
                                 Set(2, Room.Map);
                                 Room.Start();
                             }
                             else
                             {
                               string _message = "You need more players to start this room";
                               Core.Networking.OutPacket NeedMorePlayers = new Packets.Chat("SYSTEM", ChatType.Room_ToAll,NoticeManager.MessageTranslator(_message), 999, "NULL");
                               Room.Send(NeedMorePlayers.BuildEncrypted());
                             }

                        }
                    }
                }
            } else {
                Player.User.Disconnect(); // Cheating? - Not a master!
            }
        }
    }
}

AlterEmu\Game\Modes\Explosive.cs
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Game.Enums;

namespace Game.Modes {
    public class Explosive : Objects.GameMode {

        private byte limitRound;
        private byte currentRound;
        private byte[] teamRounds;

        private ushort[] playersAlive;

        private bool roundActive = false;
        private sbyte bombSide = -1;
        private bool bombPlanted = false;
        private bool bombDefused = false;

        private DateTime roundEnd;

        private readonly object _syncObject;

        public Explosive()
            : base(0, "Explosive") {
            _syncObject = new object();
            currentRound = 0;
            teamRounds = new byte[] { 0, 0 };
            playersAlive = new ushort[] {0,0};
        }

        public override void Initilize(Entities.Room room) {
            base.Initilize(room);
            // Validate based on the room setting here.
            currentRound = 0;
            teamRounds = new byte[] { 0, 0 };
            limitRound = Constants.RoundLimits[Room.Setting];

            Initilized = true;
            PrepareRound(true);
            roundActive = true;
        }

        public override Team Winner() {
            if (teamRounds[(byte)Team.Derbaran] > teamRounds[(byte)Team.NIU])
                return Team.Derbaran;
            else
                return Team.NIU;
        }

        private bool RoundRunning()
        {
            if (playersAlive[(byte)Team.Derbaran] == 0 && !bombPlanted) return false; // Deb DEAD + NO BOMB
            if (playersAlive[(byte)Team.NIU] == 0) return true; // NIU : DEAD
            if (bombPlanted && bombDefused) return false; // Bomb = Defused
            if (Room.DownTick <= 0) return false;


            return true;
        }


        public Team WinningTeam() {
            return ((bombPlanted && bombDefused) || (!bombPlanted && playersAlive[(byte)Team.Derbaran] == 0) || (!bombPlanted && Room.DownTick <= 0)) ? Team.NIU : Team.Derbaran;
        }

        public override void Process() {
            if (!roundActive && PrepareRound(false)) {
                roundActive = true;
            }

            if (roundActive) {
                playersAlive[(byte)Team.Derbaran] = (ushort)Room.Players.Select(p => p.Value).Where(p => p.IsAlive && p.Health > 0 && p.Team == Team.Derbaran).Count();
                playersAlive[(byte)Team.NIU] = (ushort)Room.Players.Select(p => p.Value).Where(p => p.IsAlive && p.Health > 0 && p.Team == Team.NIU).Count();

                if (!RoundRunning()) {
                    Team winner = WinningTeam();
                    if (teamRounds[(byte)winner] < limitRound) {
                        EndRound(winner);
                    } else {
                        Room.EndGame(WinningTeam());
                    }

                }
            }
        }

        private bool PrepareRound(bool first) {

            TimeSpan tsDiff = DateTime.Now - roundEnd;

            if (tsDiff.TotalMilliseconds >= 5000) {
                FreezeTick = false;

                if (!first)
                    currentRound++;

                if (Room.Players.Values.All(p => !p.RoundWait)) {

                    Room.Players.Values.ToList().ForEach(p => p.RoundStart());

                    Room.UpTick = 0;
                    Room.DownTick = 180000;
                    bombPlanted = false;
                    bombDefused = false;
                    bombSide = -1;

                    playersAlive[(byte)Team.Derbaran] = (ushort)Room.Players.Select(p => p.Value).Where(p => p.IsAlive && p.Health > 0 && p.Team == Team.Derbaran).Count();
                    playersAlive[(byte)Team.NIU] = (ushort)Room.Players.Select(p => p.Value).Where(p => p.IsAlive && p.Health > 0 && p.Team == Team.NIU).Count();

                    if (!first) {
                        if (currentRound > 0) {
                            if (playersAlive[0] == 0 || playersAlive[1] == 0) {
                                Team winning = Team.None;

                                if (playersAlive[0] > 0)
                                    winning = Team.Derbaran;
                                else
                                    winning = Team.NIU;

                                Room.EndGame(winning);
                                return false;
                            }
                            Room.Send((new Packets.Mission(Room)).BuildEncrypted());
                            Room.Send((new Packets.StartRound(Room)).BuildEncrypted());
                        }
                    }

                    return true;
                }
            }

            return false;
        }

        protected override void OnDeath(Entities.Player killer, Entities.Player target) {
            // TODO: Re-implement
        //    throw new System.NotImplementedException();
        }

        protected override void OnObjectDestory() {
            throw new System.NotImplementedException();
        }

        private void EndRound(Team winning) {
            roundActive = false;
            roundEnd = DateTime.Now;
            FreezeTick = true;

            foreach (Entities.Player p in Room.Players.Values)
                p.EndRound();

            if (winning != Team.None) {
                teamRounds[(byte)winning]++;
                Room.Send((new Packets.EndRound(Room, winning)).BuildEncrypted());
            }
        }

        public override bool IsGoalReached() {
            return (teamRounds[0] == limitRound || teamRounds[1] == limitRound);
        }

        private void ProcessKill() {

        }

        public override void HandleExplosives(string[] blocks, Entities.Player p) {
            if (p.IsAlive && p.Health > 0) {
                sbyte byteType = -1;
                try {
                    sbyte.TryParse(blocks[2], out byteType);
                } catch { byteType = -1; }

                switch(byteType) { // TODO: Validate item id.
                    case 0: {

                        if (p.Team == Team.Derbaran) {
                            if (!bombPlanted) {
                                // STATICS //
                                p.BombsPlanted += 1;
                                p.User.BombsPlanted += 1;

                                bombPlanted = true;
                                bombDefused = false;
                                bombSide = sbyte.Parse(blocks[4]);
                                Room.DownTick = Config.BOMBTIME;
                                Room.Send((new Packets.Explosives(blocks)).BuildEncrypted());
                            }
                        } else if (p.Team == Team.NIU) {
                            if (bombPlanted) {
                                // STATICS //
                                p.BombsDefused += 1;
                                p.User.BombsDefused += 1;

                                bombDefused = true;
                                Room.Send((new Packets.Explosives(blocks)).BuildEncrypted());
                            }
                        }
                        
                        break;
                    }
                    case 1: {
                        break;
                    }
                    case 2: {
                        break;
                    }

                    default: {
                        p.User.Disconnect(); // Cheating?
                        break;
                        }
                }
            }
        }

        public override byte CurrentRoundTeamA() {
            return teamRounds[0];
        }

        public override byte CurrentRoundTeamB() {
            return teamRounds[1];
        }

        public override ushort ScoreboardA() {
            return playersAlive[0];
        }

        public override ushort ScoreboardB() {
            return playersAlive[1];
        }
    }
}


I´m currently working on the chat system. Whispering is not coded and also the variable targetId is overflowed when someone tries to whisp. That´s due to the packet sending a negative value for targetId (targetId is a simple, unsigned byte).



Sorry for double-posting but I´ve made a lot of changes to the code and I felt like a post was needed after 2 weeks.

First of all I´M VERY SORRY, the NOTICE MANAGER WAS BUGGY. I just fixed it. The format of the messages sent were wrong and the data management was a disaster.

FIXED NOTICE MANAGER:
AlterEmu\Game\Managers\NoticeManager.cs

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

using Game.Enums;
using Game.Networking;

using MySql.Data.MySqlClient;


namespace Game.Managers
{
    class NoticeManager
    {
        List<string> ActiveNotices = new List<string>();
      
        public NoticeManager()
        {

          

        }


        public bool Load()
        {

            MySqlCommand cmd = new MySqlCommand("SELECT * FROM notices", Databases.Game.connection);
            MySqlDataReader Reader = cmd.ExecuteReader();

            int _inactiveNotices = 0;

             if(Reader.HasRows)
             {
                 
                 while(Reader.Read())
                 {
                     byte _id = Reader.GetByte("id");
                     string _message = Reader.GetString("message");
                     byte _active = Reader.GetByte("active");

                      if(_active == 1)
                      {
                          ActiveNotices.Add(_message);
                      }
                      else
                          _inactiveNotices++;
                 }

                 Log.Instance.WriteLine("Notice manager found " + ActiveNotices.Count.ToString() + " active notices");
                 Reader.Close();

                  if(ActiveNotices.Count > 0)
                  {
                      System.Timers.Timer Timer = new System.Timers.Timer();
                      Timer.Enabled = true;
                      Timer.Interval = 60000;
                      Timer.Elapsed += (sender, e) => NoticeLoop(sender, e, ActiveNotices);
                  }
             }
             else
             {
                 Reader.Close();
                 Log.Instance.WriteError("Notice manager couldn´t parse the notice table");
                 return false;

             }

           


            return true;
        }
        private static void NoticeLoop(object sender, ElapsedEventArgs e, List<string> messages)
        {
        
            Random Random = new Random();


            int _index = Random.Next(0, messages.Count());

            string _message = MessageTranslator("Notice: " + messages[_index]);

            Core.Networking.OutPacket Notice = new Packets.Chat("Server", ChatType.Notice2, _message, 100, "NULL");
            Managers.ChannelManager.Instance.SendAllLobbies(Notice.BuildEncrypted());
        }



        public static string MessageTranslator(string _message)
        {

            string _codedMessage = _message.Insert(0, ">>" + Convert.ToChar(0x1D));
            _codedMessage = _codedMessage.Replace(Convert.ToChar(0x20), Convert.ToChar(0x1D));

            

            return _codedMessage;
        }
       
        private static NoticeManager instance = null;
        public static NoticeManager Instance { get { if (instance == null) instance = new NoticeManager(); return instance; } set { } }
       
    }
}

DATABASE: The notice table was completely rebuilt

notice tables has 3 rows; id, message, active. id is a tinyint, message is a string and active is another tinyint. I uploaded an SQL dump


Maximum team difference to start a room rebuilt. Now you can configure it easily from the INI files.
CodeDragon, if you ever read this, I´m very curious about the code you used to calculate the team difference (powering and then square rooting to get the original team difference).

These modifications also allow you to configure the bomb time from the INI files too.


AlterEmu\Game\Config.cs


Code:
using Core.IO;
using System;

namespace Game {
    class Config {
        public static string AUTH_SERVER_IP = "127.0.0.1";
        public static byte SERVER_ID = 0;
        public static string SERVER_KEY = "SERVER-KEY";
        public static string SERVER_NAME = "AlterEmu";
        public static string SERVER_IP = "";
        public static int MAXIMUM_ROOM_COUNT = 5;
        public static short MAXIMUM_TEAM_DIFFERENCE = 1;
        public static double EXPRATE = 1.0;
        public static double DINARRATE = 1.0;
        public static uint LEVEL_UP_MONEY_REWARD = 25000u;
        public static string[] GAME_DATABASE;
        public static long BOMBTIME = 45000;

        public static bool Read()
        {
            INIFile configFile = new INIFile("config");
            bool result = false;
            if (configFile.Exists())
            {
                AUTH_SERVER_IP = configFile.Read("auth-server", "ip");
                SERVER_KEY = configFile.Read("auth-server", "key");
                SERVER_NAME = configFile.Read("server", "name");
                SERVER_IP = configFile.Read("server", "bindip");

                //Game configuration

                string _expRate = configFile.Read("game-configuration", "exprate");
                string _dinarRate = configFile.Read("game-configuration", "dinarrate");
                string _bombTime = configFile.Read("game-configuration", "bombtime");
                string _maximumTeamDifference = configFile.Read("game-configuration", "team_difference");

                 double.TryParse(_expRate, out EXPRATE);
                 double.TryParse(_dinarRate, out DINARRATE);
                 long.TryParse(_bombTime, out BOMBTIME);
                 Int16.TryParse(_maximumTeamDifference, out MAXIMUM_TEAM_DIFFERENCE);

                 if (EXPRATE == 0 || DINARRATE == 0)
                 {
                     Log.Instance.WriteError("Exprate or dinarrate values are 0 or not a number " + _expRate + "/" + _dinarRate);
                     Log.Instance.WriteError("Using default values");
                     EXPRATE = 1.0;
                     DINARRATE = 1.0;
                 }
                 else
                 {
                     //Just in case some dumbass tries to put a negative number
                     EXPRATE = Math.Abs(EXPRATE);
                     DINARRATE = Math.Abs(DINARRATE);
                 }

                 if (BOMBTIME == 0)
                 {
                     Log.Instance.WriteError("Invalid bomb time or the time is 0 " + _bombTime);
                     Log.Instance.WriteError("Using default value");
                     BOMBTIME = 45000;
                 }
                 else
                     BOMBTIME = Math.Abs(BOMBTIME);  //Trolling is not allowed ;)

                 if (MAXIMUM_TEAM_DIFFERENCE == 0)
                 {
                     Log.Instance.WriteError("Invalid team difference or team difference is 0 " + _maximumTeamDifference);
                     Log.Instance.WriteError("Using default value");
                     MAXIMUM_TEAM_DIFFERENCE = 1;
                 }
                 else
                     MAXIMUM_TEAM_DIFFERENCE = Math.Abs(MAXIMUM_TEAM_DIFFERENCE);

                GAME_DATABASE = new string[]
                {
                    configFile.Read("game-database", "host"),
                    configFile.Read("game-database", "port"),
                    configFile.Read("game-database", "username"),
                    configFile.Read("game-database", "password"),
                    configFile.Read("game-database", "database")
                };
                result = true;
            }
            return result;
        }
    }
}


AlterEmu\Game\Handlers\Game\Lobby\Start.cs

Code:
using System;
using System.Linq;
using Game.Enums;
using Game.Managers;

namespace Game.Handlers.Game {
    class Start : Networking.GameDataHandler {
        protected override void Handle() {
            if (Room.Master == Player.Id) {
                if (Room.State == Enums.RoomState.Waiting) {
                    lock (Room._playerLock) {
                        if (Room.Players.All(p => p.Value.Ready)) {
                            var debTeam = Room.Players.Select(n => n.Value).Where(n => n.Team == Enums.Team.Derbaran).Count();
                            var niuTeam = Room.Players.Select(n => n.Value).Where(n => n.Team == Enums.Team.NIU).Count();

                       /*     int diff = (int)Math.Sqrt(Math.Pow(debTeam - niuTeam, 2));
                           
                            //Codedragon method: 1. debTeam - niuTeam
                            //  2.  difference^2
                            //  3.  Square root of 2
                            // The result is the same of debTeam - niu Team
                            // Was it a check?????


                         
                            if (Config.MAXIMUM_TEAM_DIFFERENCE >= diff) {
                                respond = updateLobby = true;
                                type = Enums.GameSubs.StartReply;
                                Room.State = Enums.RoomState.Playing;
                                Set(2, Room.Map);
                                Room.Start();
                            }
                        */

                            //DarkRaptor Method: In WarRock you can always start a room if player difference is 1, BUT only if you aren´t alone!!!

                            int _curTeamDifference = debTeam - niuTeam;

                             if(_curTeamDifference <= Config.MAXIMUM_TEAM_DIFFERENCE && (debTeam > 0) && (niuTeam > 0))
                             {
                                 respond = updateLobby = true;
                                 type = Enums.GameSubs.StartReply;
                                 Room.State = Enums.RoomState.Playing;
                                 Set(2, Room.Map);
                                 Room.Start();
                             }
                             else
                             {
                               string _message = "You need more players to start this room";
                               Core.Networking.OutPacket NeedMorePlayers = new Packets.Chat("SYSTEM", ChatType.Room_ToAll,NoticeManager.MessageTranslator(_message), 999, "NULL");
                               Room.Send(NeedMorePlayers.BuildEncrypted());
                             }

                        }
                    }
                }
            } else {
                Player.User.Disconnect(); // Cheating? - Not a master!
            }
        }
    }
}

AlterEmu\Game\Modes\Explosive.cs
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Game.Enums;

namespace Game.Modes {
    public class Explosive : Objects.GameMode {

        private byte limitRound;
        private byte currentRound;
        private byte[] teamRounds;

        private ushort[] playersAlive;

        private bool roundActive = false;
        private sbyte bombSide = -1;
        private bool bombPlanted = false;
        private bool bombDefused = false;

        private DateTime roundEnd;

        private readonly object _syncObject;

        public Explosive()
            : base(0, "Explosive") {
            _syncObject = new object();
            currentRound = 0;
            teamRounds = new byte[] { 0, 0 };
            playersAlive = new ushort[] {0,0};
        }

        public override void Initilize(Entities.Room room) {
            base.Initilize(room);
            // Validate based on the room setting here.
            currentRound = 0;
            teamRounds = new byte[] { 0, 0 };
            limitRound = Constants.RoundLimits[Room.Setting];

            Initilized = true;
            PrepareRound(true);
            roundActive = true;
        }

        public override Team Winner() {
            if (teamRounds[(byte)Team.Derbaran] > teamRounds[(byte)Team.NIU])
                return Team.Derbaran;
            else
                return Team.NIU;
        }

        private bool RoundRunning()
        {
            if (playersAlive[(byte)Team.Derbaran] == 0 && !bombPlanted) return false; // Deb DEAD + NO BOMB
            if (playersAlive[(byte)Team.NIU] == 0) return true; // NIU : DEAD
            if (bombPlanted && bombDefused) return false; // Bomb = Defused
            if (Room.DownTick <= 0) return false;


            return true;
        }


        public Team WinningTeam() {
            return ((bombPlanted && bombDefused) || (!bombPlanted && playersAlive[(byte)Team.Derbaran] == 0) || (!bombPlanted && Room.DownTick <= 0)) ? Team.NIU : Team.Derbaran;
        }

        public override void Process() {
            if (!roundActive && PrepareRound(false)) {
                roundActive = true;
            }

            if (roundActive) {
                playersAlive[(byte)Team.Derbaran] = (ushort)Room.Players.Select(p => p.Value).Where(p => p.IsAlive && p.Health > 0 && p.Team == Team.Derbaran).Count();
                playersAlive[(byte)Team.NIU] = (ushort)Room.Players.Select(p => p.Value).Where(p => p.IsAlive && p.Health > 0 && p.Team == Team.NIU).Count();

                if (!RoundRunning()) {
                    Team winner = WinningTeam();
                    if (teamRounds[(byte)winner] < limitRound) {
                        EndRound(winner);
                    } else {
                        Room.EndGame(WinningTeam());
                    }

                }
            }
        }

        private bool PrepareRound(bool first) {

            TimeSpan tsDiff = DateTime.Now - roundEnd;

            if (tsDiff.TotalMilliseconds >= 5000) {
                FreezeTick = false;

                if (!first)
                    currentRound++;

                if (Room.Players.Values.All(p => !p.RoundWait)) {

                    Room.Players.Values.ToList().ForEach(p => p.RoundStart());

                    Room.UpTick = 0;
                    Room.DownTick = 180000;
                    bombPlanted = false;
                    bombDefused = false;
                    bombSide = -1;

                    playersAlive[(byte)Team.Derbaran] = (ushort)Room.Players.Select(p => p.Value).Where(p => p.IsAlive && p.Health > 0 && p.Team == Team.Derbaran).Count();
                    playersAlive[(byte)Team.NIU] = (ushort)Room.Players.Select(p => p.Value).Where(p => p.IsAlive && p.Health > 0 && p.Team == Team.NIU).Count();

                    if (!first) {
                        if (currentRound > 0) {
                            if (playersAlive[0] == 0 || playersAlive[1] == 0) {
                                Team winning = Team.None;

                                if (playersAlive[0] > 0)
                                    winning = Team.Derbaran;
                                else
                                    winning = Team.NIU;

                                Room.EndGame(winning);
                                return false;
                            }
                            Room.Send((new Packets.Mission(Room)).BuildEncrypted());
                            Room.Send((new Packets.StartRound(Room)).BuildEncrypted());
                        }
                    }

                    return true;
                }
            }

            return false;
        }

        protected override void OnDeath(Entities.Player killer, Entities.Player target) {
            // TODO: Re-implement
        //    throw new System.NotImplementedException();
        }

        protected override void OnObjectDestory() {
            throw new System.NotImplementedException();
        }

        private void EndRound(Team winning) {
            roundActive = false;
            roundEnd = DateTime.Now;
            FreezeTick = true;

            foreach (Entities.Player p in Room.Players.Values)
                p.EndRound();

            if (winning != Team.None) {
                teamRounds[(byte)winning]++;
                Room.Send((new Packets.EndRound(Room, winning)).BuildEncrypted());
            }
        }

        public override bool IsGoalReached() {
            return (teamRounds[0] == limitRound || teamRounds[1] == limitRound);
        }

        private void ProcessKill() {

        }

        public override void HandleExplosives(string[] blocks, Entities.Player p) {
            if (p.IsAlive && p.Health > 0) {
                sbyte byteType = -1;
                try {
                    sbyte.TryParse(blocks[2], out byteType);
                } catch { byteType = -1; }

                switch(byteType) { // TODO: Validate item id.
                    case 0: {

                        if (p.Team == Team.Derbaran) {
                            if (!bombPlanted) {
                                // STATICS //
                                p.BombsPlanted += 1;
                                p.User.BombsPlanted += 1;

                                bombPlanted = true;
                                bombDefused = false;
                                bombSide = sbyte.Parse(blocks[4]);
                                Room.DownTick = Config.BOMBTIME;
                                Room.Send((new Packets.Explosives(blocks)).BuildEncrypted());
                            }
                        } else if (p.Team == Team.NIU) {
                            if (bombPlanted) {
                                // STATICS //
                                p.BombsDefused += 1;
                                p.User.BombsDefused += 1;

                                bombDefused = true;
                                Room.Send((new Packets.Explosives(blocks)).BuildEncrypted());
                            }
                        }
                        
                        break;
                    }
                    case 1: {
                        break;
                    }
                    case 2: {
                        break;
                    }

                    default: {
                        p.User.Disconnect(); // Cheating?
                        break;
                        }
                }
            }
        }

        public override byte CurrentRoundTeamA() {
            return teamRounds[0];
        }

        public override byte CurrentRoundTeamB() {
            return teamRounds[1];
        }

        public override ushort ScoreboardA() {
            return playersAlive[0];
        }

        public override ushort ScoreboardB() {
            return playersAlive[1];
        }
    }
}

Program.cs updated to show some config values:

AlterEmu\Game\Program.cs

Code:
*
 * Alter EMU - Written By CodeDragon
 * 
 * Emulator Verion: 5
 * Credits:
 *  - CodeDragon
 *  - Basser
 *          
 * Special Thanks:
 *  - ToXiiC
 * 
 */

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;


using Core.Networking;
using Core.Enums;
using Game.Networking;


namespace Game
{
    class Program
    {
        private static bool isRunning = false;
        public static ServerClient AuthServer;

      

    

        static void Main(string[] args)
        {

            Console.Title = "AlterEmu - [Starting] Game Server";
            Console.WindowWidth = Console.LargestWindowWidth - 25;
            Console.WindowHeight = Console.LargestWindowHeight - 25;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine(@" _______        _______ _______  ______ _______ _______ _     _");
            Console.WriteLine(@" |_____| |         |    |______ |_____/ |______ |  |  | |     |");
            Console.WriteLine(@" |     | |_____    |    |______ |    \_ |______ |  |  | |_____|");
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.WriteLine(new string('_', Console.WindowWidth));
            Console.WriteLine();
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Modded by DarkRaptor");
            Console.ForegroundColor = ConsoleColor.Gray;


            if (!Config.Read())
            {
                Log.Instance.WriteError("Failed to load the configuration file.");
                Console.ReadKey();
                return;
            }

            if (!Databases.Init())
            {
                Log.Instance.WriteError("Failed to initilize all database connections.");
                Console.ReadKey();
                return;
            }

            if (!Managers.ItemManager.Instance.Load())
            {
                Log.Instance.WriteError("Failed to initilize the item manager.");
                Console.ReadKey();
                return;
            }

            if (!Managers.MapManager.Instance.Load())
            {
                Log.Instance.WriteError("Failed to initilize the map manager.");
                Console.ReadKey();
                return;
            }

            //DarkRaptor Notice Manager

            if(!Managers.NoticeManager.Instance.Load())
            {
                Log.Instance.WriteError("Failed to initialize the notice manager.");
                Console.ReadKey();
                return;
            }

            // CONNECT TO THE AUTHORIZATION SERVER //
            AuthServer = new ServerClient(Config.AUTH_SERVER_IP, (int)Ports.Internal);
            if (!AuthServer.Connect())
            {
                return;
            }

            if (!new UDPListener((int)Ports.UDP1).Start())
            {
                return;
            }

            if (!new UDPListener((int)Ports.UDP2).Start())
            {
                return;
            }

            //Configuration reminder (in case everything is well configured)

            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Dinar rate is: " + Config.DINARRATE.ToString());
            Console.WriteLine("EXP rate is: " + Config.EXPRATE.ToString());
            Console.WriteLine("Bomb time is " + Config.BOMBTIME.ToString());
            Console.WriteLine("Maximum team difference is " + Config.MAXIMUM_TEAM_DIFFERENCE.ToString());
            Console.ForegroundColor = ConsoleColor.Gray;

            // Start up the listener :)
            isRunning = (new ServerListener((int)Ports.Game)).Start();

                           
    
 
 

            while (isRunning)
            {

                Parallel.ForEach(Managers.UserManager.Instance.Sessions.Values, user =>
                {
                    if (user.Authorized)
                        user.SendPing();
                });

                Console.Title = "AlterEmu - Game Server - Players online: " + Managers.UserManager.Instance.Sessions.Values.Count;

                Thread.Sleep(5000);


            }
        }
    }
}

I´m currently working on the chat system. Whispering is not coded and also the variable targetId is overflowed when someone tries to whisp. That´s due to the packet sending a negative value for targetId (targetId is a simple, unsigned uint).
 
Last edited:
◝(⁰▿⁰)◜Smile◝ (⁰▿⁰)◜
Developer
Joined
May 29, 2007
Messages
2,167
Reaction score
899
Re: Expanding CodeDragon´s Chapter 1 sources

The reason why I took the power and then used a square root in the check was because to neutralize a negative value. Example: if there are no players on the deb team and 2 players on the NIU then the result would be -2, a normal human would know that the difference is 2. Your broke the code by removing that part by the way. You don't need to do it the very complicated way like I did. You can just grab the absolute value with Math.Abs().

Code:
int teamDifference = Math.Abs(debTeam - niuTeam);

Then replace this line:
Code:
if (Config.MAXIMUM_TEAM_DIFFERENCE >= diff) {

With this:
Code:
if (teamDifference <= Config.MAXIMUM_TEAM_DIFFERENCE) {

This would make it work correctly plus make it configurable.
 
Last edited:
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

Doh, Silly me. I didn´t thought of negatives values. Updated.

EDIT: I´m seriously considering stopping this project. None but CodeDragon and me has contributed to it, but I´ve received a lot of PMs asking about setting up a server using these files. None read the first post, where I clearly SAY: THESE FILES ARE NOT STABLE blablabla.

So, in the end, a lot of leechers but 0 contributions. It takes a lot of time to explain my changes file by file but people keep scrolling down to the latest upload.
 
Last edited:
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

Since none has contributed but CodeDragon and it takes a lot of time to explain and update my changes, I have decided to stop posting fixes. I still work on this release and I will post it one I finish it (everything but the userlist packet, sorry. It is private), but I wont update this post with code, only screenshots.

What I added so far:

* Improved the healing system. Now its fully funcional.

* Improved the player damage calculations to be more like the vanilla game. Headshot detected properly.

* Added Team Death Match to CQC and UO/BG.

* Added Conquest.

* Flags are working.

* Ammo recharge works.

* You can place any item on the ground and use it (TMA has to be debugged)

* The launcher packet is now configurable. So you can update the client easily.

* Level check for the Itemshop added.

* Level check for joining a room added.

* Fixed notice manager

* Added some config parameters: bombTime, dinar and exp rate, maximum team difference

* Added the classic coupon system. You can add new codes in the database.

* Added some missing packets: death confirmed, logout packet.


Im working on vehicles a.t.m. Once I finish them Ill move to clan system and then I will fix a couple of bugs in CQC and some bugs about the lobby update. The last step will consist on more security checks and optimization.
 
Newbie Spellweaver
Joined
Jan 22, 2009
Messages
42
Reaction score
2
Re: Expanding CodeDragon´s Chapter 1 sources

Why Darkraptor, no stoped this proyect is the best, my Clan alwais check you proyect to found bug and help you in this proyect.no lisend the leechers, the are boy wich -15 yeard old. my clan wich 23 player alwais help you. we know that is not much test the server and find bug but if you know another task on the server in which we can help tell me
 
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

Why Darkraptor, no stoped this proyect is the best, my Clan alwais check you proyect to found bug and help you in this proyect.no lisend the leechers, the are boy wich -15 yeard old. my clan wich 23 player alwais help you. we know that is not much test the server and find bug but if you know another task on the server in which we can help tell me

I don know what you mean since I never created a test server. I believe you wanted to say that you downloaded the sources and tested them with your clan, which is ok, but I see no reports here, so its kind of useless for me.

Please, read again. I still work on this release but I wont post more code nor explain what I changed since none cares but CodeDragon. Once I finish I will release everything except the userlist packet and handler. But as I said, no more code explanations, no more long posts with detailed spoilers. It takes a lot of time not only to post my changes, but to update them everytime I find a bug which I didn notice before and Its not worth it since I see no contributions.

I hope you understand my decision.
 
Newbie Spellweaver
Joined
Jan 22, 2009
Messages
42
Reaction score
2
Re: Expanding CodeDragon´s Chapter 1 sources

ok DarkRaptor i understand you decision, ok DarkRaptor i understand you decision, if you need something to help tell me.

lol Location=Spain i dont know you are spanish, yo soy español tambien xd
 
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

What I really need (and I believe this section needs too) is real contributions, and more developers. Leechers and testers are fine, but without contributions (even if they are crappy like mine) there is no development.

There is something that beginners should know: if you arent capable of programming in your sources language, then you should start learning the programming lang. instead of creating a server. I started with C# 7 months ago and after many hours of practise I started to study CodeDragon sources to understand how WarRock works. This is the only path to have a real decent server. Programming skills + experience + deep understanding of the game mechanics.

Maybe one day someone will release a full emulator, good enough for someone without knowledge to start a server following a simple tutorial. But believe me, even then it will be difficult. Updating, adding new gamemodes, customizing the server... you need at least some knowledge.

And this is it for the offtopic, from now on stick to the topic please.
 
◝(⁰▿⁰)◜Smile◝ (⁰▿⁰)◜
Developer
Joined
May 29, 2007
Messages
2,167
Reaction score
899
Re: Expanding CodeDragon´s Chapter 1 sources

I'm updating my release so people have the latest fixed version available.
I'll add you do the thank you list for finding these bugs and making an attempt to fix them.

Actually I should be studying too but I was too tired this evening.

More "fixes":

* Fixed a bug about the server not updating the DB properly when leveling up:

AlterEmu\Game\Entities\User.cs The insertion was incorrrect: rows missing in the DB
Code:
 Databases.Game.Insert("game_levels_gained", new Dictionary<string, object>() {
                    { "id", this.ID },
                    {"game_id", this.Displayname },
                    { "current_level", currentLevel},
                    { "levels_gained", levelsGained },
                    { "timestamp", nowTimeStamp }
                });

[DB] the levels_gained table has been modified: Now it has 5 rows: id, game_id, current_level, levels_gained, timestamp.

ID is an int type row. game_id has been changed from int to Text. Now the log works like this: id (player id matching the DB index), game_id (nickname of the player, can be changed to use user id lol), current_level (player´s level), levels_gained (number of levels gained during the level up, most times 1), timestamp (date in unix format).

* Fixed a bug in the level up event. The player could lose the money earned if he logged out the game without buying anything (anything that updated the DB info, to be more accurate).

I've managed to fix this bug correctly I messed the columns up, and the id in the database. I had a duplicate line, the second user_id should be re-named to game_id since I was implementing it based on each game. Anyways, here is the correct code

Code:
                Databases.Game.Insert("game_levels_gained", new Dictionary<string, object>() {
                    { "user_id", this.ID },
                    { "game_id", 0 }, // TODO
                    { "current_level", currentLevel},
                    { "levels_gained", levelsGained },
                    { "timestamp", nowTimeStamp }
                });

Also make sure you run this MySQL database command to fix the table!
Code:
DROP TABLE IF EXISTS `game_levels_gained`;
CREATE TABLE IF NOT EXISTS `game_levels_gained` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `game_id` int(10) unsigned NOT NULL,
  `current_level` tinyint(3) unsigned NOT NULL,
  `levels_gained` tinyint(3) unsigned NOT NULL,
  `timestamp` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

I also updated the experience & dinar rate system you've written, I removed the math.abs and replaced the values with the default(1.0). I also re-wrote the error message that displays if the rates are configured wrongly.

Code:
                // Experience & Dinar rates
                string _expRate = configFile.Read("game-configuration", "exprate");
                string _dinarRate = configFile.Read("game-configuration", "dinarrate");
                double.TryParse(_expRate, out EXP_RATE);
                double.TryParse(_dinarRate, out DINAR_RATE);


                if (EXP_RATE <= 0 || DINAR_RATE <= 0)
                {
                    Log.Instance.WriteError("One of the experience or dinar rates has been configured in a wrong way " + _expRate + "/" + _dinarRate);
                    Log.Instance.WriteError("Setting the wrong configured rate(s) to the default state.");


                    if (EXP_RATE <= 0)
                        EXP_RATE = 1.0;


                    if (DINAR_RATE <= 0)
                        DINAR_RATE = 1.0;
                }

I also updated my code for team starting, it now load the maximum team difference from the config file.

These updates will be uploaded soon.
 
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

Thanks you very much for updating the server and my "fixes". I have improved a lot during my experience with your files, but some of the earliest fixes can be improved due to my poor understanding of your files. Ill be updating the post once I finish testing extensively my own files to make sure Im not releasing shenanigans.

Again thanks.
 
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

Actually I´m rewritting most of them because when I started fixing CodeDragon´s release I wasn´t as skilled as I am now. I should be posting some updates in a month or so after further testing.
 
◝(⁰▿⁰)◜Smile◝ (⁰▿⁰)◜
Developer
Joined
May 29, 2007
Messages
2,167
Reaction score
899
Re: Expanding CodeDragon´s Chapter 1 sources

Actually I´m rewriting most of them because when I started fixing CodeDragon´s release I wasn´t as skilled as I am now. I should be posting some updates in a month or so after further testing.
Let me know about the changes and new stuff you find out! I'll fully support you!
 
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
53
Reaction score
18
Re: Expanding CodeDragon´s Chapter 1 sources

Not a "big" release but I found a little bug in Entities\Room.cs

Code:
    for (byte i = 0; i < 0; i++) 
                Flags[i] = -1;

Don´t ask me why because I didn´t went into it too much, but this line is setting Flag[0] to 0 and basically breaking the clean and intelligent Flag system and therefore bugging any FlagCapture handler you code. Every flag must be -1 but the spawn flags, whose states are 0 and 1 depending on the owner.

To fix it, just change it to:

Code:
    for (byte i = 0; i < flagCount; i++) 
                Flags[i] = -1;

this is my handler for FlagCapture.cs. If you are smart enough to code Team DeathMatch, I´m sure you´ll find this useful. If you are not, then wait for me to release it:

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using Game.Enums;

namespace Game.Handlers.Game.Ingame
{
    sealed class FlagCapture : Networking.GameDataHandler
    {
        protected override void Handle()
        {
            if (Room.State == RoomState.Playing && (Room.Channel == ChannelType.Urban_Ops || Room.Channel == ChannelType.Battle_Group))
            {
                if (!Player.IsAlive || Player.Team == Team.None)
                    return;
                //Flag information: 0 DERB, 1 NIU, -1 WHITE
                //TODO BUILD ENUMERATION FOR THIS :D :D :D
                byte _capturedFlagId = GetByte(2);
                Objects.Map CurrentMap = Managers.MapManager.Instance.Get(Room.Map);

                if (CurrentMap == null || CurrentMap.SpawnFlags.Contains(_capturedFlagId)) //do not rely on Room.Flag (0-1) to determine the spawn flag...CONQUEST!
                    return;

                if (Room.Flags[_capturedFlagId] == -1) //neutral flag
                    Room.Flags[_capturedFlagId] = (sbyte)Player.Team;
                else
                    Room.Flags[_capturedFlagId] = -1;

                Set(2, _capturedFlagId);
                Set(3, Room.Flags[_capturedFlagId]);
                respond = true;

                Player.AddFlags();

                //Calls the event to update gamemode
                Room.CurrentGameMode.OnFlagCapture(Player);
            }
            else
                Player.User.Disconnect(); //cheating
        }

    }
}

This is only a snippet. For the handler to work you need to make some changes to GameModes.cs and Player.cs. It´s pretty easy, though.
 
Back
Top