diff --git a/xtrn/dicewarz2/ai.js b/xtrn/dicewarz2/ai.js
index d78b02c7f8e6a366ebc80aacf1be66a935eeec72..e4d00fd81104e9ae3f4530b93b6e1392a319d87e 100644
--- a/xtrn/dicewarz2/ai.js
+++ b/xtrn/dicewarz2/ai.js
@@ -213,10 +213,9 @@ function main()
 			updateStatus(map);
 			nextTurn(map);
 		}
-		game_data.save(map);
-		mswait(1000);
+		game_data.saveData(map);
+		mswait(500);
 	}
-	stream.sendfile(getFileName(map.game_number));
 	mswait(5000);
 	stream.close();
 }
@@ -272,7 +271,7 @@ function attack()
 			var roll=random(6)+1;
 			d.roll(roll);
 		}
-		var data=new Packet("battle");
+		var data=new Packet(map,"battle");
 		data.a=a;
 		data.d=d;
 		stream.send(data);
@@ -287,8 +286,6 @@ function attack()
 		} 
 		attacking.dice=1;
 		
-		game_data.saveActivity(map,attacker + " attacked " + defender + ": " + attacking.dice + " vs " + defending.dice);
-		game_data.saveActivity(map,attacker + ": " + a.total + " " + defender + ": " + d.total);
 		game_data.saveTile(map,attacking);
 		game_data.saveTile(map,defending);
 		computer.AI.moves++;
@@ -308,7 +305,7 @@ function forfeit()
 {
 	map.in_progress=false;
 	map.players[map.turn].active=false;
-	var data=new Packet("activity");
+	var data=new Packet(map,"activity");
 	data.activity=("\1n\1y" + map.players[map.turn].name + " forfeits");
 	stream.send(data);
 	players.scoreLoss(map.players[map.turn].name);
@@ -323,7 +320,7 @@ function reinforce()
 		total+=placed[p];
 	}
 	var reserved=placeReserves(map,reinforcements-total);
-	var data=new Packet("activity");
+	var data=new Packet(map,"activity");
 	if(total>0) {
 		data.activity=("\1n\1y" + map.players[map.turn].name + " placed " + total + " dice");
 		stream.send(data);
diff --git a/xtrn/dicewarz2/dice2.js b/xtrn/dicewarz2/dice2.js
index 0ab2f633dccba1ef56946a26809327a8302a73d5..dd964f585b708b779b257f00044cd4d33cec7ea9 100644
--- a/xtrn/dicewarz2/dice2.js
+++ b/xtrn/dicewarz2/dice2.js
@@ -449,7 +449,7 @@ function run(map)
 	function forfeit()
 	{
 		map.players[map.turn].active=false;
-		var data=new Packet("activity");
+		var data=new Packet(map,"activity");
 		data.activity=("\1n\1y" + map.players[map.turn].name + " forfeits");
 		stream.send(data);
 		players.scoreLoss(map.players[map.turn].name);
@@ -460,7 +460,12 @@ function run(map)
 		nextTurn(map);
 		updateStatus(map);
 		taking_turn=false;
-		game_data.saveData(map);
+		var data=new Packet(map,"map");
+		data.in_progress=map.in_progress;
+		data.winner=map.winner;
+		data.round=map.round;
+		stream.send(data);
+		
 		listPlayers();
 		if(map.winner) {
 			activityAlert("\1rGame ended");
@@ -468,7 +473,6 @@ function run(map)
 			return;
 		}
 		if(map.players[map.turn].AI) {
-			game_data.save(map);
 			load(true,game_dir + "ai.js",map.game_number,game_dir);
 		}
 	}
@@ -547,7 +551,7 @@ function run(map)
 		showRoll(d.rolls,BLACK+BG_LIGHTGRAY,chat.chat_room.x,chat.chat_room.y+3);
 		chat.chat_room.draw();
 		battle(a,d);
-		var data=new Packet("battle");
+		var data=new Packet(map,"battle");
 		data.a=a;
 		data.d=d;
 		stream.send(data);
@@ -565,11 +569,11 @@ function run(map)
 		attacking.dice=1;
 		drawSector(map,attacking.home.x,attacking.home.y);
 		
-		game_data.saveActivity(map,attacker + " attacked " + defender + ": " + attacking.dice + " vs " + defending.dice);
-		game_data.saveActivity(map,attacker + ": " + a.total + " " + defender + ": " + d.total);
-		game_data.saveTile(map,attacking);
-		game_data.saveTile(map,defending);
-		
+		var data=new Packet(map,"tile");
+		data.tile=attacking;
+		stream.send(data);
+		data.tile=defending;
+		stream.send(data);
 		return coords;
 	}
 	function battle(a,d) 
diff --git a/xtrn/dicewarz2/handler.js b/xtrn/dicewarz2/handler.js
new file mode 100644
index 0000000000000000000000000000000000000000..5684590b6167b2931a8a4cf159ef5c3bfa0f0edd
--- /dev/null
+++ b/xtrn/dicewarz2/handler.js
@@ -0,0 +1,50 @@
+var player_file=this.dir + "players.ini";
+
+function handler(data)
+{
+	switch(data.type.toUpperCase()) {
+		case "TILE":
+			var file=new File(data.filename);
+			var tile=data.tile;
+			file.open('r+',true);
+			file.iniSetValue("t"+tile.id,"d",tile.dice);
+			file.iniSetValue("t"+tile.id,"o",tile.owner);
+			file.iniSetValue("t"+tile.id,"h",tile.home.x + "-" + tile.home.y);
+			var slist=[];
+			for(var c=0;c<tile.coords.length;c++)
+			{
+				var sector=tile.coords[c];
+				slist.push(sector.x+"-"+sector.y);
+			}
+			file.iniSetValue("t"+tile.id,"s",slist);
+			file.close();
+			break;
+		case "MAP":
+			break;
+		case "PLAYER":
+			var file=new File(data.filename);
+			var p=data.player;
+			var n=data.pnum;
+			file.open('r+',true);
+			file.iniSetValue("p"+n,"name",p.name);
+			file.iniSetValue("p"+n,"reserve",p.reserve);
+			file.iniSetValue("p"+n,"vote",p.vote);
+			file.iniSetValue("p"+n,"AI",p.AI?true:false);
+			file.close();
+			break;
+		case "TURN":
+			var file=new File(data.filename);
+			file.open('r+',true);
+			file.iniSetValue(null,"turn",data.turn);
+			file.close();
+			break;
+		case "SCORE":
+			var score=data.score;
+			if(!player_file.is_open) {
+				player_file.open(file_exists(player_file.name)?'r+':'w+');
+			}
+			player_file.iniSetObject(score.name,score);
+			player_file.close();
+			break;
+	}
+}
\ No newline at end of file
diff --git a/xtrn/dicewarz2/maps.js b/xtrn/dicewarz2/maps.js
index dcfeae2b4bf3ce536d53d4ec3229059cdb1d4403..86eba5e3271b0c2959101cea5fc95e164d41f444 100644
--- a/xtrn/dicewarz2/maps.js
+++ b/xtrn/dicewarz2/maps.js
@@ -33,6 +33,7 @@ function MapData(game_number)
 	this.single_player=false;
 	this.winner=false;
 	this.game_number=game_number?game_number:getNewGameNumber();
+	this.filename=getFileName(this.game_number);
 	this.last_update=time();
 }
 function Tile(id)
@@ -161,8 +162,7 @@ function GameData(filemask)
 	}
 	this.openGameFile=function(map) 
 	{
-		var filename=getFileName(map.game_number);
-		var file=new File(filename);
+		var file=new File(map.filename);
 		if(!file.is_open) file.open((file_exists(file.name) ? 'r+':'w+'),true); 
 		return file;
 	}
@@ -171,6 +171,10 @@ function GameData(filemask)
 	}
 	this.savePlayer=function(map,p,n)
 	{
+		var data=new Packet(map,"player");
+		data.player=p;
+		data.pnum=n;
+		stream.send(data);
 		var file=this.openGameFile(map);
 		file.iniSetValue("p"+n,"name",p.name);
 		file.iniSetValue("p"+n,"reserve",p.reserve);
@@ -191,6 +195,9 @@ function GameData(filemask)
 	}
 	this.saveTile=function(map,tile)
 	{
+		var data=new Packet(map,"tile");
+		data.tile=tile;
+		stream.send(data);
 		var file=this.openGameFile(map);
 		file.iniSetValue("t"+tile.id,"d",tile.dice);
 		file.iniSetValue("t"+tile.id,"o",tile.owner);
@@ -203,10 +210,6 @@ function GameData(filemask)
 		}
 		file.iniSetValue("t"+tile.id,"s",slist);
 		this.closeGameFile(file,map);
-		
-		var data=new Packet("tile");
-		data.tile=tile;
-		stream.send(data);
 	}
 	this.update=function()
 	{
@@ -228,9 +231,10 @@ function GameData(filemask)
 	}
 	this.init();
 }
-function Packet(type)
+function Packet(map,type)
 {
 	this.type=type;
+	this.filename=map.filename;
 }
 
 	//GAME DATA FUNCTIONS
@@ -798,12 +802,11 @@ function Packet(type)
 				map.players[map.turn].reserve--;
 				if(!placed[tile.id]) placed[tile.id]=0;
 				placed[tile.id]++;
-				game_data.saveTile(map,tile);
 			} else {
 				pt.splice(rand,1);
 			}
 		}
-		for(var p in placed) {
+		for(p in placed) {
 			game_data.saveTile(map,map.tiles[p]);
 		}
 		return placed;
@@ -820,6 +823,9 @@ function Packet(type)
 			}
 			game_data.savePlayer(map,map.players[map.turn],map.turn);
 		}
+		for(p in placed) {
+			game_data.saveTile(map,map.tiles[p]);
+		}
 		return placed;
 	}
 	function nextTurn(map)
@@ -832,7 +838,7 @@ function Packet(type)
 			nextTurn(map);
 		}
 		else {
-			var data=new Packet("turn");
+			var data=new Packet(map,"turn");
 			data.turn=map.turn;
 			stream.send(data);
 		}
diff --git a/xtrn/dicewarz2/player.js b/xtrn/dicewarz2/player.js
index 22a938092b906d346aec7c67d14a6183746a970e..ccf01fd0782945659ef600c37f4f2e0d0a7e8d53 100644
--- a/xtrn/dicewarz2/player.js
+++ b/xtrn/dicewarz2/player.js
@@ -83,6 +83,9 @@ function PlayerData(filename)
 		}
 		this.file.iniSetObject(score.name,score);
 		this.file.close();
+		var data=new Packet(map,"score");
+		data.score=score;
+		stream.send(data);
 	}
 	this.scoreKill=function(name)
 	{