Archive

Archive for October, 2009

The battle logs|Die Kampflogs

October 28th, 2009 16 comments

I stated sometimes that the there are logs of all battles that have been fought and that the players could analyse them themselves if they know how to use javascript.

So what this blogpost is about is: Explaining the battle logs so that you can (maybe) build your own statistics tool. If you are not a programming nerd, you probably can skip this post as boring and useless for your gameplay, but if you are one, you’ll most likely find this interesting unless you haven’t figured this stuff already out yourself. So here we go.

Ich habe irgendwann mal geäußert, dass es für alle ausgetragenen Kämpfe Logs gibt und dass die Spieler sie analysieren könnten, wenn sie sich mit Javascript auskennen.

Dieses Posting beschäftigt sich also damit, die Kampflogs zu erklären, so dass ihr (vielleicht) euer eigenes Statistik-Tool basteln könnt. Wenn du kein Programmier-Nerd bist, kannst du dieses Posting getrost als langweilig und uninteressant für das Gameplay überspringen, aber falls du einer sein solltest, wirst du es vermutlich interessant finden, falls ihr das nicht schon selbst herausgefunden habt. Allerdings werde ich den folgenden Kram nicht weiter übersetzen, da es eigentlich nur Leute interessieren dürfte, die sich mit Programmiersprachen beschäftigen und aus diesem Grund vermutlich eh Englisch beherrschen.

Zur Englischen Sprache wechseln.

The data format

If a battle is opened on the cemetary (you know, on the forts), all the required data is transferred. It contains really everything. For example, this is a battle of only 2 players being involved:

{
	"attackerlist":[
		{"westid":60,"name":"foo124663470921","flagholdcount":1,"hitcount":2,
		"totalcauseddamage":131,"takendamage":260,"takenhits":4,"killedby":1,
		"finishedhp":0,"starthp":260,"maxhp":260,"townid":3,"townname":"cccc",
		"weaponid":100,"weaponname":"Stein","weaponmindmg":50,"weaponmaxdmg":110,
		"posidx":356,"diedwhen":0,"targetidx":356}
		],
	"defenderlist":[
		{"westid":1,"name":"testxx","flagholdcount":0,"hitcount":4,
		"totalcauseddamage":260,"takendamage":131,"takenhits":2,"killedby":-1,
		"finishedhp":1389,"starthp":1520,"maxhp":1520,"townid":5,
		"townname":"attackers of doommmm","weaponid":100,"weaponname":"Stein",
		"weaponmindmg":50,"weaponmaxdmg":110,"posidx":396,"diedwhen":8,"targetidx":396}
	],
	"log":[0,2, 1,1, 2,396, 3,1520, 4,1, 1,60, 2,356, 3,260, 4,0, 8,594, 0,3, 1,1, 2,396, 3,1520,
		4,1, 5,60, 7,62, 1,60, 2,356, 3,198, 4,0, 5,1, 7,67, 8,560, 0,4, 1,1, 2,396, 3,1453, 4,1,
		5,60, 7,62, 1,60, 2,356, 3,136, 4,0, 5,1, 8,492, 0,5, 1,1, 2,396, 3,1453, 4,1, 5,60, 1,60,
		2,356, 3,136, 4,0, 5,1, 8,424, 0,6, 1,1, 2,396, 3,1453, 4,1, 5,60, 1,60, 2,356, 3,136, 4,0,
		5,1, 7,64, 8,390, 0,7, 1,1, 2,396, 3,1389, 4,1, 5,60, 7,85, 1,60, 2,356, 3,51, 4,0, 5,1,
		8,356, 0,8, 1,1, 2,396, 3,1389, 4,1, 5,60, 6,51],
	"map":{
		"tiles":[[3,5,2,1,11,9],[8,4,1,2,18,7],[6,6,3,1,11,15],[0,11,3,4,11,11],[3,11,3,4,21,6],
			[6,11,3,4,21,11],[20,0,4,3,10,6],[128,0,2,2,16,9],[0,0,4,4,6,2],[8,0,5,4,24,2],[8,6,5,5,24,14],
			[0,6,4,5,6,14],[1,4,2,2,7,6],[1,4,2,2,7,8],[1,4,2,2,7,10],[1,4,2,2,7,12],[1,4,2,2,26,6],
			[1,4,2,2,26,8],[1,4,2,2,26,10],[1,4,2,2,26,12],[4,1,4,2,10,3],[4,1,4,2,14,3],[4,1,4,2,18,3],
			[4,1,2,2,22,3],[4,1,4,2,10,16],[4,1,2,2,14,16],[4,1,2,2,18,16],[4,1,4,2,20,16],[5,8,2,2,16,16]],
		"cells":[0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,4,0,0,0,0,1,1,1,1,1,1,1,
			1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,4,0,0,0,0,1,1,5,5,5,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,
			6,6,6,3,3,4,4,4,4,0,0,0,0,1,1,5,5,5,7,7,7,7,7,8,8,8,8,8,8,9,9,9,9,9,6,6,6,3,3,4,4,4,4,0,0,0,0,1,
			1,5,5,5,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,6,6,6,3,3,4,4,4,4,0,0,0,0,15,15,15,16,10,
			10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,17,18,18,18,4,4,4,4,0,0,0,0,15,15,15,16,10,10,
			19,19,19,11,11,20,20,20,20,13,13,21,21,14,14,14,17,18,18,18,4,4,4,4,0,0,0,0,15,15,15,16,22,22,19,
			19,19,23,23,20,20,20,20,24,24,21,21,25,25,25,17,18,18,18,4,4,4,4,26,26,26,26,15,15,15,16,22,22,22,
			27,27,23,23,28,28,29,29,24,24,21,21,25,25,25,17,18,18,18,30,30,30,30,26,26,26,26,15,15,15,16,22,
			22,22,27,27,23,23,28,31,31,29,24,24,32,32,25,25,25,17,18,18,18,30,30,30,30,26,26,26,26,33,33,33,
			34,35,35,35,27,27,36,36,37,31,31,38,39,39,32,32,40,40,40,41,42,42,42,30,30,30,30,26,26,26,26,33,
			33,33,34,35,35,35,43,43,36,36,37,37,38,38,39,39,44,44,40,40,40,41,42,42,42,30,30,30,30,26,26,26,
			26,33,33,33,34,35,35,35,43,43,36,36,45,45,45,45,39,39,44,44,40,40,40,41,42,42,42,30,30,30,30,26,
			26,26,26,33,33,33,34,46,46,46,43,43,47,47,45,45,45,45,48,48,44,44,49,49,49,41,42,42,42,30,30,30,
			30,26,26,26,26,33,33,33,34,46,46,46,47,47,47,47,50,50,50,50,48,48,48,48,49,49,49,41,42,42,42,30,
			30,30,30,26,26,26,26,51,51,52,52,52,46,46,47,47,47,47,50,50,50,50,48,48,48,48,49,49,53,53,53,54,
			54,30,30,30,30,26,26,26,26,51,51,52,52,52,55,55,55,55,55,55,55,56,56,57,57,57,57,57,57,57,53,53,
			53,54,54,30,30,30,30,58,58,58,58,51,51,52,52,52,51,51,59,59,59,59,59,59,60,60,60,60,60,60,54,54,
			53,53,53,54,54,61,61,61,61,58,58,58,58,51,51,51,51,51,51,51,59,59,59,59,59,59,60,60,60,60,60,60,
			54,54,54,54,54,54,54,61,61,61,61,58,58,58,58,51,51,51,51,51,51,51,59,59,59,59,59,59,60,60,60,60,
			60,60,54,54,54,54,54,54,54,61,61,61,61,58,58,58,58,62,62,62,62,62,62,62,62,62,63,63,63,63,63,63,
			63,63,64,64,64,64,64,64,64,64,64,61,61,61,61,58,58,58,58,62,62,62,62,62,62,62,62,62,63,63,63,63,
			63,63,63,63,64,64,64,64,64,64,64,64,64,61,61,61,61,58,58,58,58,62,62,62,62,62,62,62,62,62,63,63,
			63,63,63,63,63,63,64,64,64,64,64,64,64,64,64,61,61,61,61,58,58,58,58,62,62,62,62,62,62,62,62,62,
			63,63,63,63,63,63,63,63,64,64,64,64,64,64,64,64,64,61,61,61,61],
		"height":24,
		"sectors":[{"height":0,"attackerSpawn":true},
			{"height":0},{"height":0},{"height":0},{"height":0,"attackerSpawn":true},
			{"height":6,"attackerBonus":6,"defenderSpawn":true,"defenderBonus":7},
			{"height":6,"attackerBonus":6,"defenderSpawn":true,"defenderBonus":7},
			{"height":4,"attackerBonus":3,"defenderSpawn":true,"defenderBonus":4},
			{"height":4,"defenderSpawn":true},{"height":4,"attackerBonus":3,"defenderSpawn":true,"defenderBonus":4},
			{"height":0,"defenderSpawn":true},{"height":0,"defenderSpawn":true},{"height":0,"defenderSpawn":true},
			{"height":0,"defenderSpawn":true},{"height":0,"defenderSpawn":true},{"height":0},
			{"height":4,"attackerBonus":3,"defenderSpawn":true,"defenderBonus":4},
			{"height":4,"attackerBonus":3,"defenderSpawn":true,"defenderBonus":4},
			{"height":0},{"height":3,"attackerBonus":1.25,"defenderSpawn":true,"defenderBonus":1.25},
			{"height":0,"defenderSpawn":true},{"height":3,"attackerBonus":1.25,"defenderSpawn":true,"defenderBonus":1.25},
			{"height":0,"defenderSpawn":true},{"height":0,"defenderSpawn":true},{"height":0,"defenderSpawn":true},
			{"height":0,"defenderSpawn":true},{"height":0,"attackerSpawn":true},{"height":0,"defenderSpawn":true},
			{"height":0,"attackerBonus":-5,"defenderSpawn":true,"defenderBonus":-5},
			{"height":0,"attackerBonus":-5,"defenderSpawn":true,"defenderBonus":-5},
			{"height":0,"attackerSpawn":true},{"flag":true,"height":0,"attackerBonus":-10,"defenderSpawn":true,"defenderBonus":-10},
			{"height":0,"defenderSpawn":true},{"height":0},{"height":4,"defenderSpawn":true},{"height":0,"defenderSpawn":true},
			{"height":0,"defenderSpawn":true},{"height":0,"attackerBonus":-5,"defenderSpawn":true,"defenderBonus":-5},
			{"height":0,"attackerBonus":-5,"defenderSpawn":true,"defenderBonus":-5},{"height":0,"defenderSpawn":true},
			{"height":0,"defenderSpawn":true},{"height":4,"defenderSpawn":true},{"height":0},
			{"height":3,"attackerBonus":1.25,"defenderSpawn":true,"defenderBonus":1.25},
			{"height":3,"attackerBonus":1.25,"defenderSpawn":true,"defenderBonus":1.25},
			{"height":0,"defenderSpawn":true},{"height":0,"defenderSpawn":true},
			{"height":0,"defenderSpawn":true},{"height":0,"defenderSpawn":true},
			{"height":0,"defenderSpawn":true},{"height":0,"defenderSpawn":true},
			{"height":0},{"height":6,"attackerBonus":6,"defenderSpawn":true,"defenderBonus":7},
			{"height":6,"attackerBonus":6,"defenderSpawn":true,"defenderBonus":7},{"height":0},
			{"height":4,"attackerBonus":3,"defenderSpawn":true,"defenderBonus":4},
			{"height":0,"attackerBonus":3,"defenderSpawn":true,"defenderBonus":4},
			{"height":4,"attackerBonus":3,"defenderSpawn":true,"defenderBonus":4},
			{"height":0,"attackerSpawn":true},{"height":0},{"height":0},{"height":0,"attackerSpawn":true},
			{"height":0,"attackerSpawn":true},{"height":0,"attackerSpawn":true},{"height":0,"attackerSpawn":true}],
		"mapname":"Test",
		"width":34},
	"logtypes":["ROUNDSTART","CHARTURN","CHARTARGET","CHARHEALTH","CHARONLINE","SHOOTAT","KILLED","HIT","MOVED"],
	"roundsplayed":8,"maxrounds":50,"battleid":81,"outcome":"ATTACKER_WIPED","fortname":"abcfort",
	"declarerid":6,"declarername":"foo12464580102","attackertownid":3,"defendertownid":5,"defendertownname":"attackers of doommmm",
	"attackertownname":"cccc"}

That’s quite a chunk, so let’s rip it apart and look at it one by one.

Attacker- and Defenderlist

Both arrays contain identical descriptions of all the involved players. Each player has following descriptions:

  • westid: the id of the player in this world. Identical to the id used in ranking etc.
  • name: the name of the player
  • flagholdcount: number of rounds that the player was holding the flag
  • hitcount: number of hits the player made
  • totalcauseddamage: the total amount of damage caused by this player
  • takendamage: how much damage the player got
  • takenhits: how often the player was hit
  • killedby: a player id (westid) of the player who knocked the player out
  • finishedhp: how much hitpoints that have been left at the end of the battle
  • starthp: hitpoints on start of the battle
  • maxhp: the maximum amount of hitpoints the player may have
  • townid: the id of the town the player belonged to
  • townname: the name of that town at the moment when the battle started
  • weaponid: the id of the used weapon
  • weaponmaxdmg: the maximum damage the weapon can cause
  • weaponmindmg: the minimum damage that the weapon is causing
  • posidx: The starting position of the player
  • diedwhen: The round the player was knocked out (bugged, fixed with 1.23)
  • targetidx: The target of the player when the game started

A lot of data is already supplied in these arrays, but there’s far more.

The log

Each battleresult contains a complete log of the whole battle. This is most likely the most interesting thing for you, as this contains a lot of data (as a side note, this data might be bugged as it has never been used yet anywhere). A part of the log looks like this:

"log":[0,2, 1,1, 2,396,(...)

I inserted whitespaces at each second comma, because each pair of numbers describes what happened. The first number tells us what operation this was, the second number describes the operation. The mere numbers are useless unless we know the codes for the numbers. The codes are supplied with the log. The values are represented in an array called “logtypes”:

"logtypes":["ROUNDSTART","CHARTURN","CHARTARGET","CHARHEALTH","CHARONLINE","SHOOTAT","KILLED","HIT","MOVED"]

The array tells us that 0 means “ROUNDSTART”, 1 means “CHARTURN” and so on. The order can change anytime when we change some implementations on our sides, so in case of developing a tool in javascript, I would suggest to figure out the right numbers before analyzing the log.
This codebook tells us now following information:
“logtypes”:

"log":[ROUNDSTART,2, CHARTURN,1, CHARTARGET,396, CHARHEALTH,1520, CHARONLINE,1,
CHARTURN,60, CHARTARGET,356, CHARHEALTH,260, CHARONLINE,0, MOVED,594,
ROUNDSTART,3, ...

So this is more meaningful now and with a bit of description, this is the log, encoded in these number pairs:

  1. ROUNDSTART,2: The game begins with round 2 (1 is the first round where everyone is choosing their starting position and target position.
  2. CHARTURN,1: The character with west id 1 is now active
  3. CHARTARGET,396: The character 1 is trying to go to the cell 396 (which is his starting position, so we’re there already)
  4. CHARHEALTH,1520: The character 1 has a health of 1520 hitpoints
  5. CHARONLINE,1: The player for character 1 was online during this round
  6. CHARTURN,60: It is now the turn of player with id 60
  7. CHARTARGET,356: The character 60 wants to go to cell 356
  8. CHARHEALTH,260: The character 60 has 260 hitpoints
  9. CHARONLINE,0: The player of character 60 was not online
  10. MOVED,594: Character 60 moves to cell 594
  11. ROUNDSTART,3: Round 2 has ended, round 3 begins

This pattern repeats all over the place and we can reconstruct the whole battle for each player. We do even know who was online and who was not online! The keys “SHOOTAT”,”KILLED” and “HIT” describe further actions:

  • SHOOTAT: the id of the player that this character is shooting at
  • KILLED: if the shot was knocking the player out, this key is used. The value represents the damage that was caused the player to be knocked out. Can be larger than the player’s hitpoints
  • HIT: if the shot was a hit, the damage is described with the value

If no hit was made, the SHOOTAT value exists but without a following HIT / KILLED actions.

The map description

The map description is also supplied here. It could be used for replaying the whole map visually. The first thing to know is how a x,y coordinate is represented in the map – since we know the width and height of the map, we can recalculate a pair of numbers to a single number and back with this small function:

// javascript code
function toxy(idx,mapwidth) {
	return {x:idx%mapwidth,y:Math.floor(idx/mapwidth)};
}
function toidx(x,y,mapwidth) {
	return x+y*mapwidth;
}

Both functions can be used to do the required calculations. The width and height of the map is supplied by the map description as well with the keys “width” and “height”.
Furthermore, we have various arrays now: “tiles”, “cells” and “sectors”. The “mapname” parameter is currently not really used, it still has the name “test” on the productive worlds, something that I didn’t know about yet – as it’s nowhere used right now.

The tiles

The tiles are simple arrays of arrays containing each 6 numbers, describing the visual layout with out tileobject:

  1. The x coordinate on the tile texture
  2. The y coordinate on the tile texture
  3. The x size of the tile
  4. The y size of the tile
  5. The x coordinate on the map where the tile is being drawn (left side of the tile)
  6. The y coordinate on the map where the tile is being drawn (top side of the tile)
    • height: The height of this sector
    • attackerbonus / defenderbonus: What bonus the sector provides
    • defenderspawn / attackerspawn: A boolean value that tells us if players can spawn here
    • flag: True if this is a flag sector

This information allows us to draw the hole map using the tile texture. It contains only eyecandy information – nothing else.

The sectors

That array describes the attributes of each sector that is present on the map. Following attributes are available:

There will be further values if there’s a bonus for a certain playerclass, but I think that the whole sector description is pretty self explanatory.

The cells

The most important description for the game is the layout of the sectors. The sectors can have any kind of form, so what we do is, we define for each cell on the map what sector it belongs – it refers here to an index in the sector array. The array called “cells” describes now for each cell, starting from top left the sector for each cell, left to right, top to bottom (just like reading letters in a book). For example:

"cells":[0,0,0,0,1,1,1,1,1,1,1,1,1,2 ...

What we see here is, that the cell located at x=0 and y=0 is described with the attributes given by the sector description at index 0 of the sector array. The same attributes are used for x=1,y=0 and x=2,y=0 and x=3,y=0. The next sector starts at x=4,y=0. Every cell that refers to the same sector id belongs to the same sector (of course…). From the game logic we know that if a sector is taken by a team, the other team can’t enter that sector. So in theory, there could be sectors that are disjunct – which means that a sector could be split. However, this should not be the case.

That’s it!

So that’s everything that is needed to know if you really want to analyze the logs of a battle yourself. How can you get now the data? Well, there are several ways – for example taking the text from the ajax call using firebug. Or by overwriting the FortBattle.makeStats function:

javascript:(function() {
  var orig = FortBattle.makeStats;
  FortBattle.makeStats = function (data,element,fortx,forty,bool) {
    alert(Json.toString(data));
    return orig(data,element,fortx,forty,bool);
  }
})(); void(0);

If you execute this code in your browser’s address bar, you’ll get an alert message the next time when you look at a fort battle result. Copy & paste the result and you’ll have the data anywhere you want it to have.

Categories: Uncategorized Tags:

Back from Japan!|Zurück aus Japan!

October 16th, 2009 11 comments

japanSo, I am back from Vacation – I’ve been to Japan and enjoyed it very much over there. Anyway, now I am back and getting into work again.

First: The chat is being delayed. The reason for this are technical reasons on the serverside. It’s unlikely that it becomes a feature of 1.23.

Zunächst: Der Chat verzögert sich. Der Grund sind technische Probleme auf dem Server. Es ist eher unwahrscheinlich, dass wir das bis 1.23 hinbekommen.
Was ist für 1.23 stattdessen geplant?

So what’s on the agenda for 1.23 then?

  • Stabilization: Certain features need smaller or larger improvements that are going to be done in 1.23.
  • Small user interface & graphical improvements: A larger map, a bit more comfort in the game internal forums a new ranking
  • Custom fort battle maps
  • New rewards
  • Stabilisierung: Einige Features brauchen kleinere oder größere Verbesserungen, das wird in 1.23 umgesetzt.
  • Kleinere Verbesserungen in der Oberfläche und grafische Veränderungen: größere Karte, mehr Komfort in den internen Foren, neues Ranking
  • Individuelle Fortkampfkarten
  • Neue Rewards

The custom fort battle maps are the most complex feature here. For the resizable map, it’s a bit easier but should help players to get a more comfortable overview on the game map, as it can be seen in this screenshot:

Die individuellen Fortkampfkarten sind dabei das komplexeste Feature. Die vergrößerte Karte ist etwas einfacher, hilft den Spielern aber, einen besseren Überblick auf der Kartenansicht zu bekommen, wie in diesem Screenhot ersichtlich:

A map that fits into the browser's screen

A map that fits into the browser’s screen

Eine Karte, die sich an die Größe des Browserfensters anpasst.

For the custom battle maps, it’s far more complex. First we have 3 different fort sizes, then we have a vast amount of different building level configurations. In order to provide as much diversity as possible, each building will be represented in the battle map dependent on its level when the battle starts (don’t ask me what happens if to positioned players in case of a tower level up – I don’t know yet). But in order to achieve this, we must create a description of all this somehow and this can not be done using a mere text editor – we need a tool for this. And I have started working on just that. In theory, once we have the tool ready and created all the data that is required for creating custom battle maps for each fight, the deployment is of important question – how will it be deployed to players and representation. Of course, most of this has already been foreseen and most stuff should work right away from the start, but of course, all that and the testing will require quite some time. But we’ll see how it goes on and how long it’ll take.

Wie gesagt, die individuellen Fortkampfkarten sind viel komplexer. Zunächst haben wir drei verschiedene Fortgrößen, dann gibt es noch jede Menge verschiedene Möglichkeiten für die Gebäudelevel.
Um soviel Abwechslung wie möglich zu schaffen, wird jedes Gebäude auf der Kampfkarte in Abhängigkeit von seinem Level dargestellt, wenn der Kampf beginnt (fragt mich nicht, was mit Spielern passiert, die sich bei einem Turm-Level-Up dort befinden – das weiss ich noch nicht).
Um das zu erreichen, müssen wir eine Beschreibung von alldem erschaffen und das kann leider nicht in einem normalen Text-Editor geschehen, wir brauchen ein Tool dafür. Ich habe gerade angefangen, daran zu arbeiten.

Theoretisch ist die Frage nach der Umsetzung sehr wichtig, nachdem das Tool bereit ist und alle Daten, die für die Erzeugung von individuellen Fortkampfkarten für jeden Kampf benötigt werden, erzeugt wurden – wie werden sie in das Spiel integriert? Natürlich wurde das meiste davon schon vorher geplant und das meiste soltle gleich von Anfang an funktionieren, aber selbstverständlich wird das (und das Testen) auch einige Zeit benötigen. Wir werden sehen, wie das alles läuft und wie lange es dauern wird.

Categories: Uncategorized Tags:

First leaked picture from 1.23

October 8th, 2009 13 comments

Hey ho 😀

I currently don’t wanna talk too much about the 1.23 update so i currently just release some pictures showing some new interface designs (nope no new feature previews leaked yet)

new town profile with additional data

new town profile with additional data (click to raise)

new ranking interface (click to raise)

new ranking interface (click to raise)

Categories: Uncategorized Tags:

Premium for everyone

October 6th, 2009 4 comments

paI’ve take care of that the beta server has a fairer premium model that fits a beta testing server. it was admittedly too expensive for a pure testing and beta world. So I’ve now raised the gained nuggets by three, of course only for the public beta world, so please don’t cry 😀

Really sorry all other 🙂

Categories: Uncategorized Tags: