Greetings,




Here is the source code for Knights of Grumthorr(2) along with required dependency information.
First of all you will need to purchase and download the game to have access to the media.
Second you will need to create a folder on your pc called 'fantasyrts'
Put the contents of the media folder into a folder fantasyrts/media.




Create a folder called fantasyrts/sdl
Copy the .cs files for the c# version of sdl2 into this folder.
Download the sdl dlls as well.
The sdl components you will require include sdl2, sdl2_image, sdl2_ttf and sdl2_mixer.




Finally copy the two source files as found below this text into fantasyrts/




The first is fantasyrts.csproj
This is a small file that contains some parameters that determine how the program compiles.
The second is Program.cs.




You will need a recent version of .NET (c#) to run and test and compile the program.
Go to your command prompt (run->cmd) and navigate to the fantasyrts folder




"cd\fantasyrts" for example.




Then you can use the following:
dotnet run
to run the program.




Or you can use dotnet publish -r win-x64 to compile the program into a release version.




Before I attach the two files I will give a basic licence for you to use my code with:
Licence:




"You may use this Program.cs and associated source code and files as you see fit. This licence is
supplied on a 'common sense' basis - in other words - use it as you would hope someone might use
your own code and treat it with respect. Beyond that - go nuts with it. As a small time one man
developer if I put a law-speak licence in do you really think I'm going to have the ability to enforce it?"




Here are the two files:




fantasyrts.csproj
<Project Sdk="Microsoft.NET.Sdk">




<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>




</Project>




And Program.cs




You can edit both of them with a simple text editor such as notepad++ or notepad.exe




Have fun!///////////////////////////////////////////////////
//fantasyrts - Knights of Grumthorr 2 - Version 2.00
//Version 18-Mar-2021 - Matt Lloyd
///////////////////////////////////////////////////
//


////////////////////////////////

Total Lines of Code:24967

Code

//Fantasy RTS Engine - KOG2
//Matt Lloyd 2020/2021
//'Knights of Grumthorr - 2'
//
//1-Oct-2020 - Bug Fix - data/data2 with 'description='
//26-Oct-2020 - Bug Fix - Count Varna 700+ times on skirmish mode in report
//26-Oct-2020 - Enhancements - snow/desert mode, overrides for scenery, multiple factions possible now.
//1-Nov-2020 - Enhancements - override for rgbbk
//1-Nov-2020 - Enhancements - gui.txt file modified for simpler gui arrangement..less cluttered.
//1-Nov-2020 - Release Version 1.0
//24-Feb-2021 - Enhancements - greater modding capability and adjustments to gui things
//25-Feb-2021 - Enhancements - death animation support added, high rate of fire support added.
//25-Feb-2021 - Enhancements - better mod support.
//26-Feb-2021 - Enhancements relating to fog
//28-Feb-2021 - Enhancements - gui link better to missions
//28-Feb-2021 - Enhancements - playable faction specific to missions....
//28-Feb-2021 - Enhancements - added second idle animation
//28-Feb-2021 - Enhancements - more flexible image loading
//28-Feb-2021 - Enhancements - better mod support.
//28-Feb-2021 - Bug Fix/Enhancements - better resource loading error handling.
//1-Mar-2021 - Enhancements - allow mission choice by name rather than index as well.
//2-Mar-2021 - Enhancements - map details (decor)
//5-Mar-2021 - Release Version 1.1
//7-Mar-2021 - Enhancements - "extraunits=" - to add more units without changing units.txt file
//7-Mar-2021 - Enhancements - new unit characteristics coded in, mob, animosity, hatred, craftsman, planar, slow, woodsman, stupidity, frenzy
//7-Mar-2021 - Bug Fix with decor
//9-Mar-2021 - Enhancements - formations, in-battle ui,
//10-Mar-2021 - Enhancements - controllable spawners (choose what to build).
//11-Mar-2021 - Enhancements to gui and AI spawners...
//////////////////////////////////////////////////////////
//12-Mar-2021 - Enhancements Officially changed to Version 2.0, KoG2 - grumthorr2 as well.
//12-Mar-2021 - KOG2 maxmission defaults to 36 at the beginning.
//12-Mar-2021 - Planar Bug Fix - Shouldn't be able to build planar units at a builder (design decision)
//12-Mar-2021 - LocalStorage.getitem, LocalStorage.setitem
//12-Mar-2021 - Marked missions as complete or incomplete.
//13-Mar-2021 - Enhancements - Language Localisation Features
//15-Mar-2021 - Enhancements to handle Chinese text. Also shield added for defend units. And a bug fix for missing check on a -1 value for an array index (would never occur though).
//15-Mar-2021 - Bug Fix - Chinese Text was being truncated - this has now been fixed with a user defined variable 'fontwmultiplier' which should be 1 or greater or left unassigned.
//15-Mar-2021 - Bug Fix / Other - Removed Network commands and Bug fix for record=1 flag when quitting and thread running causing a crash..
//16-Mar-2021 - Fix for wmultiplier on Fonts. for ascii only strings.
//16-Mar-2021 - Released to Steam for build verification by Valve.
//17-Mar-2021 - Bug Fix for chinese Text - additional fix for wmultiplier for unicode fonts.
//17-Mar-2021 - Bug fix in TranslateWord returning "" instead of the word at times.
//18-Mar-2021 - Culture Info added ?
//19-Mar-2021 - Enhancement - spellcasters buff friendly units now.
//19-Mar-2021 - Re-Enabled Network Command
//20-Mar-2021 - Enhancement - armour/attack modifier (percentage multiplier) enabled via config file.
//20-Mar-2021 - Graphical Glitch fixed with Unit drawing...
//21-Mar-2021 - Added +/- and unit circles
//21-Mar-2021 - Enhancement - added custom scenarios via level editor to game.
//21-Mar-2021 - Language Enhancement/Translation
//22-Mar-2021 - Bug Fix - scaling of sprites in Gui due to comma/period difference in region settings.
//22-Mar-2021 - Editor language allowed for, Selection indicator added. Pause with pause key on keyboard.
//23-Mar-2021 - Minor graphical glitch fixed. Trigger enhancements.
//24-Mar-2021 - Updated ALTMODE in Gui.ALTMODE to change more often. Improved Targeting.
//25-Mar-2021 - Threaded music loading....Trigger *ANY, *FRIEND, *ENEMY and CREATE and REMOVE
//26-Mar-2021 - Optimisation added (MAXINDEX)...to units and a few others.
//27-Mar-2021 - Bug Fix....
//Important note about the Bug fix on 27-Mar-2021
//The bug was introduced on 26-Mar-2021 when 'selectingtime' was added to the code
//This has now been altered so that the bug does not occur.
//That means the versions of the game released prior to 26-Mar-2021 were fine
//And now those released after are fine again too.
//27-Mar-2021 - Disabled Zoom. Adjusted WAITSELECTINGTIME from 30 to 6. Added Bullet.MAXINDEX = 0 on change gamestate. tmpbrave added...
//28-Mar-2021 - Translation Class optimised search by sorting based on length of string....(NOT IMPLEMENTED)
//28-Mar-2021 - Building spells in...minimap gui enhanced/bug fix, language reporting...
//30-Mar-2021 - added uid
//1-apr-2021 - tidied up web request.
//2-apr-2021 - enhanced some graphical features....And After Action 10 minute Replay
//2-apr-2021 - Action Replay added at end of battle. (actually 3-apr, but code changes recorded as 2-Apr)
///////////////////////////////////////////
//7apr2021 - fixed Editor restart
//9apr2021 - new spells...
//11apr2021 - fixed some minor frame+id glitches, added extra altimage handling, some saving of seeds as an attempt to fix replay (didn't work)
//12-16apr2021 - various minor enhancements
//17apr2021 - moved clicker and targeticon into gui section without hardcoding their presence.
//17apr2021 - altered AI//hmultiplier
//18apr2021 - gamestate transitions implemented....fadeout/fadein added.
//19apr2021 - fixed glitch with editor trees...
//20apr2021 - toggle gui panels, auto calculate offy/offx
//24apr2021 - addressed spawner selection bug
//25apr2021 - addressed replay bug with onscreen feature, Translation binary search (in case list gets long)
//26apr2021 - enabled demo mode
//28apr2021 - pathfinding quick pathing added.
//2may2021 - note Matt - eventually ADD the following: Transforming Units, Flying Units including dual ground/air units and Transports. All are possible with simple changes/additions.
//3may2021 Transforming units added but not tested.....Transported units added but not tested also....
//4may2021 - adding flying units....
//6may2021 - added replay MAXLENGTH back in....
//22may2021 resizable window in windowed mode.....
//29may2021 - sprite rotations through directions takes time rather than instant
//29may2021 - multithreaded pathfinding
//2jun2021 - sprite batching in part.....
//12jul2021 - bound demon code added but not tested or used yet.
//28jul2021 - added deathfx code for sound effects....
//2sep2021 - minor addition - allowed shock to be specified in file instead of shocktrooper. Also allowed TITLE set in text file.
//2sep2021 - tech addition (large update) (seems complete sort of)....
//2sep2021 - bug fix - canflyandwalk units fixed...somewhat. transform bug fix also. transporting also works now.
//4sep2021 - bug fix with transporting units.
///////////////////////////////////////////
//9sep2021 - spawners can be constrained.
//10sep2021 - defaultgridw/h, and mission based gridw/h, trigger for chatter image....and audio,
//10sep2021 - adding individual character names to units in the armies.
//12sep2021 - allow 'exit to mission name' via a trigger
//13sep2021 - bug fix with dead units (if dead animation present)
//14sep2021 - a few changes...
//15sep2021 - need los added
//16sep2021 - NOSHOWABILITY added
//17sep2021 - added menu mini map feature.


using System;
using System.Diagnostics;
using System.Threading;
using System.Net; //15mar2021
using System.IO;
using System.Text;//13Mar2021//1apr2021
using System.Runtime.InteropServices;
using SDL2;
using System.Globalization;

namespace fantasyrts
{


///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class Config
    {
        public static int NOUPDATEINDEMOMODE = 0;//18sep2021
        public static int USEDELTATIME = 0;//18sep2021
        public static int delta;//18sep2021
        public static int UNLOCKFRAMERATE = 0;//18sep2021
        public static int AUTOPLAY = 0;//18sep2021
        public static int NOSHOWABILITY = 0;//16sep2021
        public static int OPTIMISEFIRES = 0;//15sep2021
        public static int TILEFOG = 0;//15sep2021
        public static int CLUMP = 0;//15sep2021
        public static int NOREPLAY = 0;//15sep2021
        public static int FASTFRAMECHECK = 0;//14sep2021
        public static bool USETECH = true;//false;//2sep2021
        public static bool THREADEDPATHING = false;//29may2021
        public static bool SLOWROTATE = true;//29may2021
        public static int WINDOWRESIZE = 0;//22may2021
        public static bool ALLOWFLYING = true;//4may2021 //flag while debugging...will set to true later....
        public static bool FREEDEMO = false;
        public static int freedemo = 60 * 60 * 10;//26apr2021
        public static bool AUTOCALCOFFSETS = false;//20apr2021
        public static uint FRAMETIME = 15;//18apr2021
        public static bool BLOCKPRECALC = true;//11apr2021
        public static bool ALLOWREPLAY = true;//2apr2021
        public static bool GETDATA = false;//1apr2021
        public static string autodetectlang = "";
//30mar2021
        public static string uid = "1234";//30mar2021
        public static bool DEBUG = false; //23mar2021 moved up here from below...
        public static bool NOMETRICS = false;//remember to change this appropriately...
        public static bool TRANSLATEGUI = true;//21mar2021
        public static bool USEICONCIRCLES = false;//21mar2021
        public static bool USECOVERFLAG = false;//21mar2021
        public static bool USEFEETCIRCLES = false;//21mar2021
        public static int ARMOURPCT = 100;//20mar2021
        public static int ATTACKPCT = 100;//20mar2021
        public static int HEALTHPCT = 100;//20mar2021
        public static bool useUNICODE = false; //ml15mar2021
        public static bool bestiarychk = false; //5apr2021
        public static bool KOG2 = true;
        public static bool RECORD = false;
        public static bool STREAMLOAD = true; //28Feb2021
        public static bool STREAMLOADAUDIO = false;//25mar2021
        public static int USEHEIGHTS = 0;
        public static bool DODEBRIEF = true;
        public static bool TESTDEBRIEF = false;
        public static bool USEPATHFILE = false;
        public static int FACTOR = 10; //determines size of armies and so on.....10 seems to be about sufficient for the game to run very well still with lots of units on the map.
        public static int NORMALSPEED = 10;//23mar2021 (not used yet...)
        public static int LOWSPECSPEED = 6;//23mar2021 (not used yet...)
        public static string configfile; //28Feb2021
        public static string guifile;
        public static string campaignfile;
        public static string customcampaignfile;
        public static string unitsfile;
        public static string wordsfile = ""; //13mar2021
        public static string techfile = "";//2sep2021
        public static string defaultfontfile;
        public static int largefontsize;
        public static int smallfontsize;
        public static int normalfontsize;
        public static string audioclickfile;
        public static string offsetfile = "";//20apr2021
        public static bool FINISHEDOFFSETS = false;//20apr2021
        public static string logofile;
        public static string fogfile;
        public static int logowidth;
        public static int logoheight;
        public static int fogwidth;
        public static int fogheight;
        public static int hires = 0;
        public static string custommapfolder;
        public static string usercampaignfolder = "";
        public static string usercampaignfile = "";
        public static string custommapprefix = "custom_";
        public static string skirmishmessage = "Take control of the portals to spawn units.|Eliminate the enemy.";
        public static int FONTALIAS = 4;
        public static long precalcused = 0;
        public static long seekpathused = 0;
        public static long seekpathfailed = 0;
        public static long seekpathsuccess = 0 ;
        public static long maxbmenutime = 0;
        public static long maxumusictime = 0;
        public static long maxmapupdatepostime = 0;
        public static long maxmapcorrecttime = 0;
        public static long maxmaperrors = 0;
        public static long maxunitupdatetime = 0;
        public static long maxbullettime = 0;
        public static long maxbloodtime = 0;
        public static long maxselecttime = 0;
        public static long maxtriggertime = 0;
        public static long maxdrawtime = 0;
        public static long maxanimate = 0;
        public static long maxwalk = 0;
        public static long maxupdate = 0;
        public static long maxatt = 0;
        public static long[] totrtime = new long[600];
        public static long[] totutime = new long[600];
        public static long sumr = 0;
        public static long sumu = 0;
        public static long UTIMELOW = 800;
        public static long RUNNINGSPEED = 0;
        public static long runningspeed = 0;
        public static bool loaded = false;
        public static int loadpct = 0;
    }

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class Game
    {
        public static string NETTITLE = "grumthorr";
        public static string TITLE = "Knights of Grumthorr";
        public static string AUTHOR = "Matt Lloyd";
        public static string MUSIC = "Eric Matyas, soundimage.org";
        public static string YEAR = "2021";
        public static string VERSION = "2.00";
        public static int VERSIONINT = 200;
        public static string VERSIONSTR = "20210603"; //14apr2021(and subsequent)
        //
        public static bool restart = false;//13mar2021
        public IntPtr renderer;
        public IntPtr window;
        public IntPtr screen;
        public bool takepicture;
        //public int recordframe;
        public static bool running = true;
        //for screenshots.....
        //unsafe takepicture Pointer
        //
        public static bool EDITOR = false;
        public static int EDITED = -1; //7apr2021
        public RenderList[] renderlist;
        public static Replay[] replay;//2apr2021
        public Images[] images;
        public Fonts[] fonts;
        public Audios[] audios;
        //public static long killcount; //13mar2021
        public static int killcount; //13mar2021
        //
        public Map map;
        public Unit[] units;
        public Unit[] templates;
        public Mission[] missions;
        public Tech[] techs;//2sep2021
        //public Mission tutorial;
        public int missionid;
        public int nextmissionid;
        public int failedmissionid;
        public Gui[] gui;
        public Bullet[] bullets;
        public Trigger[] triggers;
        public Blood[] blood;
        public Gibbet[] gibbet; //2apr2021
        //
        //
        public static int neutralfog = 0; //26Feb2021
        public static int fogoff = 0; //26Feb2021
        //
        public static int topmissionindex = 0;
        public static int previousmissionindex = -1;//2apr2021
        public static int chosenmissionindex = -1;
        public static int ochosenmissionindex = -1;//17sep2021
        public static int maxmission = 1;
        public static int overridemaxmission = 0;//13sep2021
        public static int countcustoms = 0;
        //
        public int SW;
        public int SH;
        //public static int SSW;
        //public static int SSH;
        public int frame;
        public int gamestartframe;//2apr2021
        //
        public int mx;
        public int my;
        public int rmx;//21apr2021
        public int rmy;//21apr2021
        public int wmx;//21apr2021
        public int wmy;//21apr2021
        public static int RCORNERX;//21apr2021
        public static int RCORNERY;//21apr2021
        public static int TMPCORNERX;//21apr2021
        public static int TMPCORNERY;//21apr2021
        //public int exitmx;//2apr2021
        //public int exitmy;//2apr2021
        public int omx;
        public int omy;
        public int smx;
        public int smy;
        public int fmx;
        public int fmy;
        public bool mlclick;
        public bool mldown;
        //public bool exitclick;//2apr2021
        //public bool exitdown;//2apr2021
        public bool mrclick;
        public int mlclickframe;
        public bool mrdown;
        public int mwheel;
        public float zoom;
        public int zoomcornerx;
        public int zoomcornery;
        public bool paused;
        public int minimapframe;
        public bool demomode;
        public static int checksum;//2apr2021
        public static int ordergivenframe;
        public static int EXTRAPATHINGTIME = 60 * 4;
        public static int leftcontrolkey = 0;
        public static int[] numberkeys = new int[10];
        public static int[] numberkeysframe = new int[10];
        public static bool SPAWNERSELECTED = false; //10mar2021
        public static bool NONSPAWNERSELECTED = false;//11mar2021
        public static int SPELLCASTERSELECTED = -1;//28mar2021
        public static int SPELLCASTERLEVEL = 0;//28mar2021
        public static bool SPELLSACTIVE = true;//false;//28mar2021
        public static int EDITMODE_TREE = 1;
        public static int EDITMODE_ROCK = 2;
        public static int EDITMODE_WALL = 3;
        public static int EDITMODE_UNIT = 0;
        public static int EDITMODE_TRIGGER = 4;
        public static int EDITMODE_ENTERTEXT = 5; //from triggers....
        public static int EDITMODE_HEIGHT = 6;
        public static int EDITMODE;
        public static int editgridx;
        public static int editgridy;
        public static int editindex;
        public static string editname;
        public static int editkeypressed = 0;
        public static int recordkeypressed = 0;
        public static int backupkeypressed = 0;
        public static string edittriggerstring = "";
        public static bool editshiftheld = false;
        //
        public static int FULLSCREEN = 0;
        public static int FXVOLUME = 100;
        public static int MUSICVOLUME = 100;
        public static int oFXVOLUME = 100;
        public static int oMUSICVOLUME = 100;
        //
        public static int RESOLUTIONX;
        public static int RESOLUTIONY;
        public static int FRAMERATE;
        public static bool NODELAY = true;
        //
        public static int CORNERX = 0;
        public static int CORNERY = 0;
        public static int CORNERSPEED = 5;
        public static int CORNEREDGEDIST = 50;
        public static int LOCKCORNER = 0;
        public static int HORIZONTALFORMATION = 0; //14apr2021
        public static int VERTICALFORMATION = 0; //14apr2021
        //
        //
        public int gamestate;
        public int oldgamestate;
        public int newgamestate;
        public static int restartgamestate; //26mar2021
        public static int selectingtime;//26mar2021
        public static int WAITSELECTINGTIME = 6;//26mar2021
        //public static int transitionframe;
        //public static int TRANSITIONTIME = 30;
        public bool playerready;
        public bool skirmish;
        public bool onscreen;
        public bool victorymessage;
        public bool playingtutorial;
        public static int CAT_GAMESTATE_LOGO = 0;
        public static int CAT_GAMESTATE_MENU = 10;
        public static int CAT_GAMESTATE_NEWCONTINUE = 20;
        public static int CAT_GAMESTATE_GAME = 1000;
        public static int CAT_GAMESTATE_DEBRIEF = 999;
        public static int CAT_GAMESTATE_DEBRIEF2 = 998;
        public static int CAT_GAMESTATE_REPLAY = 997; //2apr2021
        public static int CAT_GAMESTATE_MATCH_PLAY = 1000;
        public static int CAT_GAMESTATE_STARTLEVEL = 1050;
        public static int CAT_GAMESTATE_GAMEOVER = 1100;
        public static int CAT_GAMESTATE_NEWLEVEL = 1200;
        public static int CAT_GAMESTATE_ENDLEVEL = 1300;
        public static int CAT_GAMESTATE_GUIMENUS = 10000;
        //
        public static int PLAYERFACTION = 0;
        public static int SKIRMISHENEMYFACTION = 0;
        public static int EDITORPFACTION = 0; //22mar2021
        public static int EDITOREFACTION = 0; //22mar2021
        public static int GAMEENDSTATE = 0;
        public static int GAMEENDSTATE_VICTORY = 1;
        public static int GAMEENDSTATE_DEFEAT = 2;
        public static int MAXFACTIONS = 16;
        //
        public int gameovertime;
        //public int nextleveltime;
        //
        public static int healthbar = -1;
        public static int whiteflag = -1;
        public static int shadowup = -1;//15sep2021
        public static int shadowleft = -1;//15sep2021
        public static int shadowright = -1;//15sep2021
        public static int shadowoffy = -1;//15sep2021
        public static int shadowoffx = -1;//15sep2021
        public static int shield = -1; //15mar2021
        public static int lightning = -1;//28mar2021
        public static int whirlwind = -1;//28mar2021
        public static int targeticon = -1;//16apr2021
        public static int spellball = -1;//12apr2021
        public static int clicker = -1;//15apr2021
        public static int clickerframe = -1;//15apr2021
        public static int clickerrow = 0;//15apr2021
        public static int clickerx = 0;//15apr2021
        public static int clickery = 0;//15apr2021
        public static int BLUEBALL = 0;
        public static int GREENBALL = 1;
        public static int PURPLEBALL = 2;
        public static int ORANGEBALL = 3;
        public static int REDBALL = 4;
        public static bool audioon;
        public static int iconplus = -1;//21mar2021
        public static int iconminus = -1;//21mar2021
        public static int iconcircles = -1;//21mar2021
        public static int groupselected = -1;//21mar2021
        public static bool showingselectedicons = false; //22mar2021
        public static bool togglepause = false;//22mar2021
        public static int mouseoverunitid = -1;
        public static bool anyselected = false;//16apr2021
        public static int formation = 0;//2apr2021
        public static int ai_direction = 0;//17apr2021
        public static int[] newtrees;//24apr2021
        public static int totalscore = 0;//18sep2021
        public static int maxtotalscore = 0;//18sep2021
        public static bool scoredirty = true;//18sep2021
        //

///////////////////Method Definition///////////////
        public Game(IntPtr r)
        {
            ////////////////////////
            //primary initialisation
            gamestate = Game.CAT_GAMESTATE_LOGO;
            renderlist = new RenderList[0];
            images = new Images[0];
            fonts = new Fonts[0];
            audios = new Audios[0];
            replay = new Replay[0];//2apr2021
            newtrees = new int[0];//24apr2021
            renderer = r;
            frame = 0;
            mx = 0;
            my = 0;
            omx = 0;
            omy = 0;
            mlclick = false;
            mldown = false;
            mrclick = false;
            mrdown = false;
            Game.audioon = true;
            //Game.NODELAY = true;
            //start--------------//13mar2021
            units = new Unit[0];
            templates = new Unit[0];
            missions = new Mission[0];
            techs = new Tech[0];//2sep2021
            gui = new Gui[0];
            bullets = new Bullet[0];
            triggers = new Trigger[0];
            blood = new Blood[0];
            topmissionindex = 0;
            chosenmissionindex = -1;
            ochosenmissionindex = -1;//17sep2021
            maxmission = 1;
            countcustoms = 0;
            leftcontrolkey = 0;
            numberkeys = new int[10];
            numberkeysframe = new int[10];
            SPAWNERSELECTED = false; //10mar2021
            NONSPAWNERSELECTED = false;//11mar2021
            healthbar = -1;
            whiteflag = -1;
            shadowleft = -1;//15sep2021
            shadowup = -1;//15sep2021
            shadowright = -1;//15sep2021
            shadowoffx = -1;//15sep2021
            shadowoffy = -1;//15sep2021
            shield = -1;
            spellball = -1;//12apr2021
            whirlwind = -1;//28mar2021
            targeticon = -1;//16apr2021
            clicker = -1;//15apr2021
            lightning=-1; //28mar2021
            iconplus = -1; //21mar2021
            iconminus = -1; //21mar2021
            iconcircles = -1; //21mar2021
            Resources.blackcat = -1;//18apr2021//minor bug fix
            Map.init();
            //end----------------//13mar2021
            initgame();
        }

///////////////////Method Definition///////////////
        public void killed(Game game,int i)
        {
            ////////////////////////
            //this method handles the elimination of units from the game.
            //when a unit's hp goes to zero this method ought to be called.
            //it sets the animation mode to the death animation if any exists
            //and handles the removing of the body from the map and so forth
            //start-----------//25Feb2021
            bool gibbets = false;
            //start-----------//4may2021
            if(units[i].flightlevel!=-1)
            {
                Map.removeflyer(i,units[i].x,units[i].y,units[i].flightlevel);
                units[i].flightlevel = -1;
            }
            //end-------------//4may2021
            if(units[i].animmode!=Unit.ANIMMODE_DEAD)
            {
                int gb = Functions.rand(0,(Gibbet.GIBMOD + 1));//17sep2021
                //if(units[i].animmodedeadframeend>0)//17sep2021
                if(units[i].animmodedeadframeend>0 && gb <= (Gibbet.GIBMOD + 1)/2)//17sep2021
                {
                    units[i].animmode = Unit.ANIMMODE_DEAD;
                    return;                
                }
                else//2apr2021
                {
                    Gibbet.GIBCOUNTER++;
                    if((Gibbet.GIBCOUNTER % Gibbet.GIBMOD)==0)
                    {
                        Gibbet.makegibbets(game,i);
                        gibbets = true;
                    }
                }
            }
            else
            {
                if(units[i].animframe < units[i].animmodedeadframeend)
                {
                    return;
                }
            }
            //end-------------//25Feb2021
            units[i].playdeathsound(game,i); //28jul2021
            Map.addbones(units[i].x,units[i].y);
            game.templates[units[i].templateid].deaths++;
            Map.removeunit(i,units[i].x,units[i].y);
            if(!gibbets)
            {
                Blood.makeblood(game,units[i].x,units[i].y+units[i].offy,(int)Functions.sign(units[i].zombie));
                if(units[i].bossmonster>0)
                {
                    for(int j=0;j<4;j++)
                    {
                        Blood.makeblood(game,units[i].x+(int)Functions.rand(-Map.GRIDW/2,Map.GRIDW/2),units[i].y+units[i].offy+(int)Functions.rand(-Map.GRIDH/2,Map.GRIDH/2),0);
                    }
                }
            }
            Game.killcount++;
        }
        private void initgame()
        {
        }

///////////////////Method Definition///////////////
        public void quit()
        {
            ////////////////////////
            //finalisation of the game upon exiting the main loop
            //handles removing all textures and sounds
            
            Game.running = false;
            try//13mar2021 added try catch
            {
                for(int i=0;i<images.Length;i++)
                {
                    if(images[i].texture!=IntPtr.Zero && images[i].loaded==true) //28Feb2021
                    {
                        LocalStorage.setitem("FREE IMAGE:"+images[i].file,"FAILED"); //24mar2021
                        SDL.SDL_DestroyTexture(images[i].texture);
                        LocalStorage.setitem("FREE IMAGE:"+images[i].file,"SUCCESS"); //24mar2021
                    }
                }
                for(int i=0;i<fonts.Length;i++)
                {
                    LocalStorage.setitem("FREE FONT:"+fonts[i].file,"FAILED"); //24mar2021
                    SDL_ttf.TTF_CloseFont(fonts[i].font);
                    LocalStorage.setitem("FREE FONT:"+fonts[i].file,"SUCCESS"); //24mar2021
                }
                for(int i=0;i<audios.Length;i++)
                {
                    if(audios[i].audio==IntPtr.Zero)//10sep2021
                    {
                        continue;//10sep2021
                    }
                    LocalStorage.setitem("FREE AUDIO:"+audios[i].file,"FAILED"); //24mar2021
                    if(audios[i].ismusic)
                    {
                        SDL_mixer.Mix_FreeMusic(audios[i].audio);
                    }
                    else
                    {
                        SDL_mixer.Mix_FreeChunk(audios[i].audio);
                    }
                    LocalStorage.setitem("FREE AUDIO:"+audios[i].file,"SUCCESS"); //24mar2021
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("Error on exit:"+e.Message);
                //LocalStorage.WriteLog("Error on exit:"+e.Message);
            }
        }

///////////////////Method Definition///////////////
        public void clearkeys()
        {
            ////////////////////////
            //reset the key state of the number keys and left control key
            Game.leftcontrolkey = 0;
            for(int i=0;i<10;i++)
            {
                Game.numberkeys[i] = 0;
            }
        }

///////////////////Method Definition///////////////
        public void getmouse()
        {
            ////////////////////////
            //get the mouse coordinates, and the click states
            //and also the drag select coordinates
            uint mouse = SDL.SDL_GetMouseState(out mx,out my);
            mlclick = false;
            mrclick = false;
            //exitclick = false;//2apr2021
            if(mouse==SDL.SDL_BUTTON(SDL.SDL_BUTTON_LEFT))
            {
                mldown = true;
                //exitdown = true;//2apr2021
            }
            else
            {
                if(mldown)
                {
                    mlclick = true;
                }
                //if(exitdown)
                //{
                //    exitclick = true;
                //}
                mldown = false;
                //exitdown = false;//2apr2021
            }
            if(mouse==SDL.SDL_BUTTON(SDL.SDL_BUTTON_RIGHT))
            {
                mrdown = true;
            }
            else
            {
                if(mrdown)
                {
                    mrclick = true;
                }
                mrdown = false;
            }
            if(SH>0 && SW>0)
            {
                float gxscale = (float)Game.RESOLUTIONX/ (float)SW;
                float gyscale = (float)Game.RESOLUTIONY/ (float)SH;
                mx = (int)((float)mx*gxscale);
                my = (int)((float)my*gyscale);
                //exitmx = mx; //2apr2021
                //exitmy = my; //2apr2021
                rmx = mx; //21apr2021
                rmy = my; //21apr2021
                wmx = mx; //21apr2021
                wmy = my; //21apr2021
            }
            if(mldown==false)
            {
                smx = mx;
                smy = my;
            }
            else
            {
                fmx = mx;
                fmy = my;
            }    
            //if(!Replay.PLAYBACK)
            //{
            //    exitclick = false;
            //    exitdown = false;
            //}
        }
    }
    //
    //start-------------//28Feb2021

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class StreamResources
    {
        public static int TOLERANCE = 60 * 5;
        public static int SHORTTOLERANCE = 60 * 5;
        public static int LONGTOLERANCE = 60 * 60;
        public static int STARTTOLERANCE = 60 * 15;
        public static bool threadrunning = false;//25mar2021
        public static Audios audio = null;
        
///////////////////Method Definition///////////////
        public static void streamloadhelper(Game game)
        {
            ////////////////////////
            //handles loading of resources during the game
            //and also freeing the resources
            //manages them so that we do not hog memory with
            //graphics that are unecessarily being kept when not in use for long periods
            if(!Config.STREAMLOAD)
            {
                return;
            }
            //start------------//25mar2021
            if(threadrunning==false && Config.STREAMLOADAUDIO==true)
            {
                for(int i=0;i<game.audios.Length;i++)
                {
                    if(game.audios[i].audio==IntPtr.Zero && game.audios[i].ismusic==true)
                    {
                        threadrunning = true;
                        audio = game.audios[i];
                        Thread thread = new Thread(new ThreadStart(ThreadFunction));
                        thread.Start();    
                        break;
                    }
                }
            }
            //end--------------//25mar2021
            for(int i=0;i<game.images.Length;i++)
            {
                //start-----//18apr2021
                //if(i==Resources.blackcat)
                //{
                //    continue;
                //}
                //end-------//18apr2021
                if(game.images[i].texture!=IntPtr.Zero)
                {
                    game.images[i].okloaded = true;
                }
                if(game.frame - game.images[i].drawframe > TOLERANCE)// && game.frame > STARTTOLERANCE)
                {
                    //if(game.gamestate!=Game.CAT_GAMESTATE_GAME)//2apr2021
                    if(game.gamestate!=Game.CAT_GAMESTATE_GAME && game.gamestate!=Game.CAT_GAMESTATE_REPLAY)//2apr2021
                    {
                        Resources.FreeImage(game,i);
                    }
                }
                else
                {
                    if(game.images[i].loaded == false && game.images[i].texture==IntPtr.Zero && (game.images[i].okloaded==true || game.images[i].neverloaded==true))
                    {
                        game.images[i].texture = SDL_image.IMG_LoadTexture(game.renderer,game.images[i].file);
                        if(game.images[i].texture!=IntPtr.Zero)
                        {
                            game.images[i].loaded = true;
                            game.images[i].okloaded = true;
                            game.images[i].neverloaded = false;
                            LocalStorage.setitem("FILE LOAD:"+game.images[i].file,"LOADED");//24mar2021

                        }
                        else //24mar2021
                        {
                            LocalStorage.setitem("FILE LOAD:"+game.images[i].file,"FAILED TO LOAD");//24mar2021
                        }
                    }
                }
            }
        }
        private static void ThreadFunction()
        {
            if(audio.file!="" && audio.file!=null)//28Feb2021
            {
                audio.audio = SDL_mixer.Mix_LoadMUS(audio.file);
            }
            if(audio.audio==IntPtr.Zero)
            {
                Console.WriteLine("Could Not Load Music:"+audio.file+". Error:"+SDL.SDL_GetError());
                Network.reporterror("MusicLoadFailure:"+audio.file,false);//15mar2021
                LocalStorage.setitem("FILE LOAD:"+audio.file,"FAILED TO LOAD"); //24mar2021
            }
            else //24mar2021
            {
                LocalStorage.setitem("FILE LOAD:"+audio.file,"LOADED"); //24mar2021
            }
            threadrunning = false;
        }
    }
    //end---------------//28Feb2021

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class Resources
    {
        //
        //put all resource names in here.....
        public static int LOGO = 0;
        public static int FONT = 0;
        public static int SMALLFONT = 0;
        public static int LARGEFONT = 0;
        public static int FOG = 0;
        public static int CLICK = 0;
        public static int blackcat = -1;
        //public static int loadingbk = -1; //27mar2021
        //public static int loadingbar = -1;//27mar2021
        //temporarily do this
        //start-------------//28Feb2021

///////////////////Method Definition///////////////
        public static bool readbool(string data)
        {
            ////////////////////////
            //takes a string that contains 'true' or 'false' and returns a bool value
            //string is form left identifier=right value
            //swapped if statements around 12sep2021
            if(data.Substring(data.IndexOf("=") + 1)=="false")//this was below the other if block earlier//12sep2021
            {
                return false;
            }
            else
            {
                if(data.Substring(data.IndexOf("=") + 1)=="true")
                {
                    return true;
                }
            }
            int i;
            Int32.TryParse(data.Substring(data.IndexOf("=") + 1),out i);
            if(i<=0)
            {
                return false;
            }
            else
            {
                if(i>0)
                {
                    return true;
                }
            }
            return false; //have to return something by default...so make it false by default....
        }
        //end---------------//28Feb2021

///////////////////Method Definition///////////////
        public static uint readuint(string data)//2apr2021
        {
            uint i;
            UInt32.TryParse(data.Substring(data.IndexOf("=")+1),out i);

            return i;
        
        }
        
///////////////////Method Definition///////////////
        public static int readint(string data)
        {
            //takes a string that contains an int, with no commas or period symbols
            //and converts to an integer.
            //string is of form left identifier=right value
            int i;
            Int32.TryParse(data.Substring(data.IndexOf("=") + 1),out i);
            return i;
        }

///////////////////Method Definition///////////////
        public static float readfloat(string data)
        {
            //takes a string in 100.01 format (ie one hundred point oh-one)
            //and returns the float value
            //string is of form left identifier=right value
            
            float i;
            try
            {
                System.Globalization.NumberStyles style = System.Globalization.NumberStyles.AllowDecimalPoint; //22mar2021
                CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US"); //22mar2021
                if(!Single.TryParse(data.Substring(data.IndexOf("=") + 1),style,culture,out i)) //22mar2021
                {
                    Console.WriteLine("Error reading float:"+data);
                    i = 1.0f;
                    LocalStorage.setitem("READ FLOAT:"+readstring(data),"FAILED 1");//24mar2021
                }
                else
                {
                    LocalStorage.setitem("READ FLOAT:"+readstring(data),"SUCCESS");//24mar2021
                }
            }
            catch(Exception e)
            {
                i = 1f;
                Console.WriteLine("Error reading float:"+e.Message);
                LocalStorage.setitem("READ FLOAT:"+readstring(data),"FAILED 2");//24mar2021
            }
            return i;
        }

///////////////////Method Definition///////////////
        public static string readstring(string data)
        {
            //simply returns a string from a line that looks like x=abc
            //ie left identifier=right value
            return data.Substring(data.IndexOf("=") + 1);
        }
    
///////////////////Method Definition///////////////
        public static void AssignOffsets(Game game,string file)//20apr2021
        {
            if(file=="")
            {
                return;
            }
            try
            {
                string[] data = System.IO.File.ReadAllLines(file);
                for(int i=0;i<data.Length;i++)
                {
                    if(data[i].IndexOf("=")>0)
                    {
                        switch(data[i].Substring(0,data[i].IndexOf("=")))
                        {
                            case "image":
                                string value = readstring(data[i]);
                                string[] values = value.Split(",");
                                if(values!=null)
                                {
                                    if(values.Length==3)
                                    {
                                        string tmpname = values[0];
                                        int offx = 0;
                                        int offy = 0;
                                        Int32.TryParse(values[1],out offx);
                                        Int32.TryParse(values[2],out offy);
                                        for(int j=0;j<game.templates.Length;j++)
                                        {
                                            if(game.templates[j].catfile==tmpname)
                                            {
                                                game.templates[j].offx = offx;
                                                game.templates[j].offy = offy;
                                                game.templates[j].autocalcedoffsets = true;
                                            }
                                        }
                                    }
                                }
                            break;
                        }
                    }
                }
            }
            catch(Exception e)
            {
                string msg = e.Message;
            }
        }
        
        
///////////////////Method Definition///////////////
        public static void LoadGui(Game game, string file)
        {
            ////////////////////////
            //load the gui elements into the game.gui array
            //so that we can reference them later on
            int alti = 0;//11apr2021
            try
            {
                string[] data = System.IO.File.ReadAllLines(file);//13mar2021
                //string[] data = System.IO.File.ReadAllLines(file,System.Text.Encoding.UTF8);//13mar2021
                int count = 0;
                for(int i=0;i<data.Length;i++)
                {
                    if(data[i].IndexOf("=")>0)
                    {
                        switch(data[i].Substring(0,data[i].IndexOf("=")))
                        {
                            case "newgui":
                            count++;
                            break;
                        }
                    }
                }
                if(count>0)
                {
                    game.gui = new Gui[count];
                    int id = -1;
                    int cw = 0;
                    int ch = 0;
                    int nw = 0;
                    int nh = 0;
                    int fontsize = 0;
                    string fontfile = "";
                    for(int i=0;i<data.Length;i++)
                    {
                        if(data[i].IndexOf("=")>0)
                        {
                            switch(data[i].Substring(0,data[i].IndexOf("=")))
                            {
                                case "newgui":
                                id++;
                                game.gui[id] = new Gui(game);
                                game.gui[id].reset(game,id);
                                alti = 0;//11apr2021
                                break;
                                case "type":
                                game.gui[id].type = readint(data[i]);    
                                break;
                                case "screenname":
                                game.gui[id].screenname = readstring(data[i]);
                                break;
                                case "missionindex":
                                game.gui[id].missionindex = readint(data[i]);
                                break;
                                case "index": //28mar2021
                                game.gui[id].index = readint(data[i]); //28mar2021
                                break;//28mar2021
                                case "techlinkid"://2sep2021
                                game.gui[id].index = readint(data[i]);//2sep2021
                                break;//2sep2021
                                //start-------------//28Feb2021
                                case "missionname":
                                game.gui[id].missionname = readstring(data[i]);
                                break;
                                //end---------------//28Feb2021
                                case "topindexzero": //24Feb2021
                                game.gui[id].topindexzero = (int)Functions.abs(Functions.sign(readint(data[i])));//24Feb2021
                                break;//24Feb2021
                                case "link":
                                game.gui[id].link = readstring(data[i]);
                                break;
                                case "command":
                                game.gui[id].command = readstring(data[i]);
                                break;
                                case "title":
                                game.gui[id].title = readstring(data[i]);
                                if(Config.TRANSLATEGUI)//21mar2021
                                {
                                    game.gui[id].title = Translation.TranslateWord(game.gui[id].title,false);
                                }
                                break;
                                case "tooltip":
                                game.gui[id].tooltip = readstring(data[i]);
                                if(Config.TRANSLATEGUI)//21mar2021
                                {
                                    game.gui[id].tooltip = Translation.TranslateWord(game.gui[id].tooltip,false);
                                }
                                break;
                                case "action":
                                game.gui[id].action = readint(data[i]);
                                break;
                                case "hidden":
                                game.gui[id].hidden = readint(data[i]);
                                break;
                                case "backgroundrect":
                                    string[] tmpbk = readstring(data[i]).Split(",");
                                    if(tmpbk.Length==7)
                                    {
                                        int rx = 0;
                                        int ry = 0;
                                        int rw = 0;
                                        int rh = 0;
                                        int rgb_r = 0;
                                        int rgb_b = 0;
                                        int rgb_g = 0;
                                        Int32.TryParse(tmpbk[0],out rx);
                                        Int32.TryParse(tmpbk[1],out ry);
                                        Int32.TryParse(tmpbk[2],out rw);
                                        Int32.TryParse(tmpbk[3],out rh);
                                        Int32.TryParse(tmpbk[4],out rgb_r);
                                        Int32.TryParse(tmpbk[5],out rgb_g);
                                        Int32.TryParse(tmpbk[6],out rgb_b);
                                        game.gui[id].backgroundrect = true;
                                        game.gui[id].backgroundrectcoords[0] = rx;
                                        game.gui[id].backgroundrectcoords[1] = ry;
                                        game.gui[id].backgroundrectcoords[2] = rw;
                                        game.gui[id].backgroundrectcoords[3] = rh;
                                        game.gui[id].backgroundrectcolor[0] = (byte)rgb_r;
                                        game.gui[id].backgroundrectcolor[1] = (byte)rgb_g;
                                        game.gui[id].backgroundrectcolor[2] = (byte)rgb_b;
                                    }
                                break;
                                //start-------------//11mar2021
                                case "horizontal":
                                game.gui[id].horizontal = readint(data[i]);
                                break;
                                case "vertical":
                                game.gui[id].vertical = readint(data[i]);
                                break;
                                //end---------------//11mar2021
                                case "triggerlink":
                                game.gui[id].triggerlink = readint(data[i]);
                                break;
                                case "mission":
                                game.gui[id].mission = readint(data[i]);
                                break;
                                case "gamestate":
                                game.gui[id].gamestate = 10000 + readint(data[i]);
                                break;
                                case "nextscreenname":
                                game.gui[id].nextscreenname = readstring(data[i]);
                                break;
                                case "nextgamestate":
                                game.gui[id].nextgamestate = 10000 + readint(data[i]);
                                break;
                                case "x":
                                game.gui[id].x = readint(data[i]);
                                break;
                                case "y":
                                game.gui[id].y = readint(data[i]);
                                break;
                                case "w":
                                game.gui[id].w = readint(data[i]);
                                break;
                                case "h":
                                game.gui[id].h = readint(data[i]);
                                break;
                                case "cw":
                                cw = readint(data[i]);
                                break;
                                case "ch":
                                ch = readint(data[i]);
                                break;
                                case "nw":
                                nw = readint(data[i]);
                                break;
                                case "nh":
                                nh = readint(data[i]);
                                break;
                                case "altimage":
                                //11apr2021 - modified to be an array
                                if(alti>4)
                                {
                                    continue;
                                }
                                game.gui[id].altimagefile[alti] = readstring(data[i]);
                                bool found = false;
                                for(int j=0;j<id;j++)
                                {
                                    for(int k=0;k<alti+1;k++)
                                    {
                                        if(game.gui[j].altimagefile[alti]==game.gui[id].altimagefile[k])
                                        {
                                            found = true;
                                            game.gui[id].altimage[alti] = game.gui[j].altimage[k];
                                            break;
                                        }
                                    }
                                }
                                for(int j=0;j<id;j++)
                                {
                                    for(int k=0;k<alti+1;k++)
                                    {
                                        if(game.gui[j].imagefile==game.gui[id].altimagefile[k])
                                        {
                                            found = true;
                                            game.gui[id].altimage[alti] = game.gui[j].image;
                                            break;
                                        }
                                    }
                                }
                                if(!found){game.gui[id].altimage[alti] = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);}
                                alti++;
                                break;
                                case "image":
                                game.gui[id].imagefile = readstring(data[i]);
                                found = false;
                                for(int j=0;j<id;j++)
                                {
                                    if(game.gui[j].imagefile==game.gui[id].imagefile)
                                    {
                                        found = true;
                                        game.gui[id].image = game.gui[j].image;
                                        break;
                                    }
                                }
                                if(!found){game.gui[id].image = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);}
                                game.gui[id].tmpimage = game.gui[id].image; //30apr2021
                                break;
                                case "scale":
                                game.gui[id].scale = readfloat(data[i]);
                                break;
                                case "font":
                                fontfile = readstring(data[i]);
                                game.gui[id].fontfile = fontfile;
                                break;
                                case "ptsize":
                                fontsize = readint(data[i]);
                                game.gui[id].fontsize = fontsize;// * Config.FONTALIAS;
                                break;
                                case "loadfont":
                                found = false;
                                for(int j=0;j<id;j++)
                                {
                                    if(game.gui[j].fontfile==game.gui[id].fontfile && game.gui[j].fontsize==game.gui[id].fontsize)
                                    {
                                        found = true;
                                        game.gui[id].font = game.gui[j].font;
                                        break;
                                    }
                                }
                                if(!found)
                                {
                                    if(fontfile!="" && fontsize>0)
                                    {
                                        game.gui[id].font = Resources.LoadFont(game,fontfile,fontsize);
                                    }
                                }
                                fontfile = "";
                                fontsize = 0;
                                break;
                            }
                        }
                    }
                }
                LocalStorage.setitem("FILE LOAD:"+file,"SUCCESS");//24mar2021
            }
            catch(Exception e)
            {
                Console.WriteLine("403:"+e.Message);
                LocalStorage.setitem("FILE LOAD:"+file,"FAILED");//24mar2021
            }
        }

///////////////////Method Definition///////////////
        public static string[] processextraunits() //7mar2021
        {
            ////////////////////////
            //in the config files we can have multiple lines indicating
            //multiple files for creatures and so forth
            //this method handles getting this data before we create all our
            //templates in LoadTemplates
            string[] data = new string[0];
            try
            {
                string[] config = System.IO.File.ReadAllLines(Config.configfile);
                for(int i=0;i<config.Length;i++)
                {
                    if(config[i].IndexOf("=")>0)
                    {
                        switch(config[i].Substring(0,config[i].IndexOf("=")))
                        {
                            case "extraunits":
                            try
                            {
                                string filename = readstring(config[i]);
                                string[] data2 = System.IO.File.ReadAllLines(filename);
                                if(data2!=null && data2.Length>0)
                                {
                                    int ii = data.Length;
                                    Array.Resize<string>(ref data,data.Length + data2.Length);
                                    for(int j=0;j<data2.Length;j++)
                                    {
                                        data[ii + j] = data2[j];
                                    }                
                                }
                            }
                            catch(Exception f)
                            {
                                Console.WriteLine("Error:"+f.Message);
                            }
                            break;
                        }
                    }
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("Error:"+e.Message);
            }
            return data;
        }
        
///////////////////Method Definition///////////////
        public static void LoadTech(Game game, string file) //2sep2021
        {
            ////////////////////////
            //load all the tech templates
            //that we will use in the game.
            try
            {
                string[] data = System.IO.File.ReadAllLines(file);
                int count = 0;
                for(int i=0;i<data.Length;i++)
                {
                    if(data[i].IndexOf("=")>0)
                    {
                        switch(data[i].Substring(0,data[i].IndexOf("=")))
                        {
                            case "newtech":
                            count++;
                            break;                            
                        }
                    }
                }
                if(count>0)
                {
                    game.techs = new Tech[count];
                    int id = -1;
                    for(int i=0;i<data.Length;i++)
                    {
                        //Unit Template.....
                        if(data[i].IndexOf("=")>0)
                        {
                            switch(data[i].Substring(0,data[i].IndexOf("=")))
                            {
                                case "newtech":
                                id++;
                                game.techs[id] = new Tech();
                                game.techs[id].reset(game,id,false);
                                game.techs[id].name = readstring(data[i]);
                                game.techs[id].description = readstring(data[i]).Split("|");
                                count++;
                                break;    
                                case "description":
                                game.techs[id].description = readstring(data[i]).Split("|");
                                break;
                                case "tooltip":
                                game.techs[id].tooltip = readstring(data[i]);
                                break;
                                case "displayname":
                                game.techs[id].displayname = readstring(data[i]);
                                break;
                                case "cellwidth":
                                game.techs[id].cw = readint(data[i]);
                                break;
                                case "cellheight":
                                game.techs[id].ch = readint(data[i]);
                                break;
                                case "cellswide":
                                game.techs[id].nw = readint(data[i]);
                                break;
                                case "cellshigh":
                                game.techs[id].nh = readint(data[i]);
                                break;
                                case "effectname":
                                game.techs[id].effectname = readstring(data[i]);
                                break;
                                case "effectint":
                                game.techs[id].effectint = readint(data[i]);
                                break;
                                case "parseeffect": //needed to parse the effect name and apply the effect int as required....
                                Tech.parseeffect(game,id);
                                break;
                                case "researchtime":
                                game.techs[id].researchtime = 60 * readint(data[i]); //multiply by frames per second....
                                break;
                                case "image":
                                game.techs[id].imgfile = readstring(data[i]);
                                bool found = false;
                                for(int j=0;j<id;j++)
                                {
                                    if(game.techs[j].imgfile==game.techs[id].imgfile)
                                    {
                                        found = true;
                                        game.techs[id].img = game.techs[j].img;
                                        break;
                                    }
                                }
                                if(!found)
                                {
                                    game.techs[id].img = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,game.techs[id].cw,game.techs[id].ch,game.techs[id].nw,game.techs[id].nh);
                                }
                                break;
                                case "frame":
                                game.techs[id].imgframe = readint(data[i]);
                                break;
                                case "guilinkid":
                                game.techs[id].guilinkid = readint(data[i]);
                                break;
                                case "faction":
                                game.techs[id].faction = readint(data[i]);
                                break;
                            }
                        }
                    }
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("222:"+e.Message);
                LocalStorage.setitem("FILE LOAD:"+file,"FAILED");//24mar2021
            }
        }
///////////////////Method Definition///////////////
        public static void LoadTemplates(Game game, string file)
        {
            ////////////////////////
            //load all the creature/unit templates
            //that we will use in the game.
            try
            {
                string[] data = System.IO.File.ReadAllLines(file);
                //start-------------//7mar2021
                string[] data2 = processextraunits();
                if(data2!=null && data2.Length>0)
                {
                    int ii = data.Length;
                    Array.Resize<string>(ref data,data.Length + data2.Length);
                    for(int i=0;i<data2.Length;i++)
                    {
                        data[ii + i] = data2[i];
                    }
                }
                //end---------------//7mar2021
                int count = 0;
                for(int i=0;i<data.Length;i++)
                {
                    //Unit Template.....
                    if(data[i].IndexOf("=")>0)
                    {
                        switch(data[i].Substring(0,data[i].IndexOf("=")))
                        {
                            case "newtemplate":
                            count++;
                            break;                            
                        }
                    }
                }
                if(count>0)
                {
                    game.templates = new Unit[count];
                    int id = -1;
                    int cw = 0;
                    int ch = 0;
                    int nw = 0;
                    int nh = 0;
                    for(int i=0;i<data.Length;i++)
                    {
                        //Unit Template.....
                        if(data[i].IndexOf("=")>0)
                        {
                            switch(data[i].Substring(0,data[i].IndexOf("=")))
                            {
                                case "newtemplate":
                                id++;
                                game.templates[id] = new Unit(game);
                                game.templates[id].reset(game,id);
                                game.templates[id].name = readstring(data[i]);
                                game.templates[id].description = readstring(data[i]).Split("|");
                                game.templates[id].charactername = "";//10sep2021 default it to blank to start with....
                                game.templates[id].displaycharactername = 0;//10sep2021
                                count++;
                                break;    
                                //start--------------//13mar2021
                                case "displayname":
                                game.templates[id].displayname = readstring(data[i]);
                                //start-----------------//20mar2021
                                if(game.templates[id].description[0]==game.templates[id].name)
                                {
                                    game.templates[id].description[0] = readstring(data[i]);
                                }
                                //end-------------------//20mar2021
                                break;
                                //end----------------//13mar2021
                                case "faction":
                                game.templates[id].faction = readint(data[i]);
                                break;
                                case "cellwidth":
                                cw = readint(data[i]);
                                game.templates[id].cw = cw;
                                break;
                                case "cellheight":
                                ch = readint(data[i]);
                                game.templates[id].ch = ch;
                                break;
                                case "frameswide":
                                nw = readint(data[i]);
                                break;
                                case "frameshigh":
                                nh = readint(data[i]);
                                break;
                                //9apr2021 hires stuff
                                case "hires":
                                if(Config.hires==0) //can switch it off if we wish....
                                {
                                    continue;
                                }
                                game.templates[id].cathiresfile = readstring(data[i]);
                                bool found = false;
                                for(int j=0;j<id;j++)
                                {
                                    if(game.templates[j].cathiresfile==game.templates[id].cathiresfile)
                                    {
                                        found = true;
                                        game.templates[id].cathires = game.templates[j].cathires;
                                        break;
                                    }
                                }
                                if(!found)
                                {
                                    //9apr2021 observe - double the resolution, otherwise the same....
                                    //"hires=filename" should appear in the txt file immediately following the original 'image=' line....
                                    game.templates[id].cathires = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw * 2,ch * 2,nw,nh);
                                }
                                break;
                                case "image":
                                game.templates[id].catfile = readstring(data[i]);
                                found = false;
                                for(int j=0;j<id;j++)
                                {
                                    if(game.templates[j].catfile==game.templates[id].catfile)
                                    {
                                        found = true;
                                        game.templates[id].cat = game.templates[j].cat;
                                        break;
                                    }
                                }
                                if(!found)
                                {
                                    game.templates[id].cat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                    game.templates[id].offxa = new int[nw*nh]; //20apr2021
                                    game.templates[id].offya = new int[nw*nh]; //20apr2021
                                }
                                break;
                                case "enemyimage":
                                game.templates[id].ecatfile = readstring(data[i]);
                                found = false;
                                for(int j=0;j<id;j++)
                                {
                                    if(game.templates[j].ecatfile==game.templates[id].ecatfile)
                                    {
                                        found = true;
                                        game.templates[id].ecat = game.templates[j].ecat;
                                        break;
                                    }
                                }
                                if(!found)
                                {
                                    game.templates[id].ecat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                }
                                break;
                                case "friendlyimage":
                                game.templates[id].fcatfile = readstring(data[i]);
                                found = false;
                                for(int j=0;j<id;j++)
                                {
                                    if(game.templates[j].fcatfile==game.templates[id].fcatfile)
                                    {
                                        found = true;
                                        game.templates[id].fcat = game.templates[j].fcat;
                                        break;
                                    }
                                }
                                if(!found)
                                {
                                    game.templates[id].fcat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                }
                                break;
                                case "controlpoint":
                                game.templates[id].controlpoint = readint(data[i]);
                                break;
                                case "framesperdirn":
                                game.templates[id].framesperdirn = readint(data[i]);
                                break;
                                case "nodirn":
                                game.templates[id].nodirn = readint(data[i]);
                                break;
                                case "offy":
                                game.templates[id].offy = readint(data[i]);
                                break;
                                case "mirror":
                                if(readint(data[i])==1)
                                {
                                    game.templates[id].mirrorleftright = true;
                                }
                                break;
                                case "description":
                                game.templates[id].description = readstring(data[i]).Split("|");
                                break;
                                case "basehp":
                                //game.templates[id].basehp = readint(data[i]);//20mar2021
                                game.templates[id].basehp = readint(data[i]) * Config.HEALTHPCT / 100;//20mar2021
                                //round to the nearest 5 points
                                game.templates[id].basehp += (5 - (game.templates[id].basehp % 5)) * Functions.sign(game.templates[id].basehp % 5);//20mar2021
                                game.templates[id].hp = game.templates[id].basehp;
                                break;
                                case "armour":
                                //game.templates[id].armour = readint(data[i]); //20mar2021
                                game.templates[id].armour = readint(data[i]) * Config.ARMOURPCT / 100;//20mar2021
                                break;
                                case "damage":
                                //game.templates[id].damage = readint(data[i]);//20mar2021
                                game.templates[id].damage = readint(data[i]) * Config.ATTACKPCT / 100;//20mar2021
                                break;
                                //start--------------//2sep2021
                                case "guilinkid":
                                game.templates[id].techguilinkid = readint(data[i]);
                                break;
                                case "researchneeded":
                                game.templates[id].unresearchedbydefault = readint(data[i]);
                                break;
                                //end----------------//2sep2021
                                case "firebullet":
                                game.templates[id].firebullet = readint(data[i]);
                                break;
                                case "range":
                                game.templates[id].firerange = readint(data[i]);
                                break;
                                case "needlos"://15sep2021
                                game.templates[id].needlos = readint(data[i]);
                                break;
                                case "damage2":
                                //game.templates[id].damage2 = readint(data[i]);//20mar2021
                                game.templates[id].damage2 = readint(data[i]) * Config.ATTACKPCT / 100;//20mar2021
                                break;
                                case "range2":
                                game.templates[id].firerange2 = readint(data[i]);
                                break;
                                case "splash"://2sep2021
                                game.templates[id].splash = readint(data[i]);
                                break;
                                case "levelxp":
                                game.templates[id].levelxp = readint(data[i]);
                                break;
                                case "xpvalue":
                                game.templates[id].xpvalue = readint(data[i]);
                                break;
                                case "prefermobiletargets"://18sep2021
                                game.templates[id].prefermobiletargets = readint(data[i]);
                                break;
                                case "spellcaster":
                                game.templates[id].spellcaster = readint(data[i]);
                                break;
                                case "notabuffer": //15apr2021
                                game.templates[id].notabuffer = readint(data[i]);
                                break;
                                case "extragibbet"://18sep2021
                                game.templates[id].extragibbet = readint(data[i]);
                                break;
                                case "firespell":
                                game.templates[id].firespell = readint(data[i]);
                                break;
                                case "points"://17sep2021
                                game.templates[id].points = readint(data[i]);
                                break;
                                case "powerspell":
                                game.templates[id].powerspell = readint(data[i]);
                                break;
                                case "healer":
                                game.templates[id].healer = readint(data[i]);
                                break;
                                case "zombiemaster":
                                game.templates[id].zombiemaster = readint(data[i]);
                                break;
                                case "banishment": //12mar2021
                                game.templates[id].banish = readint(data[i]);
                                break;
                                case "dustcloud":
                                game.templates[id].dustcloud = readint(data[i]);
                                break;
                                case "timid":
                                game.templates[id].timid = readint(data[i]);
                                break;
                                case "hitandrun":
                                game.templates[id].hitandrun = readint(data[i]);
                                break;
                                case "buildpenalty": //20mar2021
                                game.templates[id].buildpenalty = readint(data[i]);//20mar2021
                                break;//20mar2021
                                case "brave":
                                game.templates[id].brave = readint(data[i]);
                                break;
                                //start-----------//01apr2021
                                case "spellability":
                                game.templates[id].spellability = readint(data[i]);
                                break;
                                case "ping"://16sep2021
                                game.templates[id].ping = readint(data[i]);
                                break;
                                case "spelldefense": //magic resistance....
                                game.templates[id].spelldefense = readint(data[i]);
                                break;
                                //start--------------//4may2021
                                case "canfly":
                                game.templates[id].canfly = readint(data[i]);
                                break;
                                case "canflyandwalk":
                                game.templates[id].canflyandwalk = readint(data[i]);
                                break;
                                case "canattackair":
                                game.templates[id].canattackair = readint(data[i]);
                                break;
                                //end----------------//4may2021
                                //start--------------//3may2021
                                case "magicrelease": //for getting out of transports
                                game.templates[id].magicrelease = readint(data[i]);
                                if(game.templates[id].magicrelease>0)
                                {
                                    game.templates[id].magicrelease = Unit.MAGICRELEASE;
                                }
                                break;
                                case "magictransform": //for transforming into a different unit
                                game.templates[id].magictransform = readint(data[i]);
                                if(game.templates[id].magictransform>0)
                                {
                                    game.templates[id].magictransform = Unit.MAGICTRANSFORM;
                                }
                                break;
                                case "transforminto":
                                game.templates[id].transforminto = readstring(data[i]);
                                break;
                                case "transformrequires":
                                game.templates[id].transformrequires = readstring(data[i]); //pipe separated list of entries....
                                //currently we don't have any requirements...
                                break;
                                case "transportcapacity":
                                game.templates[id].transportcapacity = readint(data[i]);
                                if(game.templates[id].transportcapacity>0)
                                {
                                    game.templates[id].transportarray = new int[game.templates[id].transportcapacity];
                                }
                                break;
                                case "transportsize":
                                game.templates[id].transportsize = readint(data[i]);
                                break;
                                //end----------------//3may2021
                                //start--------------//9apr2021
                                case "magicsummoner":
                                game.templates[id].magiczombiemaster = readint(data[i]);
                                if(game.templates[id].magiczombiemaster>0)
                                {
                                    game.templates[id].magiczombiemaster = Unit.MAGICZOMBIEMASTER;
                                }
                                break;
                                case "magiczombiemaster"://redundant version alias
                                game.templates[id].magiczombiemaster = readint(data[i]);
                                if(game.templates[id].magiczombiemaster>0)
                                {
                                    game.templates[id].magiczombiemaster = Unit.MAGICZOMBIEMASTER;
                                }
                                break;
                                case "magicleader":
                                game.templates[id].magicleader = readint(data[i]);
                                if(game.templates[id].magicleader>0)
                                {
                                    game.templates[id].magicleader = Unit.MAGICLEADER;
                                }
                                break;
                                //end----------------//9apr2021
                                case "magicfrenzy":
                                game.templates[id].magicfrenzy = readint(data[i]);
                                if(game.templates[id].magicfrenzy>0)
                                {
                                    game.templates[id].magicfrenzy = Unit.MAGICFRENZY;
                                }
                                break;
                                case "magicdoom":
                                game.templates[id].magicdoom = readint(data[i]);
                                if(game.templates[id].magicdoom>0)
                                {
                                    game.templates[id].magicdoom = Unit.MAGICDOOM;
                                }
                                break;
                                case "magicdefense":
                                game.templates[id].magicdef = readint(data[i]);
                                if(game.templates[id].magicdef>0)
                                {
                                    game.templates[id].magicdef = Unit.MAGICDEF;
                                }
                                break;
                                case "magicdef": //redundancy
                                game.templates[id].magicdef = readint(data[i]);
                                if(game.templates[id].magicdef>0)
                                {
                                    game.templates[id].magicdef = Unit.MAGICDEF;
                                }
                                break;
                                //end-------------//01apr2021
                                //start---------------//28mar2021
                                case "magicweb":
                                game.templates[id].magicweb = readint(data[i]);
                                if(game.templates[id].magicweb>0)
                                {
                                    game.templates[id].magicweb = Unit.MAGICWEB;
                                }
                                break;
                                case "magicgas":
                                game.templates[id].magicgas = readint(data[i]);
                                if(game.templates[id].magicgas>0)
                                {
                                    game.templates[id].magicgas = Unit.MAGICGAS;
                                }
                                break;
                                case "magichaste":
                                game.templates[id].magichaste = readint(data[i]);
                                if(game.templates[id].magichaste>0)
                                {
                                    game.templates[id].magichaste = Unit.MAGICHASTE;
                                }
                                break;
                                case "magicfear":
                                game.templates[id].magicfear = readint(data[i]);
                                if(game.templates[id].magicfear>0)
                                {
                                    game.templates[id].magicfear = Unit.MAGICFEAR;
                                }
                                break;
                                case "magicshield":
                                game.templates[id].magicshield = readint(data[i]);
                                if(game.templates[id].magicshield>0)
                                {
                                    game.templates[id].magicshield = Unit.MAGICSHIELD;
                                }
                                break;
                                case "magicstorm":
                                game.templates[id].magicstorm = readint(data[i]);
                                if(game.templates[id].magicstorm>0)
                                {
                                    game.templates[id].magicstorm = Unit.MAGICSTORM;
                                }
                                break;
                                case "magicsword":
                                game.templates[id].magicsword = readint(data[i]);
                                if(game.templates[id].magicsword>0)
                                {
                                    game.templates[id].magicsword = Unit.MAGICSWORD;
                                }
                                break;
                                case "magicstealth":
                                game.templates[id].magicstealth = readint(data[i]);
                                if(game.templates[id].magicstealth>0)
                                {
                                    game.templates[id].magicstealth = Unit.MAGICSTEALTH;
                                }
                                break;
                                case "magicplant":
                                game.templates[id].magicplant = readint(data[i]);
                                if(game.templates[id].magicplant>0)
                                {
                                    game.templates[id].magicplant = Unit.MAGICPLANT;
                                }
                                break;
                                case "magicwind":
                                game.templates[id].magicwind = readint(data[i]);
                                if(game.templates[id].magicwind>0)
                                {
                                    game.templates[id].magicwind = Unit.MAGICWIND;
                                }
                                break;
                                //end-----------------//28mar2021
                                case "highfirerate": //25Feb2021
                                game.templates[id].highfirerate = readint(data[i]);
                                break;
                                //start-------------//7mar2021
                                case "mob":
                                game.templates[id].mob = readint(data[i]);
                                break;
                                case "hatred":
                                game.templates[id].hatred = readint(data[i]);
                                break;
                                case "craftsman":
                                game.templates[id].craftsman = readint(data[i]);
                                break;
                                case "planar":
                                game.templates[id].planar = readint(data[i]);
                                break;
                                case "slow":
                                game.templates[id].slow = readint(data[i]);
                                break;
                                case "woodsman":
                                game.templates[id].woodsman = readint(data[i]);
                                break;
                                case "stupid":
                                game.templates[id].stupid = readint(data[i]);
                                break;
                                case "frenzy":
                                game.templates[id].frenzy = readint(data[i]);
                                break;
                                //end---------------//7mar2021
                                case "shocktroops":
                                game.templates[id].shock = readint(data[i]);
                                break;
                                case "shock": //2sep2021
                                game.templates[id].shock = readint(data[i]);//2sep2021
                                break;//2sep2021
                                case "stealth":
                                game.templates[id].stealth = readint(data[i]);
                                break;
                                case "damagex":
                                game.templates[id].damagex = readint(data[i]);
                                break;
                                case "fearsome":
                                game.templates[id].fearsome = readint(data[i]);
                                break;
                                case "leader":
                                game.templates[id].leader = readint(data[i]);
                                break;
                                case "bounddemon"://12jul2021
                                game.templates[id].bounddemon = readint(data[i]);
                                break;
                                case "spawner":
                                game.templates[id].spawner = readstring(data[i]);
                                game.templates[id].spawnerconstraint = "*";
                                break;
                                case "spawnerconstraint": //9sep2021
                                game.templates[id].spawnerconstraint = readstring(data[i]);
                                break;
                                case "spawnercount":
                                game.templates[id].spawnercount = readint(data[i]);
                                break;
                                case "spawnertime":
                                game.templates[id].spawnertime = readint(data[i]);
                                break;
                                case "bossmonster":
                                game.templates[id].bossmonster = readint(data[i]);
                                break;
                                case "flammable":
                                game.templates[id].flammable = readint(data[i]);
                                break;
                                case "regeneration":
                                game.templates[id].regeneration = readint(data[i]);
                                break;
                                case "zombie":
                                game.templates[id].zombie = readint(data[i]);
                                break;
                                case "evilfire":
                                game.templates[id].firespell = - readint(data[i]);
                                break;
                                case "sacrificial":
                                game.templates[id].sacrificial = readint(data[i]);
                                break;
                                case "cansacrifice":
                                game.templates[id].cansacrifice = readint(data[i]);
                                break;
                                case "animosity":
                                game.templates[id].animosity = readint(data[i]);
                                break;
                                //start-----------//25Feb2021
                                case "deadframestart":
                                game.templates[id].animmodedeadframestart = readint(data[i]);
                                break;
                                case "deadframeend":
                                game.templates[id].animmodedeadframeend = readint(data[i]);
                                break;
                                //end-------------//25Feb2021
                                //start-------------//28Feb2021
                                case "idle2framestart":
                                game.templates[id].animmodeidle2framestart = readint(data[i]);
                                break;
                                case "idle2frameend":
                                game.templates[id].animmodeidle2frameend = readint(data[i]);
                                break;
                                //end---------------//28Feb2021
                                case "idleframestart":
                                game.templates[id].animmodeidleframestart = readint(data[i]);
                                break;
                                case "idleframeend":
                                game.templates[id].animmodeidleframeend = readint(data[i]);
                                break;
                                case "walkframestart":
                                game.templates[id].animmodewalkframestart = readint(data[i]);
                                break;
                                case "walkframeend":
                                game.templates[id].animmodewalkframeend = readint(data[i]);
                                break;
                                //2sep2021 bug fix
                                case "flyframestart":
                                game.templates[id].animmodeflyframestart = readint(data[i]);
                                break;
                                case "flyframeend":
                                game.templates[id].animmodeflyframeend = readint(data[i]);
                                break;
                                //end 2sep2021
                                case "att1framestart":
                                game.templates[id].animmodeattframestart = readint(data[i]);
                                break;
                                case "att1frameend":
                                game.templates[id].animmodeattframeend = readint(data[i]);
                                break;
                                case "att2framestart":
                                game.templates[id].animmodeatt2framestart = readint(data[i]);
                                break;
                                case "att2frameend":
                                game.templates[id].animmodeatt2frameend = readint(data[i]);
                                break;
                                case "walkspeed":
                                game.templates[id].walkspeed = readint(data[i]);
                                break;
                                case "animspeed":
                                game.templates[id].animspeed = readint(data[i]);
                                break;
                                case "targetfx":
                                for(int a=0;a<game.templates[id].targetfx.Length;a++)
                                {
                                    if(game.templates[id].targetfx[a]==-1)
                                    {
                                        game.templates[id].targetfx[a] = Resources.LoadAudio(game,readstring(data[i]),false);
                                        break;
                                    }
                                }
                                break;
                                case "magicfx":
                                for(int a=0;a<game.templates[id].magicfx.Length;a++)
                                {
                                    if(game.templates[id].magicfx[a]==-1)
                                    {
                                        game.templates[id].magicfx[a] = Resources.LoadAudio(game,readstring(data[i]),false);
                                        break;
                                    }
                                }
                                break;
                                case "impactfx":
                                for(int a=0;a<game.templates[id].impactfx.Length;a++)
                                {
                                    if(game.templates[id].impactfx[a]==-1)
                                    {
                                        game.templates[id].impactfx[a] = Resources.LoadAudio(game,readstring(data[i]),false);
                                        break;
                                    }
                                }
                                break;
                                case "selectfx":
                                for(int a=0;a<game.templates[id].selectfx.Length;a++)
                                {
                                    if(game.templates[id].selectfx[a]==-1)
                                    {
                                        game.templates[id].selectfx[a] = Resources.LoadAudio(game,readstring(data[i]),false);
                                        break;
                                    }
                                }
                                break;
                                case "ackfx":
                                for(int a=0;a<game.templates[id].ackfx.Length;a++)
                                {
                                    if(game.templates[id].ackfx[a]==-1)
                                    {
                                        game.templates[id].ackfx[a] = Resources.LoadAudio(game,readstring(data[i]),false);
                                        break;
                                    }
                                }
                                break;
                                case "attackfx":
                                for(int a=0;a<game.templates[id].attackfx.Length;a++)
                                {
                                    if(game.templates[id].attackfx[a]==-1)
                                    {
                                        game.templates[id].attackfx[a] = Resources.LoadAudio(game,readstring(data[i]),false);
                                        break;
                                    }
                                }
                                break;
                                case "deathfx": //28jul2021
                                for(int a=0;a<game.templates[id].deathfx.Length;a++)
                                {
                                    if(game.templates[id].deathfx[a]==-1)
                                    {
                                        game.templates[id].deathfx[a] = Resources.LoadAudio(game,readstring(data[i]),false);
                                        break;
                                    }
                                }
                                break;
                                
                            }
                        }
                    }
                    //start-----------------//22mar2021
                    //in the event we don't set the displayname we can always look it up in the translation table..in case we have it there...makes it easier sometimes.
                    for(int i=0;i<game.templates.Length;i++)
                    {
                        if(game.templates[i].displayname=="")
                        {
                            game.templates[i].displayname = Translation.TranslateWord(game.templates[i].name,false);
                        }
                    }
                    //end-------------------//22mar2021
                }
                LocalStorage.setitem("FILE LOAD:"+file,"SUCCESS");//24mar2021
            }
            catch(Exception e)
            {
                Console.WriteLine("569:"+e.Message);
                LocalStorage.setitem("FILE LOAD:"+file,"FAILED");//24mar2021
            }
        }

///////////////////Method Definition///////////////
        public static bool comparecustomversions()
        {
            //compare the custom usercampaign.txt file with the one in the
            //install directory. This is so that we can make a copy in the user'sacrificial
            //local area for them to play around with
            int userversion = 0;
            int gameversion = 1;
            try
            {
                string[] datag = System.IO.File.ReadAllLines(Config.customcampaignfile);
                for(int i=0;i<datag.Length;i++)
                {
                    if(datag[i].IndexOf("=")>0)
                    {
                        switch(datag[i].Substring(0,datag[i].IndexOf("=")))
                        {
                            case "version":
                            gameversion = readint(datag[i]);
                            break;
                        }
                    }
                }
            }
            catch(Exception e)
            {
                string msg0 = e.Message;
            }
            try
            {
                string[] datau = System.IO.File.ReadAllLines(Config.usercampaignfile);
                for(int i=0;i<datau.Length;i++)
                {
                    if(datau[i].IndexOf("=")>0)
                    {
                        switch(datau[i].Substring(0,datau[i].IndexOf("=")))
                        {
                            case "version":
                            userversion = readint(datau[i]);
                            break;
                        }
                    }
                }
            }
            catch(Exception e)
            {
                string msg1 = e.Message;
            }
            if(userversion<gameversion)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

///////////////////Method Definition///////////////
        public static bool custommissionvalid(Game game,string[] data2,int i) //24Feb2021
        {
            //verify if the mission loaded by LoadCampaign is a valid mission
            //checks factions and existence of units
            bool anyplayers = false;
            int pfaction = Unit.HUMAN; //28Feb2021
            for(int j=i+1;j<data2.Length;j++)
            {
                if(data2[j].IndexOf("=")>0)
                {
                    if(data2[j].Substring(0,data2[j].IndexOf("="))=="mission")
                    {
                        break;
                    }
                    //start-------------//28Feb2021
                    if(data2[j].Substring(0,data2[j].IndexOf("="))=="playerfaction")
                    {
                        pfaction = Resources.readint(data2[j]);
                    }
                    //end---------------//28Feb2021
                    if(data2[j].Substring(0,data2[j].IndexOf("="))=="unit")
                    {
                        string[] unitlist = readstring(data2[j]).Split(",");
                        string unitname = unitlist[0];
                        bool found = false;
                        for(int k=0;k<game.templates.Length;k++)
                        {
                            if(unitname==game.templates[k].name)
                            {
                                //if(game.templates[k].faction==Unit.HUMAN) //28Feb2021
                                if(game.templates[k].faction==pfaction)//28Feb2021
                                {
                                    anyplayers = true;
                                }
                                found = true;
                                break;
                            }
                        }
                        if(!found)
                        {
                            return false;
                        }
                    }
                }
            }
            if(!anyplayers)
            {
                return false;
            }
            return true;
        }

///////////////////Method Definition///////////////
        public static void LoadCampaign(Game game,string file)
        {
            ////////////////////////
            //load the Campaign files including both custom and core campaigns.
            string errline = "";
            int toomanytrees = 0;
            int toomanyrocks = 0;
            int toomanywalls = 0;
            bool getnewversion = comparecustomversions();
            try
            {
                string[] data = System.IO.File.ReadAllLines(file);
                string[] data2 = new string[0];
                try
                {
                    data2 = System.IO.File.ReadAllLines(Config.usercampaignfile);
                    LocalStorage.setitem("FILE LOAD:"+Config.usercampaignfile,"SUCCESS");
                }
                catch(Exception gge)
                {
                    Console.WriteLine(gge.Message);
                    LocalStorage.setitem("FILE LOAD:"+Config.usercampaignfile,"FAILED");
                }
                if(data2.Length<=0 || getnewversion==true)
                {
                    data2 = System.IO.File.ReadAllLines(Config.customcampaignfile);    
                    try
                    {
                        string txt = "";
                        for(int i=0;i<data2.Length;i++)
                        {
                            txt+=data2[i]+Environment.NewLine;
                        }
                        System.IO.File.WriteAllText(Config.usercampaignfile,txt);
                    }
                    catch(Exception ffe)
                    {
                        Console.WriteLine(ffe.Message);
                    }
                }
                int cw = 0;
                int ch = 0;
                int nw = 0;
                int nh = 0;
                int offy = 0;
                int countmissions = 0;
                int countcustoms = 0;
                for(int d=0;d<Map.deadcell.Length;d++)
                {
                    Map.deadcell[d] = -1;
                }
                for(int i=0;i<data2.Length;i++)
                {
                    errline = data2[i];
                    if(data2[i].IndexOf("=")>0)
                    {
                        switch(data2[i].Substring(0,data2[i].IndexOf("=")))
                        {
                            case "mission":
                            //check mission valid....24Feb2021
                            if(custommissionvalid(game,data2,i))//24Feb2021
                            {
                                countcustoms++;
                                LocalStorage.setitem("CUSTOM MISSION:"+readstring(data2[i]),"SUCCESS");//24mar2021
                            }
                            else //17mar21
                            {
                                Console.WriteLine("Error with custom map:"+readstring(data2[i]));
                                //LocalStorage.WriteLog("Error with custom map:"+readstring(data2[i]));
                                LocalStorage.setitem("CUSTOM MISSION:"+readstring(data2[i]),"FAIL");//24mar2021
                            }
                            break;
                        }
                    }
                }
                int id = -1;
                int countunits = 0;
                int unitid = -1;
                Game.countcustoms = countcustoms;
                //Console.WriteLine("Count Customs:"+countcustoms);
                for(int i=0;i<data.Length;i++)
                {
                    //Unit Template.....
                    errline = data[i];
                    if(data[i].IndexOf("=")>0)
                    {
                        switch(data[i].Substring(0,data[i].IndexOf("=")))
                        {
                            case "shield": //15mar2021
                                Game.shield = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "spellball"://12apr2021
                                Game.spellball = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "whirlwind"://28mar2021
                                Game.whirlwind = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "lightning"://28mar2021
                                Game.lightning = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "whiteflag":
                                Game.whiteflag = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            //start-------------//15sep2021
                            case "shadowup":
                                Game.shadowup = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "shadowleft":
                                Game.shadowleft = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "shadowright":
                                Game.shadowright = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "shadowoffx":
                                Game.shadowoffx = Resources.readint(data[i]);
                            break;
                            case "shadowoffy":
                                Game.shadowoffy = Resources.readint(data[i]);
                            break;
                            //end---------------//15sep2021
                            //start-----------------//21mar2021
                            case "plus":
                                Game.iconplus = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "minus":
                                Game.iconminus = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "circles":
                                //110,110,13,1 - standard
                                Game.iconcircles = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            //end-------------------//21mar2021
                            case "healthbar":
                                Game.healthbar = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                            break;
                            case "cw":
                                cw = readint(data[i]);
                            break;
                            case "ch":
                                ch = readint(data[i]);
                            break;
                            case "nw":
                                nw = readint(data[i]);
                            break;
                            case "nh":
                                nh = readint(data[i]);
                            break;
                            case "offy":
                                offy = readint(data[i]);
                            break;
                            case "menumusic":
                                string[] tmpmenumusic = readstring(data[i]).Split(",");
                                if(tmpmenumusic.Length==2)
                                {
                                    string menumusicfile = tmpmenumusic[0];
                                    int menuduration = -1;
                                    Int32.TryParse(tmpmenumusic[1],out menuduration);
                                    if(menuduration!=-1)
                                    {
                                        Map.menumusicfile = menumusicfile;//25mar2021
                                        Map.menumusic = Resources.LoadAudio(game,menumusicfile,true);
                                        Map.menumusicplaying = -1;
                                    }
                                }
                            break;
                            case "musictrack":
                                string[] tmpmusic = readstring(data[i]).Split(",");
                                if(tmpmusic.Length==2)
                                {
                                    string musfile = tmpmusic[0];
                                    int duration = -1;
                                    Int32.TryParse(tmpmusic[1],out duration);
                                    if(duration!=-1)
                                    {
                                        if(Map.musictrack==null)
                                        {
                                            Map.musictrack = new int[Map.MAXMUSIC];
                                            Map.musicduration = new int[Map.MAXMUSIC];
                                            Map.musictrackfile = new string[Map.MAXMUSIC];//25mar2021
                                            for(int m=0;m<Map.musictrack.Length;m++)
                                            {
                                                Map.musictrack[m]=-1;
                                                Map.musicduration[m]=-1;
                                                Map.musictrackfile[m]=""; //25mar2021
                                            }
                                            Map.musicplaying = -1;
                                            Map.musicstartframe = -1;
                                        }
                                        for(int m=0;m<Map.musictrack.Length;m++)
                                        {
                                            if(Map.musictrack[m]==-1)
                                            {
                                                Map.musictrackfile[m] = musfile;//25mar2021
                                                Map.musictrack[m] = Resources.LoadAudio(game,musfile,true);
                                                if(Map.musictrack[m]!=-1)
                                                {
                                                    Map.musicduration[m] = duration;
                                                }
                                                break;
                                            }
                                        }
                                    }
                                }
                            break;
                            case "dead":
                                for(int d=0;d<Map.deadcell.Length;d++)
                                {
                                    if(Map.deadcell[d]==-1)
                                    {
                                        Map.deadcell[d] = readint(data[i]);
                                    }
                                }
                            break;
                            case "environment_ground":
                                Map.tilecat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                Map.tileframes = nw * nh;
                            break;
                            case "environment_trees":
                                Map.treecat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                Map.treeframes = nw * nh;
                                Map.treeoffsety = offy;
                            break;
                            //start--------------//2mar2021
                            case "environment_decor":
                                Map.decorcat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                Map.decorframes = nw * nh;
                                Map.decoroffsety = offy;
                            break;
                            //end----------------//2mar2021
                            case "environment_rocks":
                                Map.rockcat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                Map.rockframes = nw * nh;
                                Map.rockoffsety = offy;
                            break;
                            case "environment_walls":
                                Map.wallcat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                Map.wallframes = nw * nh;
                                Map.walloffsety = offy;
                            break;
                            case "environment_fire":
                                Map.firecat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                Map.fireframes = nw * nh;
                            break;
                            case "mission":
                                countmissions++;
                            break;
                        }
                    }
                }
                if(countmissions>0 || countcustoms>0)
                {
                    game.missions = new Mission[countmissions+countcustoms];
                    Game.overridemaxmission = countmissions;//13sep2021
                    int countobjectives = 0;
                    int objective = -1;
                    for(int i=0;i<data.Length;i++)
                    {
                        //Unit Template.....
                        errline = data[i];
                        if(data[i].IndexOf("=")>0)
                        {
                            switch(data[i].Substring(0,data[i].IndexOf("=")))
                            {
                                case "mission":
                                id++;
                                game.missions[id] = new Mission();
                                game.missions[id].name = readstring(data[i]);
                                game.missions[id].custom = false;
                                game.missions[id].gridw = Map.DEFAULTGRIDW;//10sep2021
                                game.missions[id].gridh = Map.DEFAULTGRIDH;//10sep2021
                                toomanytrees = 0;
                                toomanyrocks = 0;
                                toomanywalls = 0;
                                countunits = 0;
                                for(int j=i+1;j<data.Length;j++)
                                {
                                    if(data[j].IndexOf("=")>0)
                                    {
                                        if(data[j].Substring(0,data[j].IndexOf("="))=="unit")
                                        {
                                            countunits++;
                                        }
                                        if(data[j].Substring(0,data[j].IndexOf("="))=="mission")
                                        {
                                            break;
                                        }
                                        if(data[j].Substring(0,data[j].IndexOf("="))=="tutorial")
                                        {
                                            break;
                                        }
                                        if(data[j].Substring(0,data[j].IndexOf("="))=="objective")
                                        {
                                            countobjectives++;
                                        }
                                    }
                                }
                                if(countunits>0)
                                {
                                    game.missions[id].units = new Unit[countunits];
                                    unitid = -1;
                                }
                                if(countobjectives>0)
                                {
                                    game.missions[id].objectives = new string[countobjectives];
                                }
                                break;
                                //26oct2020 start
                                case "cw":
                                    cw = readint(data[i]);
                                break;
                                case "ch":
                                    ch = readint(data[i]);
                                break;
                                case "nw":
                                    nw = readint(data[i]);
                                break;
                                case "nh":
                                    nh = readint(data[i]);
                                break;
                                case "offy":
                                    offy = readint(data[i]);
                                break;
                                //start-----------------//10sep2021
                                case "gridw":
                                game.missions[id].gridw = readint(data[i]);
                                break;
                                case "gridh":
                                game.missions[id].gridh = readint(data[i]);
                                break;
                                //end-------------------//10sep2021
                                //1nov2020 start
                                case "override_bk_red":
                                game.missions[id].overridergbbk = true;
                                game.missions[id].overridergbbk_r = readint(data[i]);
                                break;
                                case "override_bk_green":
                                game.missions[id].overridergbbk = true;
                                game.missions[id].overridergbbk_g = readint(data[i]);
                                break;
                                case "override_bk_blue":
                                game.missions[id].overridergbbk = true;
                                game.missions[id].overridergbbk_b = readint(data[i]);
                                break;
                                //1nov2020 end
                                case "override_ground":
                                    game.missions[id].tilecat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].tileframes = nw * nh;
                                    if(readstring(data[i]).IndexOf("snow")>0)
                                    {
                                        game.missions[id].issnow = true;
                                    }
                                    if(readstring(data[i]).IndexOf("desert")>0)
                                    {
                                        game.missions[id].isdesert = true;
                                    }
                                break;
                                //start--------------//2mar2021
                                case "override_decor":
                                    game.missions[id].decorcat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].decorframes = nw * nh;
                                    game.missions[id].decoroffsety = offy;
                                break;
                                //end----------------//2mar2021
                                case "override_trees":
                                    game.missions[id].treecat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].treeframes = nw * nh;
                                    game.missions[id].treeoffsety = offy;
                                break;
                                case "override_rocks":
                                    game.missions[id].rockcat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].rockframes = nw * nh;
                                    game.missions[id].rockoffsety = offy;
                                break;
                                case "override_walls":
                                    game.missions[id].wallcat = Resources.LoadAnimImage(game,readstring(data[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].wallframes = nw * nh;
                                    game.missions[id].walloffsety = offy;
                                break;
                                //26oct2020 end
                                case "nextmissionid":
                                    game.missions[id].nextmissionid = readint(data[i]);
                                break;
                                case "debrief":
                                    game.missions[id].debrief = readint(data[i]);
                                break;
                                case "failedmissionid":
                                    game.missions[id].failedmissionid = readint(data[i]);
                                break;
                                case "floorpattern"://16sep2021
                                game.missions[id].floorpattern = readint(data[i]);
                                break;
                                //start--------------//1mar2021
                                case "nextmissionname":
                                    game.missions[id].nextmissionname = readstring(data[i]);
                                break;
                                case "failedmissionname":
                                    game.missions[id].failedmissionname = readstring(data[i]);
                                break;
                                //end----------------//1mar2021
                                case "demo":
                                    game.missions[id].demo = readint(data[i]);
                                break;
                                //start-----------//26Feb2021
                                case "fogoff":
                                    game.missions[id].fogoff = readint(data[i]);
                                break;
                                case "neutralfog":
                                    game.missions[id].neutralfog = readint(data[i]);
                                break;
                                //end-------------//26Feb2021
                                //start-------------//28Feb2021
                                case "playerfaction":
                                    game.missions[id].playerfaction = readint(data[i]);
                                break;
                                case "enemyfaction":
                                    game.missions[id].skirmishenemyfaction = readint(data[i]);
                                break;
                                case "unlocked":
                                    game.missions[id].alwaysunlocked = readint(data[i]);
                                break;
                                //end---------------//28Feb2021
                                //start--------------//1mar2021
                                case "lockcorner":
                                    game.missions[id].lockcorner = readint(data[i]);
                                break;
                                //end----------------//1mar2021
                                case "corner":
                                    string[] tmpcorner = readstring(data[i]).Split(",");
                                    if(tmpcorner.Length==2)
                                    {
                                        Int32.TryParse(tmpcorner[0],out game.missions[id].cornerx);
                                        Int32.TryParse(tmpcorner[1],out game.missions[id].cornery);
                                    }
                                break;
                                case "seed":
                                    game.missions[id].seed = readint(data[i]);
                                break;
                                case "skirmish":
                                    game.missions[id].skirmish = readint(data[i]);
                                break;
                                case "description":
                                    if(game.missions[id].description[0] == "")
                                    {
                                        game.missions[id].description[0] = readstring(data[i]);
                                    }
                                    else
                                    {
                                        if(game.missions[id].description[1] == "")
                                        {
                                            game.missions[id].description[1] = readstring(data[i]);
                                        }
                                        else
                                        {
                                            game.missions[id].description[2] = readstring(data[i]);
                                        }
                                    }
                                break;
                                case "mapgen":
                                    game.missions[id].mapgen = 1;
                                break;
                                case "ai":
                                    game.missions[id].ai = readint(data[i]);
                                break;
                                case "istutorial":
                                    game.missions[id].istutorial = readint(data[i]);
                                break;
                                case "toomanytrees":
                                    toomanytrees=1;
                                break;
                                case "toomanyrocks":
                                    toomanyrocks=1;
                                break;
                                case "toomanywalls":
                                    toomanywalls = 1;
                                break;
                                //start--------------//2mar2021
                                case "decor":
                                if(id>=0)
                                {
                                    string[] tmpdecor = readstring(data[i]).Split(",");
                                    game.missions[id].decorimage = new int[tmpdecor.Length];
                                    for(int j=0;j<tmpdecor.Length;j++)
                                    {
                                        int tt = -1;
                                        Int32.TryParse(tmpdecor[j],out tt);
                                        game.missions[id].decorimage[j] = tt;
                                    }
                                }
                                break;
                                //end----------------//2mar2021
                                case "trees":
                                if(id>=0)
                                {
                                    string[] tmptrees = readstring(data[i]).Split(",");
                                    game.missions[id].treeimage = new int[tmptrees.Length];
                                    for(int j=0;j<tmptrees.Length;j++)
                                    {
                                        int tt = -1;
                                        Int32.TryParse(tmptrees[j],out tt);
                                        if(toomanytrees>0)
                                        {
                                            if(j % 3<2)
                                            {
                                                continue;
                                            }
                                        }
                                        game.missions[id].treeimage[j] = tt;
                                    }
                                }
                                break;
                                case "walls":
                                if(id>=0)
                                {
                                    string[] tmpwalls = readstring(data[i]).Split(",");
                                    game.missions[id].wallimage = new int[tmpwalls.Length];
                                    for(int j=0;j<tmpwalls.Length;j++)
                                    {
                                        int tt = -1;
                                        Int32.TryParse(tmpwalls[j],out tt);
                                        if(toomanywalls==1)
                                        {
                                            if((Functions.rand(0,1000) % 4)>0)
                                            {
                                                continue;
                                            }
                                        }
                                        game.missions[id].wallimage[j] = tt;
                                    }
                                }
                                break;
                                case "rocks":
                                if(id>=0)
                                {
                                    string[] tmprocks = readstring(data[i]).Split(",");
                                    game.missions[id].rockimage = new int[tmprocks.Length];
                                    for(int j=0;j<tmprocks.Length;j++)
                                    {
                                        int tt = -1;
                                        Int32.TryParse(tmprocks[j],out tt);
                                        if(toomanyrocks>0)
                                        {
                                            if(j % 3<2)
                                            {
                                                continue;
                                            }
                                        }
                                        game.missions[id].rockimage[j] = tt;
                                    }
                                }
                                break;
                                case "setfire":
                                if(id>=0)
                                {
                                    string[] tmpfire = readstring(data[i]).Split(",");
                                    if(tmpfire.Length==2)
                                    {
                                        game.missions[id].campfirex = -1;
                                        game.missions[id].campfirey = -1;
                                        Int32.TryParse(tmpfire[0],out game.missions[id].campfirex);
                                        Int32.TryParse(tmpfire[1],out game.missions[id].campfirey);
                                    }
                                }
                                break;
                                case "objective":
                                    objective++;
                                    game.missions[id].objectives[objective] = readstring(data[i]);
                                break;
                                case "showkills":
                                    game.missions[id].showkills = readint(data[i]);
                                break;
                                case "unit":
                                    string[] unitlist = readstring(data[i]).Split(",");
                                    if(unitlist.Length==3)
                                    {
                                        bool success1 = true;
                                        bool success2 = true;
                                        string name = unitlist[0];
                                        int x = 0;
                                        int y = 0;
                                        if(unitlist[1]=="random")
                                        {
                                            x = Functions.rand(Map.GRIDW * 35,Map.GRIDW*65);
                                            success1 = true;
                                        }
                                        else
                                        {
                                            success1 = Int32.TryParse(unitlist[1],out x);
                                        }
                                        if(unitlist[2]=="random")
                                        {
                                            y = Functions.rand(Map.GRIDH * 35,Map.GRIDH*65);
                                            success2 = true;
                                        }
                                        else
                                        {
                                            success2 = Int32.TryParse(unitlist[2],out y);
                                        }
                                        if(success1 && success2)
                                        {
                                            unitid++;
                                            game.missions[id].units[unitid] = new Unit(game);
                                            game.missions[id].units[unitid].x = x;
                                            game.missions[id].units[unitid].y = y;
                                            game.missions[id].units[unitid].name = name;
                                        }
                                    }
                                break;
                                //start--------------//10sep2021
                                case "unitname"://unit name must immediately follow the unit that was just created....
                                if(game.missions[id].units!=null)
                                {
                                    if(unitid<game.missions[id].units.Length && unitid>=0)
                                    {
                                        game.missions[id].units[unitid].charactername = readstring(data[i]);
                                    }
                                }
                                break;
                                case "displayunitname"://unit name must immediately follow the unit that was just created....
                                if(game.missions[id].units!=null)
                                {
                                    if(unitid<game.missions[id].units.Length && unitid>=0)
                                    {
                                        game.missions[id].units[unitid].displaycharactername = readint(data[i]);
                                    }
                                }
                                break;
                                //end----------------//10sep2021
                                case "trigger":
                                //type,num,comparator,name,xx,yy,ww,hh
                                //type == 1 Victory
                                //type == 2 Defeat
                                //comparator == 0 equal
                                //comparator == -1 less than
                                //comparator == 1 greater than
                                    if(id>=0)
                                    {
                                        string[] trigger = readstring(data[i]).Split(",");
                                        if(trigger.Length==8)
                                        {
                                            int typ = 0;
                                            int num = 0;
                                            int comp = 0;
                                            Int32.TryParse(trigger[0],out typ);
                                            Int32.TryParse(trigger[1],out num);
                                            Int32.TryParse(trigger[2],out comp);
                                            int xx = 0;
                                            int yy = 0;
                                            int ww = 0;
                                            int hh = 0;
                                            Int32.TryParse(trigger[4],out xx);
                                            Int32.TryParse(trigger[5],out yy);
                                            Int32.TryParse(trigger[6],out ww);
                                            Int32.TryParse(trigger[7],out hh);
                                            game.missions[id].createtrigger(typ,num,comp,trigger[3].Replace("^",","),xx,yy,ww,hh);
                                        }
                                    }
                                break;
                            }
                        }
                    }
                    //
                    //customs
                    bool validblock = true; //24Feb2021
                    for(int i=0;i<data2.Length;i++)
                    {
                        //Unit Template.....
                        errline = data2[i];
                        if(data2[i].IndexOf("=")>0)
                        {
                            if((data2[i].Substring(0,data2[i].IndexOf("="))=="mission")) //24Feb2021
                            {//24Feb2021
                                validblock = true;//24Feb2021
                            }//24Feb2021
                            if(!validblock)//24Feb2021
                            {//24Feb2021
                                continue;//24Feb2021
                            }//24Feb2021
                            switch(data2[i].Substring(0,data2[i].IndexOf("=")))
                            {
                                case "mission":
                                validblock = true; //24Feb2021
                                if(!custommissionvalid(game,data2,i))//24Feb2021
                                {//24Feb2021
                                    validblock = false;
                                    continue;
                                }//24Feb2021
                                id++;
                                game.missions[id] = new Mission();
                                game.missions[id].name = readstring(data2[i]);
                                game.missions[id].custom = true;
                                game.missions[id].gridw = Map.DEFAULTGRIDW;//10sep2021
                                game.missions[id].gridh = Map.DEFAULTGRIDH;//10sep2021
                                toomanytrees = 0;
                                toomanyrocks = 0;
                                countunits = 0;
                                for(int j=i+1;j<data2.Length;j++)
                                {
                                    if(data2[j].IndexOf("=")>0)
                                    {
                                        if(data2[j].Substring(0,data2[j].IndexOf("="))=="unit")
                                        {
                                            countunits++;
                                        }
                                        if(data2[j].Substring(0,data2[j].IndexOf("="))=="mission")
                                        {
                                            break;
                                        }
                                        if(data2[j].Substring(0,data2[j].IndexOf("="))=="tutorial")
                                        {
                                            break;
                                        }
                                        if(data2[j].Substring(0,data2[j].IndexOf("="))=="objective")
                                        {
                                            countobjectives++;
                                        }
                                    }
                                }
                                if(countunits>0)
                                {
                                    game.missions[id].units = new Unit[countunits];
                                    unitid = -1;
                                }
                                if(countobjectives>0)
                                {
                                    game.missions[id].objectives = new string[countobjectives];
                                }
                                break;
                                //26oct2020 start
                                case "cw":
                                    cw = readint(data2[i]);
                                break;
                                case "ch":
                                    ch = readint(data2[i]);
                                break;
                                case "nw":
                                    nw = readint(data2[i]);
                                break;
                                case "nh":
                                    nh = readint(data2[i]);
                                break;
                                case "offy":
                                    offy = readint(data2[i]);
                                break;
                                //start-----------------//10sep2021
                                case "gridw":
                                game.missions[id].gridw = readint(data2[i]);
                                break;
                                case "gridh":
                                game.missions[id].gridh = readint(data2[i]);
                                break;
                                //end-------------------//10sep2021
                                //1nov2020 start
                                case "override_bk_red":
                                game.missions[id].overridergbbk = true;
                                game.missions[id].overridergbbk_r = readint(data2[i]);
                                break;
                                case "override_bk_green":
                                game.missions[id].overridergbbk = true;
                                game.missions[id].overridergbbk_g = readint(data2[i]);
                                break;
                                case "override_bk_blue":
                                game.missions[id].overridergbbk = true;
                                game.missions[id].overridergbbk_b = readint(data2[i]);
                                break;
                                //1nov2020 end
                                case "override_ground":
                                    game.missions[id].tilecat = Resources.LoadAnimImage(game,readstring(data2[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].tileframes = nw * nh;
                                    if(readstring(data2[i]).IndexOf("snow")>0)
                                    {
                                        game.missions[id].issnow = true;
                                    }
                                    if(readstring(data2[i]).IndexOf("desert")>0)
                                    {
                                        game.missions[id].isdesert = true;
                                    }
                                break;
                                case "override_trees":
                                    game.missions[id].treecat = Resources.LoadAnimImage(game,readstring(data2[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].treeframes = nw * nh;
                                    game.missions[id].treeoffsety = offy;
                                break;
                                //start--------------//2mar2021
                                case "override_decor":
                                    game.missions[id].decorcat = Resources.LoadAnimImage(game,readstring(data2[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].decorframes = nw * nh;
                                    game.missions[id].decoroffsety = offy;
                                break;
                                //end----------------//2mar2021
                                case "override_rocks":
                                    game.missions[id].rockcat = Resources.LoadAnimImage(game,readstring(data2[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].rockframes = nw * nh;
                                    game.missions[id].rockoffsety = offy;
                                break;
                                case "override_walls":
                                    game.missions[id].wallcat = Resources.LoadAnimImage(game,readstring(data2[i]),game.renderer,cw,ch,nw,nh);
                                    game.missions[id].wallframes = nw * nh;
                                    game.missions[id].walloffsety = offy;
                                break;
                                //26oct2020 end
                                case "nextmissionid":
                                    game.missions[id].nextmissionid = readint(data2[i]);
                                break;
                                case "debrief":
                                    game.missions[id].debrief = readint(data2[i]);
                                break;
                                case "failedmissionid":
                                    game.missions[id].failedmissionid = readint(data2[i]);
                                break;
                                //start--------------//1mar2021
                                case "nextmissionname":
                                    game.missions[id].nextmissionname = readstring(data2[i]);
                                break;
                                case "failedmissionname":
                                    game.missions[id].failedmissionname = readstring(data2[i]);
                                break;
                                //end----------------//1mar2021
                                case "demo":
                                    game.missions[id].demo = 0;//readint(data2[i]);
                                break;
                                //start-----------//26Feb2021
                                case "fogoff":
                                    game.missions[id].fogoff = readint(data2[i]);
                                break;
                                case "neutralfog":
                                    game.missions[id].neutralfog = readint(data2[i]);
                                break;
                                //end-------------//26Feb2021
                                //start-------------//28Feb2021
                                case "playerfaction":
                                    game.missions[id].playerfaction = readint(data2[i]);
                                break;
                                case "enemyfaction":
                                    game.missions[id].skirmishenemyfaction = readint(data2[i]);
                                break;
                                case "floorpattern"://16sep2021
                                    game.missions[id].floorpattern = readint(data2[i]);
                                break;
                                case "unlocked":
                                    game.missions[id].alwaysunlocked = readint(data2[i]);
                                break;
                                //end---------------//28Feb2021
                                //start--------------//1mar2021
                                case "lockcorner":
                                    game.missions[id].lockcorner = readint(data2[i]);
                                break;
                                //end----------------//1mar2021
                                case "corner":
                                    string[] tmpcorner = readstring(data2[i]).Split(",");
                                    if(tmpcorner.Length==2)
                                    {
                                        Int32.TryParse(tmpcorner[0],out game.missions[id].cornerx);
                                        Int32.TryParse(tmpcorner[1],out game.missions[id].cornery);
                                    }
                                break;
                                case "seed":
                                    game.missions[id].seed = readint(data2[i]);
                                break;
                                case "skirmish":
                                    game.missions[id].skirmish = readint(data2[i]);
                                break;
                                case "mapgen":
                                    game.missions[id].mapgen = 1;
                                break;
                                case "ai":
                                    game.missions[id].ai = readint(data2[i]);
                                break;
                                case "description":
                                    if(game.missions[id].description[0] == "")
                                    {
                                        //game.missions[id].description[0] = readstring(data2[i]);//21mar2021
                                        game.missions[id].description[0] = Translation.TranslateWord(readstring(data2[i]),false);//21mar2021
                                    }
                                    else
                                    {
                                        if(game.missions[id].description[1] == "")
                                        {
                                            //game.missions[id].description[1] = readstring(data2[i]);//22mar2021
                                            game.missions[id].description[1] = Translation.TranslateWord(readstring(data2[i]),false);//22mar2021
                                        }
                                        else
                                        {
                                            //game.missions[id].description[2] = readstring(data2[i]);//22mar2021
                                            game.missions[id].description[2] = Translation.TranslateWord(readstring(data2[i]),false);//22mar2021
                                        }
                                    }
                                break;
                                case "istutorial":
                                    game.missions[id].istutorial = 0;//readint(data[i]);
                                break;
                                //start--------------//2mar2021
                                case "decor":
                                if(id>=0)
                                {
                                    string[] tmpdecor = readstring(data2[i]).Split(",");
                                    game.missions[id].decorimage = new int[tmpdecor.Length];
                                    for(int j=0;j<tmpdecor.Length;j++)
                                    {
                                        int tt = -1;
                                        Int32.TryParse(tmpdecor[j],out tt);
                                        game.missions[id].decorimage[j] = tt;
                                    }
                                }
                                break;
                                //end----------------//2mar2021
                                case "trees":
                                if(id>=0)
                                {
                                    string[] tmptrees = readstring(data2[i]).Split(",");
                                    game.missions[id].treeimage = new int[tmptrees.Length];
                                    for(int j=0;j<tmptrees.Length;j++)
                                    {
                                        int tt = -1;
                                        Int32.TryParse(tmptrees[j],out tt);
                                        game.missions[id].treeimage[j] = tt;
                                    }
                                }
                                break;
                                case "walls":
                                if(id>=0)
                                {
                                    string[] tmpwalls = readstring(data2[i]).Split(",");
                                    game.missions[id].wallimage = new int[tmpwalls.Length];
                                    for(int j=0;j<tmpwalls.Length;j++)
                                    {
                                        int tt = -1;
                                        Int32.TryParse(tmpwalls[j],out tt);
                                        game.missions[id].wallimage[j] = tt;
                                    }
                                }
                                break;
                                case "rocks":
                                if(id>=0)
                                {
                                    string[] tmprocks = readstring(data2[i]).Split(",");
                                    game.missions[id].rockimage = new int[tmprocks.Length];
                                    for(int j=0;j<tmprocks.Length;j++)
                                    {
                                        int tt = -1;
                                        Int32.TryParse(tmprocks[j],out tt);
                                        game.missions[id].rockimage[j] = tt;
                                    }
                                }
                                break;
                                case "setfire":
                                if(id>=0)
                                {
                                    string[] tmpfire = readstring(data2[i]).Split(",");
                                    if(tmpfire.Length==2)
                                    {
                                        game.missions[id].campfirex = -1;
                                        game.missions[id].campfirey = -1;
                                        Int32.TryParse(tmpfire[0],out game.missions[id].campfirex);
                                        Int32.TryParse(tmpfire[1],out game.missions[id].campfirey);
                                    }
                                }
                                break;
                                case "objective":
                                    objective++;
                                    //game.missions[id].objectives[objective] = readstring(data2[i]);//22mar2021
                                    game.missions[id].objectives[objective] = Translation.TranslateWord(readstring(data2[i]),false);//22mar2021
                                break;
                                case "showkills":
                                    game.missions[id].showkills = readint(data2[i]);
                                break;
                                case "unit":
                                    string[] unitlist = readstring(data2[i]).Split(",");
                                    if(unitlist.Length==3)
                                    {
                                        bool success1 = true;
                                        bool success2 = true;
                                        string name = unitlist[0];
                                        int x = 0;
                                        int y = 0;
                                        if(unitlist[1]=="random")
                                        {
                                            x = Functions.rand(Map.GRIDW * 35,Map.GRIDW*65);
                                            success1 = true;
                                        }
                                        else
                                        {
                                            success1 = Int32.TryParse(unitlist[1],out x);
                                        }
                                        if(unitlist[2]=="random")
                                        {
                                            y = Functions.rand(Map.GRIDH * 35,Map.GRIDH*65);
                                            success2 = true;
                                        }
                                        else
                                        {
                                            success2 = Int32.TryParse(unitlist[2],out y);
                                        }
                                        if(success1 && success2)
                                        {
                                            unitid++;
                                            game.missions[id].units[unitid] = new Unit(game);
                                            game.missions[id].units[unitid].x = x;
                                            game.missions[id].units[unitid].y = y;
                                            game.missions[id].units[unitid].name = name;
                                        }
                                    }
                                break;
                                //start--------------//10sep2021
                                case "unitname"://unit name must immediately follow the unit that was just created....
                                if(game.missions[id].units!=null)
                                {
                                    if(unitid<game.missions[id].units.Length && unitid>=0)
                                    {
                                        game.missions[id].units[unitid].charactername = readstring(data2[i]);
                                    }
                                }
                                break;
                                case "displayunitname":
                                if(game.missions[id].units!=null)
                                {
                                    if(unitid<game.missions[id].units.Length && unitid>=0)
                                    {
                                        game.missions[id].units[unitid].displaycharactername = readint(data2[i]);
                                    }
                                }
                                break;
                                //end----------------//10sep2021
                                case "trigger":
                                //type,num,comparator,name,xx,yy,ww,hh
                                //type == 1 Victory
                                //type == 2 Defeat
                                //comparator == 0 equal
                                //comparator == -1 less than
                                //comparator == 1 greater than
                                    if(id>=0)
                                    {
                                        string[] trigger = readstring(data2[i]).Split(",");
                                        if(trigger.Length==8)
                                        {
                                            int typ = 0;
                                            int num = 0;
                                            int comp = 0;
                                            Int32.TryParse(trigger[0],out typ);
                                            Int32.TryParse(trigger[1],out num);
                                            Int32.TryParse(trigger[2],out comp);
                                            int xx = 0;
                                            int yy = 0;
                                            int ww = 0;
                                            int hh = 0;
                                            Int32.TryParse(trigger[4],out xx);
                                            Int32.TryParse(trigger[5],out yy);
                                            Int32.TryParse(trigger[6],out ww);
                                            Int32.TryParse(trigger[7],out hh);
                                            game.missions[id].createtrigger(typ,num,comp,trigger[3].Replace("^",","),xx,yy,ww,hh);
                                        }
                                    }
                                break;
                            }
                        }
                    }
                }
                LocalStorage.setitem("FILE LOAD:"+file,"SUCCESS");//24mar2021
            }
            catch(Exception e)
            {
                Console.WriteLine("766:"+"Error in file on line containing:"+errline+" "+e.Message);
                //LocalStorage.WriteLog("766:"+"Error in file on line containing:"+errline+" "+e.Message);
                LocalStorage.setitem("FILE LOAD:"+file,"FAILED");//24mar2021
            }
        }

///////////////////Method Definition///////////////
        public static int LoadFont(Game game,string file,int ptsize)
        {
            ////////////////////////
            //Load a font in the game for use
            Fonts f = new Fonts();
            //ptsize*=Config.FONTALIAS;
            if(file!="" && file!=null)//28Feb2021
            {
                if(ptsize>=20)
                {
                    f.font = SDL_ttf.TTF_OpenFont(file,ptsize*Config.FONTALIAS);
                }
                else
                {
                    f.font = SDL_ttf.TTF_OpenFont(file,ptsize);
                }
            }
            if(f.font==IntPtr.Zero)
            {
                Console.WriteLine("Could Not Open Font:"+file+". Error:"+SDL.SDL_GetError());
                Network.reporterror("FontLoadFailure:"+file,false);//15mar2021
                LocalStorage.setitem("FILE LOAD:"+file,"FAILED TO LOAD");
            }
            else
            {
                LocalStorage.setitem("FILE LOAD:"+file,"LOADED");
            }
            int i = game.fonts.Length;
            Array.Resize<Fonts>(ref game.fonts,i+1);
            f.file = file;//24mar2021
            game.fonts[i] = f;
            game.fonts[i].font = f.font;
            game.fonts[i].ptsize = ptsize;
            i++;
            return i - 1;
        }
        //

///////////////////Method Definition///////////////
        public static int LoadAudio(Game game,string file,bool music)
        {
            ////////////////////////
            //Load an Audio file of .wav type
            for(int j=0;j<game.audios.Length;j++)
            {
                if(game.audios[j].file==file)
                {
                    return j;
                }
            }
            Audios a = new Audios();
            a.loop = music;
            a.file = file; //25mar2021
            if(music)
            {
                if(!Config.STREAMLOADAUDIO)//25mar2021
                {
                    if(file!="" && file!=null)//28Feb2021
                    {
                        a.audio = SDL_mixer.Mix_LoadMUS(file);
                    }
                    if(a.audio==IntPtr.Zero)
                    {
                        Console.WriteLine("Could Not Load Music:"+file+". Error:"+SDL.SDL_GetError());
                        Network.reporterror("MusicLoadFailure:"+file,false);//15mar2021
                        LocalStorage.setitem("FILE LOAD:"+file,"FAILED TO LOAD"); //24mar2021
                    }
                    else //24mar2021
                    {
                        LocalStorage.setitem("FILE LOAD:"+file,"LOADED"); //24mar2021
                    }
                }
                else
                {
                    //do nothing yet...
                }
                a.ismusic = true;
            }
            else
            {
                if(file!="" && file!=null)//28Feb2021
                {
                    a.audio = SDL_mixer.Mix_LoadWAV(file);
                }
                if(a.audio==IntPtr.Zero)
                {
                    Console.WriteLine("Could Not Load Sound:"+file+". Error:"+SDL.SDL_GetError());
                    Network.reporterror("SoundLoadFailure:"+file,false);//15mar2021
                    LocalStorage.setitem("FILE LOAD:"+file,"FAILED TO LOAD"); //24mar2021
                }
                else//24mar2021
                {
                    LocalStorage.setitem("FILE LOAD:"+file,"LOADED"); //24mar2021
                }
            
            }
            int i = game.audios.Length;
            Array.Resize<Audios>(ref game.audios,i+1);
            game.audios[i] = a;
            game.audios[i].index = i;
            game.audios[i].loop = music;
            game.audios[i].volume = 1;
            game.audios[i].file = file;
            i++;
            return i - 1;
        }
        //
        //start-------------//28Feb2021

///////////////////Method Definition///////////////
        public static void StreamImage(Game game,int i)
        {
            ////////////////////////
            //not used
            //used after an image is released...and we want to reload it in game....in a separate thread.
            if(i>=0 && i<game.images.Length)
            {
                if(game.images[i].loaded==false && game.images[i].stream==false)
                {
                    if(game.images[i].texture==IntPtr.Zero)
                    {
                        game.images[i].stream = true;
                    }
                }
            }
        }

///////////////////Method Definition///////////////
        public static bool FreeImage(Game game,int i)
        {
            ////////////////////////
            //frees images from memory
            if(i>=0 && i<game.images.Length)
            {
                if(game.images[i].texture!=IntPtr.Zero && game.images[i].loaded==true)
                {
                    LocalStorage.setitem("FREE IMAGE:"+game.images[i].file,"FAILED"); //24mar2021
                    SDL.SDL_DestroyTexture(game.images[i].texture);
                    LocalStorage.setitem("FREE IMAGE:"+game.images[i].file,"SUCCESS"); //24mar2021
                    game.images[i].loaded = false;
                    game.images[i].texture = IntPtr.Zero;
                    return true;
                }
            }
            return false;
        }
        //end---------------//28Feb2021
        //

///////////////////Method Definition///////////////
        public static int LoadImage(Game game,string file,IntPtr renderer,int w,int h) //note the slight change.....added w and h as can't work out how to do it otherwise....
        {
            ////////////////////////
            //Load an image of the form .png or .jpg into memory
            bool loaded = false;//28Feb2021
            for(int j=0;j<game.images.Length;j++)//26oct2020
            {
                if(game.images[j].file==file)
                {
                    //start-------------//28Feb2021
                    if(game.images[j].loaded==false) //assumes the image was loaded once before successfully, cleared out and needs to be loaded again.....
                    {
                        game.images[j].texture = SDL_image.IMG_LoadTexture(renderer,file);
                        if(game.images[j].texture==IntPtr.Zero)
                        {
                            Console.WriteLine("Could Not Load Texture:"+file+". Error:"+SDL.SDL_GetError());
                            Network.reporterror("TextureLoadFailure:"+file,false);//15mar2021
                            LocalStorage.setitem("FILE LOAD:"+file,"FAILED TO LOAD");//24mar2021
                        }
                        else
                        {
                            game.images[j].loaded = true;
                            LocalStorage.setitem("FILE LOAD:"+file,"LOADED"); //24mar2021
                        }
                    }
                    //end---------------//28Feb2021
                    return j;
                }
            }
            Images img = new Images();
            if(!Config.STREAMLOAD) //28Feb2021
            {
                if(file!="" && file!=null)//28Feb2021
                {
                    img.texture = SDL_image.IMG_LoadTexture(renderer,file);
                }
                if(img.texture==IntPtr.Zero)
                {
                    Console.WriteLine("Could Not Load Texture:"+file+". Error:"+SDL.SDL_GetError());
                    Network.reporterror("TextureLoadFailure:"+file,false);//15mar2021
                    LocalStorage.setitem("FILE LOAD:"+file,"FAILED TO LOAD");//24mar2021
                }
                else
                {
                    loaded = true;
                    LocalStorage.setitem("FILE LOAD:"+file,"LOADED");//24mar2021
                }
            }
            int i = game.images.Length;
            Array.Resize<Images>(ref game.images,i+1);
            game.images[i] = img;
            game.images[i].file = file;//26oct2020
            game.images[i].texture = img.texture;
            game.images[i].anim = false;
            game.images[i].index = i;
            game.images[i].cwx = w;//??
            game.images[i].chy = h;//??
            game.images[i].chn = 1;
            game.images[i].cwn = 1;
            game.images[i].stream = Config.STREAMLOAD;//28Feb2021
            game.images[i].loaded = loaded; ///28Feb2021
            game.images[i].okloaded = loaded; //28Feb2021
            game.images[i].neverloaded = !loaded; //28Feb2021
            i++;
            return i - 1;
        }
        //

///////////////////Method Definition///////////////
        public static int LoadAnimImage(Game game,string file,IntPtr renderer,int cellwidth, int cellheight, int cellswide, int cellshigh)
        {
            ////////////////////////
            //Load an animated image of the form .png or .jpg into memory
            bool loaded = false; //28Feb2021
            for(int j=0;j<game.images.Length;j++)//26oct2020
            {
                if(game.images[j].file==file)
                {
                    //start-------------//28Feb2021
                    if(game.images[j].loaded==false) //assumes the image was loaded once before successfully, cleared out and needs to be loaded again.....
                    {
                        game.images[j].texture = SDL_image.IMG_LoadTexture(renderer,file);
                        if(game.images[j].texture==IntPtr.Zero)
                        {
                            Console.WriteLine("Could Not Load Texture:"+file+". Error:"+SDL.SDL_GetError());
                            Network.reporterror("TextureLoadFailure:"+file,false);//15mar2021
                            LocalStorage.setitem("FILE LOAD:"+file,"FAILED TO LOAD");//24mar2021
                        }
                        else
                        {
                            game.images[j].loaded = true;
                            LocalStorage.setitem("FILE LOAD:"+file,"LOADED");//24mar2021
                        }
                    }
                    //end---------------//28Feb2021
                    return j;
                }
            }
            Images img = new Images();
            if(!Config.STREAMLOAD) //28Feb2021
            {
                if(file!="" && file!=null) //28Feb2021
                {
                    img.texture = SDL_image.IMG_LoadTexture(renderer,file);
                }
                if(img.texture==IntPtr.Zero)
                {
                    Console.WriteLine("Could Not Load Texture:"+file+". Error:"+SDL.SDL_GetError());
                    Network.reporterror("TextureLoadFailure:"+file,false);//15mar2021
                    LocalStorage.setitem("FILE LOAD:"+file,"FAILED TO LOAD");//24mar2021
                }
                else
                {
                    loaded = true;
                    LocalStorage.setitem("FILE LOAD:"+file,"LOADED");//24mar2021
                }
            }
            int i = game.images.Length;
            Array.Resize<Images>(ref game.images,i+1);
            game.images[i] = img;
            game.images[i].file = file;//26oct2020
            game.images[i].texture = img.texture;
            game.images[i].anim = true;
            game.images[i].index = i;
            game.images[i].cwx = cellwidth;
            game.images[i].chy = cellheight;
            game.images[i].chn = cellshigh;
            game.images[i].cwn = cellswide;
            game.images[i].stream = Config.STREAMLOAD;//28Feb2021
            game.images[i].loaded = loaded;//28Feb2021
            game.images[i].okloaded = loaded; //28Feb2021
            game.images[i].neverloaded = !loaded; //28Feb2021
            i++;
            return i - 1;
        }
    }
    //

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class Fonts
    {
        public IntPtr font;
        public int ptsize;
        public static int WMULTIPLIER = 1; //15mar2021
        public static int HMULTIPLIER = 1; //17apr2021
        public string file;

///////////////////Method Definition///////////////
        public Fonts()
        {
            file = "";
        }
    }
    //

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class Audios
    {
        public int index;
        public bool loop;
        public int volume;
        //
        public IntPtr audio;
        public bool ismusic;
        public bool ispaused;
        public int[] channel;
        public static int maxchannels = 8;
        public string file;
        public int previousmusicchannel;
        public int currentmusicchannel;
        //
        //

///////////////////Method Definition///////////////
        public Audios()
        {
            loop = false;
            volume = 1;
            index = 0;
            ismusic = false;
            channel = new int[Audios.maxchannels];
            ispaused = false;
            file = "";//25mar2021
        }
        //

///////////////////Method Definition///////////////
        public static int playsound(Audios a,int vol)
        {
            ////////////////////////
            //play an audio clip at a specified volume from 0 to 100
            if(!Game.audioon)
            {
                return -1;
            }
            if(!a.ismusic)
            {
                //start-------------//10sep2021
                //in case we freed at a certain point.....
                //in the game....
                if(a.audio==IntPtr.Zero)
                {
                    if(a.file!=null)
                    {
                        if(a.file!="")
                        {
                            a.audio = SDL_mixer.Mix_LoadWAV(a.file);
                        }
                    }
                }
                //end---------------//10sep2021
                int i = SDL_mixer.Mix_PlayChannel(-1,a.audio,0);
                SDL_mixer.Mix_Volume(i,vol);
                return i;
            }
            return -1;
        }

///////////////////Method Definition///////////////
        public static void playmusic(Audios a,int vol,bool loop)
        {
            //play a music clip at a specified volume from 0 to 100, and perhaps loop it
            if(!Game.audioon)
            {
                return;
            }
            if(a.ismusic)
            {
                if(a.ispaused)
                {
                    SDL_mixer.Mix_ResumeMusic();
                    a.ispaused = false;
                }
                else
                {
                    int i = SDL_mixer.Mix_PlayMusic(a.audio,-1);
                    SDL_mixer.Mix_VolumeMusic(vol);
                    a.previousmusicchannel = a.currentmusicchannel;
                    a.currentmusicchannel = i;
                    a.ispaused = false;
                }
            }
        }

///////////////////Method Definition///////////////
        public static void FreeAudio(Audios a)//10sep2021
        {
            //alias for freeaudio(Audios a)
            freeaudio(a);
        }
///////////////////Method Definition///////////////
        public static void freeaudio(Audios a)//10sep2021
        {
            if(a.ismusic)
            {
                return;
            }
            try
            {
                SDL_mixer.Mix_FreeChunk(a.audio);
                LocalStorage.setitem("FREE AUDIO:"+a.file,"SUCCESS"); //24mar2021
                a.audio = IntPtr.Zero;
            }
            catch(Exception e)
            {
                string txt = e.Message;
            }
        }
///////////////////Method Definition///////////////
        public static void stopchannel(int i)//10sep2021
        {
            try
            {
                SDL_mixer.Mix_HaltChannel(i);
            }
            catch(Exception e)
            {
                string txt = e.Message;
            }
        }
///////////////////Method Definition///////////////
        public static void pauseaudio(Audios a)
        {
            //pause an audio music track that is playing
            //and stop all other audio at the same time.
            if(a.ismusic)
            {
                SDL_mixer.Mix_PauseMusic();
                a.ispaused = true;
            }
            else
            {
            }
            SDL_mixer.Mix_HaltChannel(-1);
        }

///////////////////Method Definition///////////////
        public static void resumemusic(Audios a)
        {
            //resume a music track that is paused.
            if(!Game.audioon)
            {
                return;
            }
            if(a.ismusic)
            {
                SDL_mixer.Mix_ResumeMusic();
                a.ispaused = false;
            }
        }
    }
    //

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class Images
    {
        public IntPtr texture;
        public int index;
        public bool anim;
        public int cwx;
        public int chy;
        public int chn;
        public int cwn;
        public string file; //26oct2020
        public bool loaded;//28Feb2021
        public bool stream; //28Feb2021
        public int drawframe; //28Feb2021
        public bool okloaded; //28Feb2021
        public bool neverloaded; //28Feb2021

///////////////////Method Definition///////////////
        public Images()
        {
        }

///////////////////Method Definition///////////////
        public Images(int i,bool a,int cw, int ch, int xn, int yn)
        {
            index = i;
            anim = a;
            cwx = cw;
            chy = ch;
            cwn = xn;
            chn = yn;
            loaded = false;//28Feb2021
            okloaded = false; //28Feb2021
            stream = Config.STREAMLOAD; //28Feb2021
            neverloaded = true;//28Feb2021
        }
    }
    //

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class RenderList
    {
        //
        public static int transitionmode = -1; //18apr2021
        public static int HALFTRANSIT = 30;//18apr2021
        public static int TRANSITIONRATE = 1;//18apr2021
        public static int STARTTRANSITION = 60;//18apr2021
        public static int screenshake = 0;
        public static bool IGNOREZOOM;
        public static int RENDERMODE = 0;
        public static int RENDERMODE_POOL = 0;
        public static int RENDERMODE_NONPOOL = 1;
        public IntPtr texture;
        public bool istext;
        public bool isrect;
        public bool isline;
        public bool filled;
        public int x;
        public int y;
        public int w;
        public int h;
        public int blend;
        public int index;
        public int frame;
        public uint color;
        public float sx;
        public float sy;
        public bool flipx;
        public bool flipy;
        public float alpha;
        public float angle;
        public string text;
        public IntPtr font;
        public int fontindex;//2apr2021//7apr2021
        public bool drawn;
        public bool centre;
        public bool ignorezoom;
        public bool ignorefontalias;
        //
        public static int renderi = 0;
        public static int maxrenderi = 0;
        //
        public static int offsetx = 0;
        public static int offsety = 0;
        //
        public static bool threadrunning = false;
        public static int recordframe = 0;
        public static IntPtr screenshotsurface;

        //start--------------//2apr2021
        public bool subimage;
        public int subx;
        public int suby;
        public int subw;
        public int subh;
        //end----------------//2apr2021
        
///////////////////Method Definition///////////////
        public static void init()
        {
            //RenderList has an init function that is called once before drawing
            renderi = 0;
            maxrenderi = 0;
        }

///////////////////Method Definition///////////////
        public static bool CaptureThread(IntPtr screenshotsurface)
        {
            //Separate thread used for capturing screenshots
            //screenshot is captured in the main thread
            //but the file is saved in a secondary thread to
            //prevent performance hits
            //if we had a faster hard drive we could capture movies this way..!
            if(threadrunning)
            {
                return false;
            }
            threadrunning = true;
            RenderList.screenshotsurface = screenshotsurface;
            Thread thread = new Thread(new ThreadStart(ThreadFunction));
            thread.Start();    
            return true;
        }

///////////////////Method Definition///////////////
        private static void ThreadFunction()
        {
            //screenshot saving thread
            recordframe++;
            //SDL.SDL_SaveBMP(screenshotsurface,"media/screenshots/img_"+Functions.zstr(recordframe,6)+".bmp");
            try //13mar2021 - try catch block added....
            {
            SDL_image.IMG_SavePNG(screenshotsurface,"media/screenshots/img_"+Functions.zstr(recordframe,6)+".png");    

            }
            catch(Exception e)
            {
                Console.WriteLine("Thread Error Taking Screenshot:"+e.Message);
            }
            try
            {
                SDL.SDL_FreeSurface(screenshotsurface);
            }
            catch(Exception e)
            {
                string msg = e.Message;
            }
            threadrunning = false;
        }

///////////////////Method Definition///////////////
        public RenderList()
        {
            drawn = false;    
            text = "";
            font = IntPtr.Zero;
            texture = IntPtr.Zero;
            centre = false;
            ignorezoom = true;
            ignorefontalias = false;
            subimage = false;//2apr2021
            subx = 0;
            suby = 0;
            subw = 0;
            subh = 0;
        }

///////////////////Method Definition///////////////
        public static void render(Game game)
        {
            ////////////////////////
            //Core Render function that is called in the game
            //Takes all the drawimage/drawrect/drawtext calls that were stored
            //in an array and draws them one after the other
            //start------//15mar2021
            bool chinese = false;
            Functions.saveseed(Functions.seed);
            if(Translation.GetLanguage()=="chinesesimplified")
            {
                chinese = true;
            }
            if(Config.useUNICODE)
            {
                chinese = true;
            }
            //end--------//15mar2021
            SDL.SDL_Rect src;
            SDL.SDL_Rect dst;
            int SW = 0;
            int SH = 0;
            SDL.SDL_GetRendererOutputSize(game.renderer,out SW,out SH);
            game.SW = SW;
            game.SH = SH;
            float gxscale = 1f;
            float gyscale = 1f;
            for(int i=0;i<RenderList.renderi;i++)
            {
                //start----//19apr2021
                int origx = game.renderlist[i].x;
                int origy = game.renderlist[i].y;
                float origsx = game.renderlist[i].sx;
                float origsy = game.renderlist[i].sy;
                int origw = game.renderlist[i].w;
                int origh = game.renderlist[i].h;
                //end------//19apr2021
                gxscale = (float)SW / (float)Game.RESOLUTIONX;
                gyscale = (float)SH / (float)Game.RESOLUTIONY;
                game.renderlist[i].x+=RenderList.offsetx;
                game.renderlist[i].y+=RenderList.offsety;
                if(game.renderlist[i].ignorezoom==false)
                {
                    game.renderlist[i].x = Convert.ToInt32((float)game.renderlist[i].x*gxscale*game.zoom) + game.zoomcornerx;
                    game.renderlist[i].y = Convert.ToInt32((float)game.renderlist[i].y*gyscale*game.zoom) + game.zoomcornery;
                    game.renderlist[i].sx = ((float)game.renderlist[i].sx*gxscale*game.zoom);
                    game.renderlist[i].sy = ((float)game.renderlist[i].sy*gyscale*game.zoom);
                    game.renderlist[i].w = Convert.ToInt32((float)game.renderlist[i].w*gxscale*game.zoom);
                    game.renderlist[i].h = Convert.ToInt32((float)game.renderlist[i].h*gyscale*game.zoom);    
                }
                else
                {
                    game.renderlist[i].x = Convert.ToInt32((float)game.renderlist[i].x*gxscale);
                    game.renderlist[i].y = Convert.ToInt32((float)game.renderlist[i].y*gyscale);
                    game.renderlist[i].sx = ((float)game.renderlist[i].sx*gxscale);
                    game.renderlist[i].sy = ((float)game.renderlist[i].sy*gyscale);
                    game.renderlist[i].w = Convert.ToInt32((float)game.renderlist[i].w*gxscale);
                    game.renderlist[i].h = Convert.ToInt32((float)game.renderlist[i].h*gyscale);
                }
                if(screenshake>0)
                {
                    screenshake--;
                    int offsetx=(int)(gxscale*(float)(Functions.rand(0,screenshake+1)-screenshake/2));
                    int offsety=(int)(gyscale*(float)(Functions.rand(0,screenshake+1)-screenshake/2));
                    game.renderlist[i].x+=offsetx;
                    game.renderlist[i].y+=offsety;
                }
                //
                if(game.renderlist[i].sx<0)
                {
                    game.renderlist[i].sx*=-1;
                    game.renderlist[i].flipx = true;
                }
                else
                {
                    game.renderlist[i].flipx = false;
                }
                if(game.renderlist[i].sy<0)
                {
                    game.renderlist[i].sy*=-1;
                    game.renderlist[i].flipy = true;
                }
                else
                {
                    game.renderlist[i].flipy = false;
                }
                SDL.SDL_SetRenderDrawColor(game.renderer,RenderList.getcomponents(game.renderlist[i].color)[1],RenderList.getcomponents(game.renderlist[i].color)[2],RenderList.getcomponents(game.renderlist[i].color)[3],RenderList.getcomponents(game.renderlist[i].color)[0]);
                if(game.renderlist[i].isrect)
                {
                    dst.x = game.renderlist[i].x;
                    dst.y = game.renderlist[i].y;
                    dst.w = game.renderlist[i].w;
                    dst.h = game.renderlist[i].h;
                    if(game.renderlist[i].filled)
                    {
                        SDL.SDL_RenderFillRect(game.renderer,ref dst);
                    }
                    else
                    {
                        SDL.SDL_RenderDrawRect(game.renderer,ref dst);
                    }
                }
                if(game.renderlist[i].isline)
                {
                    SDL.SDL_RenderDrawLine(game.renderer,game.renderlist[i].x,game.renderlist[i].y,game.renderlist[i].x+game.renderlist[i].w,game.renderlist[i].y+game.renderlist[i].h);
                }
                if(game.renderlist[i].istext)
                {
                    SDL.SDL_Color color;
                    color.r = RenderList.getcomponents(game.renderlist[i].color)[1];
                    color.g = RenderList.getcomponents(game.renderlist[i].color)[2];
                    color.b = RenderList.getcomponents(game.renderlist[i].color)[3];
                    color.a = (byte)Convert.ToInt32(255f * game.renderlist[i].alpha);
                    IntPtr text_surface;
                    if(!chinese) //15mar2021
                    {
                        text_surface = SDL_ttf.TTF_RenderText_Solid(game.renderlist[i].font,game.renderlist[i].text,color);
                    }
                    else
                    {
                        text_surface = SDL_ttf.TTF_RenderUNICODE_Solid(game.renderlist[i].font,game.renderlist[i].text,color); //15mar2021
                    }
                    dst.x = game.renderlist[i].x;
                    dst.y = game.renderlist[i].y;
                    if(!chinese) //15mar2021
                    {
                        SDL_ttf.TTF_SizeText(game.renderlist[i].font,game.renderlist[i].text,out dst.w,out dst.h);
                    }
                    else
                    {
                        SDL_ttf.TTF_SizeText(game.renderlist[i].font,game.renderlist[i].text,out dst.w,out dst.h);
                        if(!Translation.AllAscii(game.renderlist[i].text)) //16mar2021
                        {
                            //dst.w*=Fonts.WMULTIPLIER;//17mar2021
                            if(game.renderlist[i].text!=null)//17mar2021
                            {
                                if(game.renderlist[i].text.Length>0)
                                {
                                    dst.w*=(int)System.Math.Ceiling((double)((float)Fonts.WMULTIPLIER * (float)Translation.CountNonAscii(game.renderlist[i].text)) / (float)game.renderlist[i].text.Length); //Huh!?//17mar2021
                                    dst.h*=(int)System.Math.Ceiling((double)((float)Fonts.HMULTIPLIER * (float)Translation.CountNonAscii(game.renderlist[i].text)) / (float)game.renderlist[i].text.Length);//17apr2021
                                }
                            }
                        }
                    }
                    src.x = 0;
                    src.y = 0;
                    src.w = dst.w;
                    src.h = dst.h;
                    if(game.renderlist[i].ignorefontalias)
                    {
                        dst.w = Convert.ToInt32((float)dst.w*game.renderlist[i].sx);
                        dst.h = Convert.ToInt32((float)dst.h*game.renderlist[i].sy);
                    }
                    else
                    {
                        dst.w = Convert.ToInt32((float)dst.w*game.renderlist[i].sx)/Config.FONTALIAS;
                        dst.h = Convert.ToInt32((float)dst.h*game.renderlist[i].sy)/Config.FONTALIAS;
                    }
                    if(game.renderlist[i].centre)
                    {
                        dst.x-=dst.w/2;
                        dst.y-=dst.h/2;
                    }
                    IntPtr tex = SDL.SDL_CreateTextureFromSurface(game.renderer,text_surface);
                    //SDL.SDL_SetTextureScaleMode(tex,SDL.SDL_ScaleMode.SDL_ScaleModeNearest); //already commented out a while ago
                    SDL.SDL_FreeSurface(text_surface);
                    SDL.SDL_RenderCopyEx(game.renderer,tex,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_NONE);
                    SDL.SDL_DestroyTexture(tex);
                }
                SDL.SDL_SetRenderDrawColor(game.renderer,0,0,0,0);
                if(game.renderlist[i].texture!=IntPtr.Zero)
                {
                    SDL.SDL_SetTextureAlphaMod(game.renderlist[i].texture,Convert.ToByte(255.0f*game.renderlist[i].alpha));    
                    switch(game.renderlist[i].blend)
                    {
                        case 0:
                        SDL.SDL_SetTextureBlendMode(game.renderlist[i].texture,SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
                        break;
                        case 1:
                        SDL.SDL_SetTextureBlendMode(game.renderlist[i].texture,SDL.SDL_BlendMode.SDL_BLENDMODE_ADD);
                        break;
                    }
                    //start--------------//2apr2021
                    if(game.renderlist[i].subimage)
                    {
                        src.x = game.renderlist[i].subx;
                        src.y = game.renderlist[i].suby;
                        src.w = game.renderlist[i].subw;
                        src.h = game.renderlist[i].subh;
                        dst.x = game.renderlist[i].x;
                        dst.y = game.renderlist[i].y;
                        dst.w = Convert.ToInt32(game.renderlist[i].subw * game.renderlist[i].sx);
                        dst.h = Convert.ToInt32(game.renderlist[i].subh * game.renderlist[i].sy);
                        dst.x -= dst.w/2;
                        dst.y -= dst.h/2;
                        //SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_NONE);
                        if(game.renderlist[i].flipx && game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_HORIZONTAL | SDL.SDL_RendererFlip.SDL_FLIP_VERTICAL);
                        }
                        if(game.renderlist[i].flipx && !game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_HORIZONTAL);
                        }
                        if(!game.renderlist[i].flipx && game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_VERTICAL);
                        }
                        if(!game.renderlist[i].flipx && !game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_NONE);    
                        }
                        continue;
                    }
                    //end----------------//2apr2021
                    if(game.images[game.renderlist[i].index].anim)
                    {
                        src.x = game.images[game.renderlist[i].index].cwx * (game.renderlist[i].frame % game.images[game.renderlist[i].index].cwn);
                        src.y = game.images[game.renderlist[i].index].chy * ((game.renderlist[i].frame - (game.renderlist[i].frame % game.images[game.renderlist[i].index].cwn))/game.images[game.renderlist[i].index].cwn);
                        src.w = game.images[game.renderlist[i].index].cwx;
                        src.h = game.images[game.renderlist[i].index].chy;
                        dst.x = game.renderlist[i].x;
                        dst.y = game.renderlist[i].y;
                        dst.w = Convert.ToInt32(src.w * game.renderlist[i].sx);
                        dst.h = Convert.ToInt32(src.h * game.renderlist[i].sy);
                        dst.x -= dst.w/2;
                        dst.y -= dst.h/2;
                        if(game.renderlist[i].flipx && game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_HORIZONTAL | SDL.SDL_RendererFlip.SDL_FLIP_VERTICAL);
                        }
                        if(game.renderlist[i].flipx && !game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_HORIZONTAL);
                        }
                        if(!game.renderlist[i].flipx && game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_VERTICAL);
                        }
                        if(!game.renderlist[i].flipx && !game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_NONE);    
                        }
                    }
                    else
                    {
                        src.x = 0;
                        src.y = 0;
                        src.w = game.images[game.renderlist[i].index].cwx;
                        src.h = game.images[game.renderlist[i].index].chy;
                        dst.x = game.renderlist[i].x;
                        dst.y = game.renderlist[i].y;
                        dst.w = Convert.ToInt32(game.images[game.renderlist[i].index].cwx * game.renderlist[i].sx);
                        dst.h = Convert.ToInt32(game.images[game.renderlist[i].index].chy * game.renderlist[i].sy);
                        dst.x -= dst.w/2;
                        dst.y -= dst.h/2;
                        //SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_NONE);
                        if(game.renderlist[i].flipx && game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_HORIZONTAL | SDL.SDL_RendererFlip.SDL_FLIP_VERTICAL);
                        }
                        if(game.renderlist[i].flipx && !game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_HORIZONTAL);
                        }
                        if(!game.renderlist[i].flipx && game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_VERTICAL);
                        }
                        if(!game.renderlist[i].flipx && !game.renderlist[i].flipy)
                        {
                            SDL.SDL_RenderCopyEx(game.renderer,game.renderlist[i].texture,ref src,ref dst,Convert.ToDouble(game.renderlist[i].angle),IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_NONE);    
                        }
                    }
                }
                //start----//19apr2021
                game.renderlist[i].x = origx;
                game.renderlist[i].y = origy;
                game.renderlist[i].sx = origsx;
                game.renderlist[i].sy = origsy;
                game.renderlist[i].w = origw;
                game.renderlist[i].h = origh;
                //end------//19apr2021
            }        
            if(RenderList.renderi>RenderList.maxrenderi)
            {
                RenderList.maxrenderi = RenderList.renderi;
            }
            //start-----//18apr2021
            if(transitionmode>=0)
            {
                //byte alpha = 255;
                int alpha = 255;
                if(transitionmode < HALFTRANSIT)
                {
                    RenderList.renderi = 0;
                    //alpha = (byte)(transitionmode * 8);
                    alpha = transitionmode * 8;
                }
                else
                {
                    //alpha = (byte)((60 - transitionmode) * 8);
                    alpha = (60 - transitionmode) * 8;
                }
                src.x = 0;
                src.y = 0;
                src.w = 1;
                src.h = 1;
                dst.x = 0;
                dst.y = 0;
                dst.w = SW;
                dst.h = SH;
                //if(Resources.blackcat!=-1)
                //{
                    //SDL.SDL_SetRenderDrawColor(game.renderer,(byte)(255-alpha),(byte)(255-alpha),(byte)(255-alpha),(byte)255);
                    SDL.SDL_SetRenderDrawBlendMode(game.renderer,SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
                    SDL.SDL_SetRenderDrawColor(game.renderer,0,0,0,(byte)alpha);
                    //SDL.SDL_SetRenderDrawBlendMode(game.renderer,SDL.SDL_BlendMode.SDL_BLENDMODE_MUL);
                    //SDL.SDL_SetTextureAlphaMod(game.images[Resources.blackcat].texture,alpha);    
                    //SDL.SDL_SetTextureBlendMode(game.images[Resources.blackcat].texture,SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
                    //SDL.SDL_RenderCopyEx(game.renderer,game.images[Resources.blackcat].texture,ref src,ref dst,0,IntPtr.Zero,SDL.SDL_RendererFlip.SDL_FLIP_NONE);    
                    SDL.SDL_RenderFillRect(game.renderer,ref dst);
                    SDL.SDL_SetRenderDrawBlendMode(game.renderer,SDL.SDL_BlendMode.SDL_BLENDMODE_NONE);
                    SDL.SDL_SetRenderDrawColor(game.renderer,0,0,0,0);
                    
                    
                //}
                transitionmode-=TRANSITIONRATE;
                Functions.restoreseed();
                return;
                //in other words don't clear the drawing list
                //so that we can draw over the top of it in some way
                //such as a black fade out screen......
            }
            //end-------//18apr2021
            RenderList.renderi = 0;
            Functions.restoreseed();
        }
        //draw an image

///////////////////Method Definition///////////////
        public static void drawimage(Game game,IntPtr img,int x,int y,float angle,float scalex,float scaley,int framenumber,int blend,bool istext,float alpha,int celltype)
        {
            //draw an image on the screen
            RenderList r;
            if(RenderList.renderi<game.renderlist.Length && RENDERMODE==RENDERMODE_POOL)
            {
                r = game.renderlist[RenderList.renderi];
                r.drawn = false;    
                r.text = "";
                r.font = IntPtr.Zero;
                r.texture = IntPtr.Zero;
                r.centre = false;
                r.ignorezoom = true;
                r.ignorefontalias = false;
                r.subimage = false;//2apr2021
            }
            else
            {
                r = new RenderList();
            }
            //RenderList r = new RenderList();
            //
            r.texture = img;
            r.x = x;
            r.y = y;
            r.w = 0;
            r.h = 0;
            r.isline = false;
            r.color = 0;
            r.alpha = alpha;
            r.angle = angle;
            r.sx = scalex;
            r.sy = scaley;
            r.frame = framenumber;
            r.blend = blend;
            r.istext = false;
            r.isrect = false;
            r.filled = false;
            r.index = celltype;
            //start-------------//28Feb2021
            if(celltype >= 0 && celltype < game.images.Length)
            {
                game.images[celltype].drawframe = game.frame;
            }
            //end---------------//28Feb2021
            if(RenderList.renderi>=RenderList.maxrenderi)
            {
                Array.Resize<RenderList>(ref game.renderlist,game.renderlist.Length + 1);
            }
            game.renderlist[RenderList.renderi] = r;
            game.renderlist[RenderList.renderi].ignorezoom = IGNOREZOOM;
            RenderList.renderi++;
        }
        //

///////////////////Method Definition///////////////
        public static void drawanimimage(Game game,IntPtr img,int x,int y,float angle,float scalex,float scaley,int framenumber,int blend,bool istext,float alpha,int index)
        {
            //draw an animated image on the screen
            //can be used as an alternative to drawimage, but they are mostly identical now.
            //RenderList r = new RenderList();
            RenderList r;
            if(RenderList.renderi<game.renderlist.Length && RENDERMODE==RENDERMODE_POOL)
            {
                r = game.renderlist[RenderList.renderi];
                r.drawn = false;    
                r.text = "";
                r.font = IntPtr.Zero;
                r.texture = IntPtr.Zero;
                r.centre = false;
                r.ignorezoom = true;
                r.ignorefontalias = false;
                r.subimage = false;//2apr2021
            }
            else
            {
                r = new RenderList();
            }
            //
            r.texture = img;
            r.x = x;
            r.y = y;
            r.w = 0;
            r.h = 0;
            r.isline = false;
            r.color = 0;
            r.alpha = alpha;
            r.angle = angle;
            r.sx = scalex;
            r.sy = scaley;
            r.frame = framenumber;
            r.blend = blend;
            r.istext = false;
            r.isrect = false;
            r.filled = false;
            r.index = index;
            //start-------------//28Feb2021
            if(index >= 0 && index < game.images.Length)
            {
                game.images[index].drawframe = game.frame;
            }
            //end---------------//28Feb2021
            if(RenderList.renderi>=RenderList.maxrenderi)
            {
                Array.Resize<RenderList>(ref game.renderlist,game.renderlist.Length + 1);
            }
            game.renderlist[RenderList.renderi] = r;
            game.renderlist[RenderList.renderi].ignorezoom = IGNOREZOOM;
            RenderList.renderi++;
        }

///////////////////Method Definition///////////////
        public static void drawsubimage(Game game,IntPtr img,int x,int y,float angle,float scalex,float scaley,int framenumber,int blend,bool istext,float alpha,int celltype,int ssx,int ssy,int ssw,int ssh)//2apr2021
        {
            //draw an image on the screen
            RenderList r;
            if(RenderList.renderi<game.renderlist.Length && RENDERMODE==RENDERMODE_POOL)
            {
                r = game.renderlist[RenderList.renderi];
                r.drawn = false;    
                r.text = "";
                r.font = IntPtr.Zero;
                r.texture = IntPtr.Zero;
                r.centre = false;
                r.ignorezoom = true;
                r.ignorefontalias = false;
                r.subimage = false;//2apr2021
            }
            else
            {
                r = new RenderList();
            }
            //RenderList r = new RenderList();
            //
            r.subimage = true;//2apr2021
            r.subx = ssx;//2apr2021
            r.suby = ssy;//2apr2021
            r.subw = ssw;//2apr2021
            r.subh = ssh;//2apr2021
            r.texture = img;
            r.x = x;
            r.y = y;
            r.w = 0;
            r.h = 0;
            r.isline = false;
            r.color = 0;
            r.alpha = alpha;
            r.angle = angle;
            r.sx = scalex;
            r.sy = scaley;
            r.frame = framenumber;
            r.blend = blend;
            r.istext = false;
            r.isrect = false;
            r.filled = false;
            r.index = celltype;
            //start-------------//28Feb2021
            if(celltype >= 0 && celltype < game.images.Length)
            {
                game.images[celltype].drawframe = game.frame;
            }
            //end---------------//28Feb2021
            if(RenderList.renderi>=RenderList.maxrenderi)
            {
                Array.Resize<RenderList>(ref game.renderlist,game.renderlist.Length + 1);
            }
            game.renderlist[RenderList.renderi] = r;
            game.renderlist[RenderList.renderi].ignorezoom = IGNOREZOOM;
            RenderList.renderi++;
        }
        //

        //draw primitives

///////////////////Method Definition///////////////
        public static void drawrect(Game game,int x,int y,int w,int h,uint color,int blend)
        {
            //draw a filled rect on the screen
            //RenderList r = new RenderList();
            RenderList r;
            if(RenderList.renderi<game.renderlist.Length && RENDERMODE==RENDERMODE_POOL)
            {
                r = game.renderlist[RenderList.renderi];
                r.drawn = false;    
                r.text = "";
                r.font = IntPtr.Zero;
                r.texture = IntPtr.Zero;
                r.centre = false;
                r.ignorezoom = true;
                r.ignorefontalias = false;
                r.subimage = false;//2apr2021
            }
            else
            {
                r = new RenderList();
            }
            //
            r.texture = IntPtr.Zero;
            r.x = x;
            r.y = y;
            r.w = w;
            r.h = h;
            r.isline = false;
            r.color = color;
            r.alpha = 1;
            r.angle = 0;
            r.sx = 1;
            r.sy = 1;
            r.frame = 0;
            r.blend = blend;
            r.istext = false;
            r.isrect = true;
            r.filled = true;
            r.index = 0;
            if(RenderList.renderi>=RenderList.maxrenderi)
            {
                Array.Resize<RenderList>(ref game.renderlist,game.renderlist.Length + 1);
            }
            game.renderlist[RenderList.renderi] = r;
            game.renderlist[RenderList.renderi].ignorezoom = IGNOREZOOM;
            RenderList.renderi++;
        }

///////////////////Method Definition///////////////
        public static void drawunfilledrect(Game game,int x,int y,int w,int h,uint color,int blend)
        {
            //draw an unfilled rect on the screen
            //RenderList r = new RenderList();
            RenderList r;
            if(RenderList.renderi<game.renderlist.Length && RENDERMODE==RENDERMODE_POOL)
            {
                r = game.renderlist[RenderList.renderi];
                r.drawn = false;    
                r.text = "";
                r.font = IntPtr.Zero;
                r.texture = IntPtr.Zero;
                r.centre = false;
                r.ignorezoom = true;
                r.ignorefontalias = false;
                r.subimage = false;//2apr2021
            }
            else
            {
                r = new RenderList();
            }
            //
            r.texture = IntPtr.Zero;
            r.x = x;
            r.y = y;
            r.w = w;
            r.h = h;
            r.isline = false;
            r.color = color;
            r.alpha = 1;
            r.angle = 0;
            r.sx = 1;
            r.sy = 1;
            r.frame = 0;
            r.blend = blend;
            r.istext = false;
            r.isrect = true;
            r.filled = false;
            r.index = 0;
            if(RenderList.renderi>=RenderList.maxrenderi)
            {
                Array.Resize<RenderList>(ref game.renderlist,game.renderlist.Length + 1);
            }
            game.renderlist[RenderList.renderi] = r;
            game.renderlist[RenderList.renderi].ignorezoom = IGNOREZOOM;
            RenderList.renderi++;
        }

///////////////////Method Definition///////////////
        public static void drawline(Game game,int sx,int sy,int fx,int fy,uint color,int blend)
        {
            //draw a solid line on the screen
            //can also draw points.
            //RenderList r = new RenderList();
            RenderList r;
            if(RenderList.renderi<game.renderlist.Length && RENDERMODE==RENDERMODE_POOL)
            {
                r = game.renderlist[RenderList.renderi];
                r.drawn = false;    
                r.text = "";
                r.font = IntPtr.Zero;
                r.texture = IntPtr.Zero;
                r.centre = false;
                r.ignorezoom = true;
                r.ignorefontalias = false;
                r.subimage = false;//2apr2021
            }
            else
            {
                r = new RenderList();
            }
            //
            r.texture = IntPtr.Zero;
            r.x = sx;
            r.y = sy;
            r.w = (int)Functions.abs(fx - sx);
            r.h = (int)Functions.abs(fy - sy);
            if(fx<sx)
            {
                sx = fx;
            }
            if(fy<sy)
            {
                sy = fy;
            }
            r.isline = true;
            r.color = color;
            r.alpha = 1;
            r.angle = 0;
            r.sx = 1;
            r.sy = 1;
            r.frame = 0;
            r.blend = blend;
            r.istext = false;
            r.isrect = false;
            r.filled = false;
            r.index = 0;
            if(RenderList.renderi>=RenderList.maxrenderi)
            {
                Array.Resize<RenderList>(ref game.renderlist,game.renderlist.Length + 1);
            }
            game.renderlist[RenderList.renderi] = r;
            game.renderlist[RenderList.renderi].ignorezoom = IGNOREZOOM;
            RenderList.renderi++;
        }
        //draw text
///////////////////Method Definition///////////////
        public static void drawtext(Game game,int x,int y,string text,uint color,IntPtr font,bool centre)
        {
            //draw text with a certain font on the screen
            //RenderList r = new RenderList();
            RenderList r;
            if(RenderList.renderi<game.renderlist.Length && RENDERMODE==RENDERMODE_POOL)
            {
                r = game.renderlist[RenderList.renderi];
                r.drawn = false;    
                r.text = "";
                r.font = IntPtr.Zero;
                r.texture = IntPtr.Zero;
                r.centre = false;
                r.ignorezoom = true;
                r.ignorefontalias = false;
                r.subimage = false;//2apr2021
            }
            else
            {
                r = new RenderList();
            }
            //
            r.texture = IntPtr.Zero;
            r.x = x;
            r.y = y;
            r.w = 0;
            r.h = 0;
            r.isline = false;
            r.color = color;
            r.alpha = 1;
            r.angle = 0;
            r.sx = 1;
            r.sy = 1;
            r.frame = 0;
            r.blend = 0;
            r.istext = true;
            r.isrect = false;
            r.filled = false;
            r.index = 0;
            r.text = text;
            r.font = font;
            r.ignorefontalias = false;
            if(font==game.fonts[Resources.SMALLFONT].font)
            {
                if(game.fonts[Resources.SMALLFONT].ptsize<20)
                {
                    r.ignorefontalias = true;
                }
                r.fontindex = Resources.SMALLFONT;//7apr2021
            }
            if(font==game.fonts[Resources.FONT].font)
            {
                if(game.fonts[Resources.FONT].ptsize<20)
                {
                    r.ignorefontalias = true;
                }
                r.fontindex = Resources.FONT;//7apr2021
            }
            if(font==game.fonts[Resources.LARGEFONT].font)
            {
                if(game.fonts[Resources.LARGEFONT].ptsize<20)
                {
                    r.ignorefontalias = true;
                }
                r.fontindex = Resources.LARGEFONT;//7apr2021
            }
            r.centre = centre;
            if(RenderList.renderi>=RenderList.maxrenderi)
            {
                Array.Resize<RenderList>(ref game.renderlist,game.renderlist.Length + 1);
            }
            game.renderlist[RenderList.renderi] = r;
            game.renderlist[RenderList.renderi].ignorezoom = IGNOREZOOM;
            RenderList.renderi++;
        }

///////////////////Method Definition///////////////
        public static void drawtext(Game game,IntPtr font,int x,int y,float angle,float scalex,float scaley,bool centre,int blend,string text,float alpha,uint color)
        {
            //alternative drawtext command
            //RenderList r = new RenderList();
            RenderList r;
            if(RenderList.renderi<game.renderlist.Length && RENDERMODE==RENDERMODE_POOL)
            {
                r = game.renderlist[RenderList.renderi];
                r.drawn = false;    
                r.text = "";
                r.font = IntPtr.Zero;
                r.texture = IntPtr.Zero;
                r.centre = false;
                r.ignorezoom = true;
                r.ignorefontalias = false;
                r.subimage = false;//2apr2021
            }
            else
            {
                r = new RenderList();
            }
            //
            r.texture = IntPtr.Zero;
            r.x = x;
            r.y = y;
            r.w = 0;
            r.h = 0;
            r.isline = false;
            r.color = color;
            r.alpha = alpha;
            r.angle = angle;
            r.sx = scalex;
            r.sy = scaley;
            r.frame = 0;
            r.blend = blend;
            r.istext = true;
            r.isrect = false;
            r.filled = false;
            r.index = 0;
            r.text = text;
            r.font = font;
            r.ignorefontalias = false;
            if(font==game.fonts[Resources.SMALLFONT].font)
            {
                if(game.fonts[Resources.SMALLFONT].ptsize<20)
                {
                    r.ignorefontalias = true;
                }
                r.fontindex = Resources.SMALLFONT;//7apr2021
            }
            if(font==game.fonts[Resources.FONT].font)
            {
                if(game.fonts[Resources.FONT].ptsize<20)
                {
                    r.ignorefontalias = true;
                }
                r.fontindex = Resources.FONT;//7apr2021
            }
            if(font==game.fonts[Resources.LARGEFONT].font)
            {
                if(game.fonts[Resources.LARGEFONT].ptsize<20)
                {
                    r.ignorefontalias = true;
                }
                r.fontindex = Resources.LARGEFONT;//7apr2021
            }
            r.centre = centre;
            if(RenderList.renderi>=RenderList.maxrenderi)
            {
                Array.Resize<RenderList>(ref game.renderlist,game.renderlist.Length + 1);
            }
            game.renderlist[RenderList.renderi] = r;
            game.renderlist[RenderList.renderi].ignorezoom = IGNOREZOOM;
            RenderList.renderi++;
        }
        //rgb helper functions.

///////////////////Method Definition///////////////
        public static uint getrgb(int r, int g, int b)
        {
            //return the rgb value by its components
            return (uint)(255 << 24 | (byte)r << 16 | (byte)g << 8 | (byte)b);
        }

///////////////////Method Definition///////////////
        public static uint getrgb(byte r,byte g, byte b)
        {
            //return the rgb value by its components
            return (uint)(255 << 24 | r << 16 | g << 8 | b);
        }

///////////////////Method Definition///////////////
        public static byte[] getcomponents(uint argb)
        {
            //get the components of an argb colour and return an array of alpha, red, green, blue as a bunch of byte values
            byte[] rgbarray = {0,0,0,0};
            rgbarray[0] = (byte)((argb >> 24) & (255));
            rgbarray[1] = (byte)((argb >> 16) & (255));
            rgbarray[2] = (byte)((argb >> 8) & 255);
            rgbarray[3] = (byte)((argb & 255));
            return rgbarray;
        }
    }
    //
    

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class Network
    {
        //Network.url = "https://www.mattiesgames.com/metrics/metric.php?game="+Game.NETTITLE+"&event=[your event here]&value="[your value here];
        //Network.httpget(Network.url);
        public static string url = "";

        public static string errorreport = "";    
        public static string ERRORURL = "https://www.mattiesgames.com/metrics/metric.php?game=grumthorr&event=errorlog&value=error:";

///////////////////Method Definition///////////////
        private static void ThreadFunction()
        {
            //send a network message to a website
            //typically used for sending metrics
            //or such. return values are ignored
            if(Network.url=="")
            {
                return;
            }
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Network.url);
                request.Timeout = 10000;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                //start---//1apr2021
                Stream stream = response.GetResponseStream();
                Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
                StreamReader read = new StreamReader(stream,encode);
                Char[] chararray = new Char[256];
                if(Config.GETDATA)
                {
                    int count = read.Read(chararray,0,256);
                    while(count>0)
                    {
                        String str = new String(chararray,0,count);
                        //Console.WriteLine(str);
                        count = read.Read(chararray,0,256);
                    }
                }
                response.Close();//1apr2021
                read.Close();
                //end---//1apr2021
            }
            catch(Exception e)
            {
                string message = (e.Message);
            }
        }

///////////////////Method Definition///////////////
        private static void ErrorFunction()
        {
            //send error information to a location
            //should the game have an error on intialisation
            Network.url = Network.ERRORURL+Network.errorreport;
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Network.url);
                request.Timeout = 10000;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                //start---//1apr2021
                Stream stream = response.GetResponseStream();
                Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
                StreamReader read = new StreamReader(stream,encode);
                Char[] chararray = new Char[256];
                int count = read.Read(chararray,0,256);
                if(Config.GETDATA)
                {
                    while(count>0)
                    {
                        String str = new String(chararray,0,count);
                        //Console.WriteLine(str);
                        count = read.Read(chararray,0,256);
                    }
                }
                response.Close();//1apr2021
                read.Close();
                //end---//1apr2021
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message);
            }
            Network.url = "";
        }

///////////////////Method Definition///////////////
        public static void httpget(string u)
        {
            //basic function for performing a http get operation
            //runs in a separate thread
            if(Config.NOMETRICS)
            {
                return;
            }
            Network.url = u;
            try
            {
            Thread thread = new Thread(new ThreadStart(ThreadFunction));
            thread.Start();
            }
            catch(Exception e)
            {
                string message = e.Message;
            }
        }

///////////////////Method Definition///////////////
        public static void reporterror(bool send)
        {
            //report an error in intialisation of the game
            if(Network.errorreport=="")
            {
                return;
            }
            if(send)
            {
                Network.errorreport+="endoferrors";
                Thread thread = new Thread(new ThreadStart(ErrorFunction));
                thread.Start();
            }
        }

///////////////////Method Definition///////////////
        public static void reporterror(string report,bool send)
        {
            //alternative reporting of an error method
            Network.errorreport+=report+":";
            if(send)
            {
                Network.errorreport+="endoferrors";
                Thread thread = new Thread(new ThreadStart(ErrorFunction));
                thread.Start();
            }
        }
    }
    

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
    class Functions
    {
        public static int oseed = 12345678;
        public static int seed = 12345678;
        public static int[] seeds = new int[0];
        //
///////////////////Method Definition///////////////
        public static string ClockTime(int seconds)
        {
            int mins = (seconds - (seconds % 60)) / 60;
            int secs = seconds % 60;
            return zstr(mins,2) + ":" + zstr(secs,2);
        }
        
///////////////////Method Definition///////////////
        public static string zstr(int i,int n)
        {
            //return an integer number such as 123 as 00123,
            //i = the number
            //n = the number of digits to use
            string s = "" + i;
            while(s.Length<n)
            {
                s = "0" + s;
            }
            return s;
        }

///////////////////Method Definition///////////////
        public static void saveseed() //11apr2021
        {
            oseed = seed;
            Array.Resize(ref seeds,seeds.Length + 1); //11apr2021
            seeds[seeds.Length - 1] = seed;//11apr2021
        }
        
///////////////////Method Definition///////////////
        public static void saveseed(int s)
        {
            //save the random number seed for later use
            oseed = seed;
            seed = s;
            Array.Resize(ref seeds,seeds.Length + 1);//11apr2021
            seeds[seeds.Length - 1] = s;//11apr2021
        }

///////////////////Method Definition///////////////
        public static void restoreseed()
        {
            //restore the random number seed which was saved earlier
            //seed = oseed;//11apr2021
            if(seeds.Length>0)//11apr2021
            {
                seed = seeds[seeds.Length - 1];//11apr2021
                Array.Resize(ref seeds,seeds.Length -1);//11apr2021
            }
            else//11apr2021
            {
                seed = oseed;//11apr2021
                Console.WriteLine("Warning:Seeds Out of Sync");//11apr2021
            }
        }

///////////////////Method Definition///////////////
        public static float abs(float value)
        {
            //absolute value
            if(value<0)
            {
                return -1* value;
            }
            return value;
        }

///////////////////Method Definition///////////////
        public static int Rand(int min,int max)
        {
            //random number generator
            return min + Convert.ToInt32(random()*(double)(max-min));
        }        
        //

///////////////////Method Definition///////////////
        public static int Sign(float value)
        {
            //return the sign positive or negative of the number, or zero
            if(value>0){return 1;}
            if(value<0){return -1;}
            return 0;    
        }
        //

///////////////////Method Definition///////////////
        public static int rand(int min,int max)
        {
            //random number generator
            return Rand(min,max);
        }
        //

///////////////////Method Definition///////////////
        public static int sign(float value)
        {
            //alias of Sign
            return Sign(value);
        }
        //

///////////////////Method Definition///////////////
        public static double random()
        {
            //pseudo random number generator
            Functions.seed = ((89723453 * Functions.seed + 42854321) % 1000000);
            double r = ((double)Functions.seed / 1000000.0);
            if(r<0)
            {
                r*=-1.0;
            }
            return r;
        }
        /*

///////////////////Method Definition///////////////
        public static float calcangle(float x, float y)
        {
        //    return Math.atan2(y, x) ;
        }
        //
        *
/

///////////////////Method Definition///////////////
        public static int isox(int x,int y,int w)
        {
            //isometric calculation
            //pass in the grid square and return a location in screen coordinates
            return (w/2) * (1 + x - y);
        }
        //

///////////////////Method Definition///////////////
        public static int isoy(int x,int y,int w)
        {
            //isometric calculation
            //pass in the grid square and return a location in screen coordinates
            return (w/4) * (1 + y + x);
        }
        //

///////////////////Method Definition///////////////
        public static int screentoisox(int sx,int sy,int w,int offsetx,int offsety)
        {
            //isometric calculation
            //pass in screen coordinates and convert to iso x grid
            sx-=offsetx;
            sy-=offsety;
            return Convert.ToInt32((((float)sx + 2f * (float)sy)/(float)w) - 1f);
        }
        //

///////////////////Method Definition///////////////
        public static int screentoisoy(int sx,int sy,int w,int offsetx,int offsety)
        {
            //isometric calculation
            //pass in screen coordinates and convert to iso y grid
            sx-=offsetx;
            sy-=offsety;
            return Convert.ToInt32((2f*(float)sy - (float)sx)/(float)w);
        }
    }
    //

///////////////////////////////////////////////////
///////////////////Class Definition////////////////
     class Program
     {
        //game specific stuff here
        //
        //RTS Components
        //

///////////////////Method Definition///////////////
        static void Main(string[] args)
                     {
            if(args!=null)
            {
                if(args.Length>0)
                {
                    if(args[0] == "-editor")
                    {
                        Game.EDITOR = true;
                    }
                }
            }
            //init(); //13mar2021
            //start--------------//13mar2021
            Game.restart = true;
            Game.restartgamestate = -1;//26mar2021
            while(Game.restart)
            {
                Game.restart = false;
                init();
            }
            //end----------------//13mar2021
                     }

///////////////////Method Definition///////////////
        //static void checkconfig() //28Feb2021

///////////////////Method Definition///////////////
        static bool checkconfig() //28Feb2021
        {
            //Game initialisation - check the config file
            //and setup initial parameters including the filenames and paths
            //to check for all the various game components
            //language also set here
            //start-------------//12mar2021
            Config.useUNICODE = false; //15mar2021
            if(Config.KOG2)
            {
                Game.NETTITLE = "grumthorr2";
                Game.TITLE = "Knights of Grumthorr 2";
            }
            //end---------------//12mar2021
            //25Feb2021 - altered order of try/catch statements...config file read first.
            string folder = "";
            string folderu = "";
            string folderd = "";
            //start-------------//28Feb2021
            Config.configfile = "media/txt/config.txt"; //28Feb2021
            try
            {
                string[] cdata = System.IO.File.ReadAllLines("media/txt/init.txt");
                for(int i=0;i<cdata.Length;i++)
                {
                    if(cdata[i].IndexOf("=")>0)
                    {
                        switch(cdata[i].Substring(0,cdata[i].IndexOf("=")))
                        {
                            case "config":
                            Config.configfile = Resources.readstring(cdata[i]);
                            break;
                        }
                    }
                }
            }
            catch(Exception e)
            {
                //do nothing
                Console.WriteLine("Warning - Error reading init.txt:"+e.Message);
                Config.configfile = "media/txt/config.txt"; //28Feb2021
            }
            //end---------------//28Feb2021
            try
            {
                //string[] data = System.IO.File.ReadAllLines("media/txt/config.txt"); //28Feb2021
                string[] data = System.IO.File.ReadAllLines(Config.configfile); //28Feb2021
                for(int i=0;i<data.Length;i++)
                {
                    if(data[i].IndexOf("=")>0)
                    {
                        switch(data[i].Substring(0,data[i].IndexOf("=")))
                        {
                            case "fastframecheck"://14sep2021
                            Config.FASTFRAMECHECK = Resources.readint(data[i]);//14sep2021
                            break;
                            case "usedelta"://18sep2021
                            Config.USEDELTATIME = Resources.readint(data[i]);//18sep2021
                            break;
                            case "noupdateindemomode"://18sep2021
                            Config.NOUPDATEINDEMOMODE = Resources.readint(data[i]);//18sep2021
                            break;
                            case "maxfps"://18sep2021
                            Config.UNLOCKFRAMERATE = Resources.readint(data[i]);//18sep2021
                            break;
                            case "autoplay"://18sep2021
                            Config.AUTOPLAY = Resources.readint(data[i]);//18sep2021
                            break;
                            case "noshowability"://16sep2021
                            Config.NOSHOWABILITY = Resources.readint(data[i]);//16sep2021
                            break;
                            case "optimisefires"://15sep2021
                            Config.OPTIMISEFIRES = Resources.readint(data[i]);//15sep2021
                            break;
                            case "clump"://15sep2021
                            Config.CLUMP = Resources.readint(data[i]);//15sep2021
                            break;
                            case "tilefog"://15sep2021
                            Config.TILEFOG = Resources.readint(data[i]);//15sep2021
                            break;
                            case "noreplay"://15sep2021
                            Config.NOREPLAY = Resources.readint(data[i]);//15sep2021
                            break;
                            case "gridw"://10sep2021
                            Map.DEFAULTGRIDW = Resources.readint(data[i]);//10sep2021
                            break;//10sep2021
                            case "gridh"://10sep2021
                            Map.DEFAULTGRIDH = Resources.readint(data[i]);//10sep2021
                            break;//10sep2021
                            case "VER"://16apr2021
                            Game.VERSIONSTR = Resources.readstring(data[i]);//16apr2021
                            break;
                            case "NETTITLE": //25Feb2021
                            Game.NETTITLE = Resources.readstring(data[i]);//25Feb2021;
                            break;//25Feb2021
                            case "TITLE"://2sep2021
                            Game.TITLE = Resources.readstring(data[i]);//2sep2021
                            break;//2sep2021
                            case "PATHTHREADING"://29may2021
                            if(Resources.readint(data[i])>0 && Environment.ProcessorCount>=4)
                            {
                                Config.THREADEDPATHING = true;
                            }
                            else
                            {
                                Config.THREADEDPATHING = false;
                            }
                            break;
                            case "KEYFRAME": //21apr2021
                            Replay.KEYFRAME = Resources.readint(data[i]);
                            if(Replay.KEYFRAME<1)
                            {
                                Replay.KEYFRAME = 1;
                            }
                            break;
                            //start-----------------//21mar2021
                            case "usecoverflag":
                            if(Resources.readstring(data[i])=="1")
                            {
                                Config.USECOVERFLAG = true;
                            }
                            if(Resources.readstring(data[i])=="0")
                            {
                                Config.USECOVERFLAG = false;
                            }
                            break;
                            case "usefeetcircles":
                            if(Resources.readstring(data[i])=="1")
                            {
                                Config.USEFEETCIRCLES = true;
                            }
                            if(Resources.readstring(data[i])=="0")
                            {
                                Config.USEFEETCIRCLES = false;
                            }
                            break;
                            case "translategui":
                            if(Resources.readstring(data[i])=="1")
                            {
                                Config.TRANSLATEGUI = true;
                            }
                            if(Resources.readstring(data[i])=="0")
                            {
                                Config.TRANSLATEGUI = false;
                            }
                            break;
                            case "useiconcircles":
                            if(Resources.readstring(data[i])=="1")
                            {
                                Config.USEICONCIRCLES = true;
                            }
                            if(Resources.readstring(data[i])=="0")
                            {
                                Config.USEICONCIRCLES = false;
                            }
                            break;
                            //end-------------------//21mar2021
                            case "fullscreen":
                            Game.FULLSCREEN = Resources.readint(data[i]);
                            break;
                            case "resize"://22may2021
                            Config.WINDOWRESIZE = Resources.readint(data[i]);//22may2021
                            break;//22may2021
                            case "hires"://10apr2021
                            Config.hires = Resources.readint(data[i]);//10apr202
                            break;//10apr2021
                            case "musicvolume":
                            Game.MUSICVOLUME = Resources.readint(data[i]);
                            Game.oMUSICVOLUME = Game.MUSICVOLUME;
                            if(Game.EDITOR)
                            {
                                Game.MUSICVOLUME = 0;
                            }
                            break;
                            //start--------------//13mar2021
                            case "words":
                            Config.wordsfile = Resources.readstring(data[i]);
                            break;
                            //end----------------//13mar2021
                            case "fxvolume":
                            Game.FXVOLUME = Resources.readint(data[i]);
                            Game.oFXVOLUME = Game.FXVOLUME;
                            break;
                            case "guifile":
                            Config.guifile = Resources.readstring(data[i]);
                            break;
                            case "fontalias":
                            Config.FONTALIAS = Resources.readint(data[i]);
                            if(Config.FONTALIAS<1)
                            {
                                Config.FONTALIAS = 1;
                            }
                            break;
                            //start-----------------//20mar2021
                            case "healthmod":
                            Config.HEALTHPCT = Resources.readint(data[i]);
                            break;
                            case "armourmod":
                            Config.ARMOURPCT = Resources.readint(data[i]);
                            break;
                            case "attackmod":
                            Config.ATTACKPCT = Resources.readint(data[i]);
                            break;
                            //end-------------------//20mar2021
                            case "campaignfile":
                            Config.campaignfile = Resources.readstring(data[i]);
                            break;
                            case "skirmishmessage":
                            Config.skirmishmessage = Resources.readstring(data[i]);
                            break;
                            case "customcampaignfile":
                            Config.customcampaignfile = Resources.readstring(data[i]);
                            break;
                            case "unitsfile":
                            Config.unitsfile = Resources.readstring(data[i]);
                            break;
                            case "techfile": //2sep2021
                            Config.techfile = Resources.readstring(data[i]);//2sep2021
                            break;//2sep2021
                            case "defaultfontfile":
                            Config.defaultfontfile = Resources.readstring(data[i]);
                            break;
                            case "normalfontsize":
                            Config.normalfontsize = Resources.readint(data[i]);// * Config.FONTALIAS;
                            break;
                            case "smallfontsize":
                            Config.smallfontsize = Resources.readint(data[i]);// * Config.FONTALIAS;
                            break;
                            case "largefontsize":
                            Config.largefontsize = Resources.readint(data[i]);// * Config.FONTALIAS;
                            break;
                            case "audioclickfile":
                            Config.audioclickfile = Resources.readstring(data[i]);
                            break;
                            case "offsetfile"://20apr2021
                            Config.offsetfile = Resources.readstring(data[i]);//20apr2021
                            break;
                            case "DOCALCOFFSETS"://20apr2021
                            if(Resources.readint(data[i])==1)
                            {
                                Config.AUTOCALCOFFSETS = true;
                            }
                            else
                            {
                                Config.AUTOCALCOFFSETS = false;
                            }
                            break;
                            case "logofile":
                            Config.logofile = Resources.readstring(data[i]);
                            break;
                            case "fogfile":
                            Config.fogfile = Resources.readstring(data[i]);
                            break;
                            case "logowidth":
                            Config.logowidth = Resources.readint(data[i]);
                            break;
                            case "logoheight":
                            Config.logoheight = Resources.readint(data[i]);
                            break;
                            case "fogwidth":
                            Config.fogwidth = Resources.readint(data[i]);
                            break;
                            case "fogheight":
                            Config.fogheight = Resources.readint(data[i]);
                            break;
                            case "record": //13mar2021
                            if(Resources.readint(data[i])==1)
                            {
                                Config.RECORD = true;
                            }
                            break;
                            case "useunicode": //15mar2021
                                if(Resources.readint(data[i])==1)
                                {
                                    Config.useUNICODE = true;
                                }
                                if(Resources.readint(data[i])==0)
                                {
                                    Config.useUNICODE = false;
                                }
                            break;
                        }
                    }
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("Error reading config.txt:"+e.Message);
                return false; //28Feb2021
            }
            try
            {
                folderd = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)+"\\"+Game.NETTITLE;
                if(!Directory.Exists(folderd))
                {
                    Directory.CreateDirectory(folderd);
                }
            }
            catch(Exception e)
            {
                string message = e.Message;
            }
            try
            {
                string[] datad = System.IO.File.ReadAllLines(folderd+"\\nometrics.txt");
                if(datad.Length>0)
                {
                    Config.NOMETRICS = true;
                }
            }
            catch(Exception e)
            {
                string mm = e.Message;
            }
            try
            {
                folderu = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)+"\\"+Game.NETTITLE+"\\usercampaign";
                if(!Directory.Exists(folderu))
                {
                    Directory.CreateDirectory(folderu);
                }
                if(Directory.Exists(folderu))
                {
                    Config.usercampaignfolder = folderu;
                    Config.usercampaignfile = folderu + "\\usercampaign.txt";
                }
            }
            catch(Exception e)
            {
                string message = e.Message;
            }
            try
            {
                folder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)+"\\"+Game.NETTITLE+"\\custommaps";
                if(!Directory.Exists(folder))
                {
                    Directory.CreateDirectory(folder);
                }
                if(Directory.Exists(folder))
                {
                    Config.custommapfolder = folder;
                }
            }
            catch(Exception e)
            {
                string message = e.Message;
            }
            if(Game.EDITOR)
            {
                Game.FULLSCREEN = 0;
            }
            LocalStorage.init();//12mar2021
            //LocalStorage.WriteLog("Begin");
            LocalStorage.finalise();//13mar2021
            applyprefs();
            return true; //28Feb2021
        }

///////////////////Method Definition///////////////
        static void applyprefs() //12mar2021
        {
            //start---------------//30mar2021
            if(LocalStorage.getitem("uid")!="")
            {
                Config.uid = LocalStorage.getitem("uid");
            }
            else
            {
                long milliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
                Config.uid = ""+milliseconds;
                LocalStorage.setitem("uid",Config.uid);
            }
            //end-----------------//30mar2021
            //apply preferences and language settings
            Fonts.WMULTIPLIER = 1;//15mar2021
            Fonts.HMULTIPLIER = 1;//17apr2021
            if(LocalStorage.getitem("sfx")=="off")
            {
                Game.oFXVOLUME = Game.FXVOLUME;
                Game.FXVOLUME = 0;
            }
            if(LocalStorage.getitem("music")=="off")
            {
                Game.oMUSICVOLUME = Game.MUSICVOLUME;
                Game.MUSICVOLUME = 0;
            }
            //start------------//17apr2021
            if(LocalStorage.getitem("hires")=="0")
            {
                Config.hires = 0;
            }
            if(LocalStorage.getitem("hires")=="1")
            {
                Config.hires = 1;
            }
            if(LocalStorage.getitem("fullscreen")=="0")
            {
                Game.FULLSCREEN = 0;
            }
            if(LocalStorage.getitem("fullscreen")=="1")
            {
                Game.FULLSCREEN = 1;
            }
            //end--------------//17apr2021
            //start--------------//13mar2021
            string language = Translation.GetLanguage();
            //start------------------//18mar2021
            if(language=="")
            {
                try
                {
                    string langcode = CultureInfo.CurrentUICulture.Name;
                    switch(langcode.Substring(0,2))
                    {
                        case "en": //English
                            language = "english";
                        break;
                        case "de": //German
                            language = "german";
                        break;
                        case "fr": //French
                            language = "french";
                        break;
                        case "es": //Spanish
                            language = "spanish";
                        break;
                        case "zh": //Chinese
                            if(langcode=="zh-CN")
                            {
                                language = "chinesesimplified";
                            }
                        break;
                        case "tr": //Turkish//22mar2021
                            language = "turkish";
                        break;
                        case "ru": //Russian
                            language = "russian";
                        break;
                        case "ro": //Romanian //21mar2021
                            language = "romanian";
                        break;
                    }
                    if(language!="")
                    {
                        Console.WriteLine("Language Found and Chosen:"+language);
                        //LocalStorage.WriteLog("Language Found and Chosen:"+language);
                        Config.autodetectlang = language;//30mar2021
                    }
                    else
                    {
                        Console.WriteLine("Possible language not supported");
                        //LocalStorage.WriteLog("Possible language not supported");
                    }
                }
                catch(Exception e)
                {
                    Console.WriteLine("Error getting UI Language:"+e.Message);
                    //LocalStorage.WriteLog("Error getting UI Language:"+e.Message);
                }
            }
            //end--------------------//18mar2021
            if(language!="")
            {
                string altconfigfile = Config.configfile + language;
                try
                {
                    string[] data = System.IO.File.ReadAllLines(altconfigfile); //28Feb2021
                    for(int i=0;i<data.Length;i++)
                    {
                        if(data[i].IndexOf("=")>0)
                        {
                            switch(data[i].Substring(0,data[i].IndexOf("=")))
                            {
                                case "foreignnumbers":
                                Translation.init(Resources.readstring(data[i]));
                                break;
                                //start--------------//13mar2021
                                case "words":
                                Config.wordsfile = Resources.readstring(data[i]);
                                break;
                                //end----------------//13mar2021
//                                case "NETTITLE": //25Feb2021
//                                Game.NETTITLE = Resources.readstring(data[i]);//25Feb2021;
//                                break;//25Feb2021
//                                case "fullscreen":
//                                Game.FULLSCREEN = Resources.readint(data[i]);
//                                break;
//                                case "musicvolume":
//                                Game.MUSICVOLUME = Resources.readint(data[i]);
//                                Game.oMUSICVOLUME = Game.MUSICVOLUME;
//                                if(Game.EDITOR)
//                                {
//                                    Game.MUSICVOLUME = 0;
//                                }
//                                break;
//                                case "fxvolume":
//                                Game.FXVOLUME = Resources.readint(data[i]);
//                                Game.oFXVOLUME = Game.FXVOLUME;
//                                break;
                                case "guifile":
                                Config.guifile = Resources.readstring(data[i]);
                                break;
                                case "fontalias":
                                Config.FONTALIAS = Resources.readint(data[i]);
                                if(Config.FONTALIAS<1)
                                {
                                    Config.FONTALIAS = 1;
                                }
                                break;
                                case "fastframecheck"://14sep2021
                                Config.FASTFRAMECHECK = Resources.readint(data[i]);//14sep2021
                                break;
                                case "noreplay"://15sep2021
                                Config.NOREPLAY = Resources.readint(data[i]);//15sep2021
                                break;
                                case "noupdateindemomode"://18sep2021
                                Config.NOUPDATEINDEMOMODE = Resources.readint(data[i]);//18sep2021
                                break;
                                case "usedelta"://18sep2021
                                Config.USEDELTATIME = Resources.readint(data[i]);//18sep2021
                                break;
                                case "maxfps"://18sep2021
                                Config.UNLOCKFRAMERATE = Resources.readint(data[i]);//18sep2021
                                break;
                                case "autoplay"://18sep2021
                                Config.AUTOPLAY = Resources.readint(data[i]);//18sep2021
                                break;
                                case "noshowability"://16sep2021
                                Config.NOSHOWABILITY = Resources.readint(data[i]);//16sep2021
                                break;
                                case "optimisefires"://15sep2021
                                Config.OPTIMISEFIRES = Resources.readint(data[i]);//15sep2021
                                break;
                                case "clump"://15sep2021
                                Config.CLUMP = Resources.readint(data[i]);//15sep2021
                                break;
                                case "tilefog"://15sep2021
                                Config.TILEFOG = Resources.readint(data[i]);//15sep2021
                                break;
                                case "campaignfile":
                                Config.campaignfile = Resources.readstring(data[i]);
                                break;
                                case "skirmishmessage":
                                Config.skirmishmessage = Resources.readstring(data[i]);
                                break;
                                case "customcampaignfile":
                                Config.customcampaignfile = Resources.readstring(data[i]);
                                break;
                                case "unitsfile":
                                Config.unitsfile = Resources.readstring(data[i]);
                                break;
                                case "gridw"://10sep2021
                                Map.DEFAULTGRIDW = Resources.readint(data[i]);//10sep2021
                                break;//10sep2021
                                case "gridh"://10sep2021
                                Map.DEFAULTGRIDH = Resources.readint(data[i]);//10sep2021
                                break;//10sep2021
                                case "techfile"://2sep2021
                                Config.techfile = Resources.readstring(data[i]);//2sep2021
                                break;//2sep2021
                                case "defaultfontfile":
                                Config.defaultfontfile = Resources.readstring(data[i]);
                                break;
                                case "normalfontsize":
                                Config.normalfontsize = Resources.readint(data[i]);// * Config.FONTALIAS;
                                break;
                                case "smallfontsize":
                                Config.smallfontsize = Resources.readint(data[i]);// * Config.FONTALIAS;
                                break;
                                case "largefontsize":
                                Config.largefontsize = Resources.readint(data[i]);// * Config.FONTALIAS;
                                break;
                                case "fonthmultiplier"://17apr2021
                                Fonts.HMULTIPLIER = Resources.readint(data[i]);
                                if(Fonts.HMULTIPLIER<1)
                                {
                                    Fonts.HMULTIPLIER = 1;
                                }
                                break;
                                case "fontwmultiplier": //15mar2021
                                Fonts.WMULTIPLIER = Resources.readint(data[i]);
                                if(Fonts.WMULTIPLIER<1)
                                {
                                    Fonts.WMULTIPLIER = 1;
                                }
                                break;
                                case "offsetfile"://20apr2021
                                Config.offsetfile = Resources.readstring(data[i]);//20apr2021
                                break;
                                case "audioclickfile":
                                Config.audioclickfile = Resources.readstring(data[i]);
                                break;
//                                case "logofile":
//                                Config.logofile = Resources.readstring(data[i]);
//                                break;
//                                case "fogfile":
//                                Config.fogfile = Resources.readstring(data[i]);
//                                break;
//                                case "logowidth":
//                                Config.logowidth = Resources.readint(data[i]);
//                                break;
//                                case "logoheight":
//                                Config.logoheight = Resources.readint(data[i]);
//                                break;
//                                case "fogwidth":
//                                Config.fogwidth = Resources.readint(data[i]);
//                                break;
//                                case "fogheight":
//                                Config.fogheight = Resources.readint(data[i]);
//                                break;
//                                case "record": //13mar2021
//                                if(Resources.readint(data[i])==1)
//                                {
//                                    Config.RECORD = true;
//                                }
//                                break;
                                case "translategui": //21mar2021
                                if(Resources.readstring(data[i])=="1")
                                {
                                    Config.TRANSLATEGUI = true;
                                }