Jelenlegi hely

Cikkek

Megszavazta a nép: Ghost of a Tale betekintő

Fórum:

kép:https://i.imgur.com/iOXTsTn.png

A Ghost of a Tale egy igazi gyöngyszem. Az előzetes képek és videók alapján nagyon jónak tűnt az art design és a grafika, de nem gondoltam, hogy ennyire magával ragad majd. A játék Indiegogo kalapozással készült, és márciusban meg is jelent. Azóta már szépen foltozták is a nagyobb bugokat. A készítője az a Lionel Gallat, aki a Dreamworksnél animátorként vett részt például az Egyiptom hercege készítésében, a Universal Studiosnál pedig a Despicable Me című filmen dolgozott animation director pozícióban. Ez meg is látszik a játékon, a főhős mozgása nagyon természetesnek hat.

kép:http://www.ghostofatale.com/wp-content/uploads/2018/02/46.jpg

A sztoriról röviden annyit, hogy Tilót, a vándorzenész egeret alakítjuk, aki egy börtönben ébred, különválasztva a feleségétől, Merrától. A játék során őt kell megtalálni. A feladat adott, rá kell jönnünk hol tartják fogva Merrát, és meg kell szöknünk a börtönből.

kép:https://i.imgur.com/uyscj0t.png

Amikor sikerül kilógnunk, akkor derül ki, hogy nem csak egy egyszerű börtönben vagyunk, hanem egy hatalmas partmenti erődben, ahol sok tennivalónk akad. Az erőd és környéke ugyanis a Red Paw nevű patkányok alkotta katonai szervezet fennhatósága alatt áll, akik nem kedvelik a szökött egereket, kezdetben ők nehezítik meg a dolgunkat.

kép:http://www.ghostofatale.com/wp-content/uploads/2018/02/63.jpg

Tennivalónk bőven akad: fel kell kutatnunk NPC-ket, gyilkossági ügyben kell nyomoznunk, csempészhálózat lebuktatásában kell segédkeznünk, van egy rakás gyűjtenivaló stb. A játéktér nem kimondottan nagy, de egér mértékkel mérve hatalmas tud lenni. Ezt úgy kell elképzelni, hogy minden tárgy, a székek, asztalok, a kút stb. patkányméretű, ezzel szemben mi akkorák vagyunk mint egy 8 éves gyerek egy felnőtthöz képest. Talán pont ezért van olyan nosztalgikus hangulata a játéknak. Előhozza a gyerekkori kirándulások emlékét, amikor az erdők és a várak sokkal nagyobbnak tűntek, mint felnőttként.

Kalandozásaink során bejárhatjuk az említett erődöt, egy nagyobb erdős területet, lejutunk a partra és az erőd alatti csatorna illetve katakombahálózatba. Nagyon jól működik a területek, helyszínek megismerése, feltérképezése. Az elején, amikor még minden új, csak lassan szemlélődve osonunk, később, amikor már vágjuk, mi merre található az adott helyen, szélsebesen kotrunk végig az ismerős folyosókon, ösvényeken. Főleg akkor tehetünk így, ha felfedezzük a shortcutokat, amik segítségével mindjárt gyorsabb a közlekedés, amíg viszont ez nincs meg, sok a backtracking. A területek között van néhány, ami kicsit üresnek és befejezetlennek tűnik, ilyen például a kikötő: ahhoz képest, hogy milyen hatalmas, kevés dolgot tudunk ott csinálni.

kép:http://www.ghostofatale.com/wp-content/uploads/2018/02/Screen-Shot-02-15-18-at-10.34-AM-001.jpg

Amíg nincs megfelelő páncélunk, sokat kell bujkálni, erre vannak megfelelő tereptárgyak: ládák, szekrények stb. Lopakodás közben óvatosan elcsenhetünk kulcsokat, illetve bármit, amire szükségünk van, illetve rövid időre kiüthetjük az őröket üres üvegekkel, elterelhetjük a figyelmüket vagy csapdát állíthatunk nekik. Viszont amint megvan a patkánypáncélszett, már szemtelen kisegér módjára járkálhatunk köztük. Innentől megváltozik a felállás és szabadon járhatunk-kelhetünk, beszélhetünk velük és még küldetéseket is csinálhatunk nekik.

Mivel sokat mászkálunk sötét pincékben, éjjel az erdőben meg alig látni valamit, vihetünk magunkkal gyertyát ami persze elég hamar elfogy, de szerencsére használhatjuk az olajjal tölthető lámpásunkat is. Ezen kívül találhatunk egy olyan sapkát amin egy végtelen gyertya ég, ez viszont negatív hatással van a staminánkra, így ha azt használjuk, nem tudunk futni, ami a menekülésnél hátrány. Arra is van lehetőség (ha találunk ágyat), hogy aludjunk egyet: ez egy kicsit tölti az életünket, de ha úgy gondoljuk, alhatunk akár reggelig is, amikor már világosodik.
Harc igazából nincs a játékban, az említett ágak, üvegek, csiganyálas üvegcsék dobálásán kívül.

kép:http://www.ghostofatale.com/wp-content/uploads/2018/02/10.jpg

A karakterek általában elég emlékezetesek, a szövegeik jól megírtak, maga a sztori is végig érdekes tud lenni. A játék világa pedig annyira egyben van, hogy utánanéztem, nem adaptációja-e könyvnek esetleg mesének, és nem, ez egy teljesen önálló fantasy világ. Persze Gallat saját bevallása szerint sokat merített a The Secret of Nymh és a The Dark Crystal című filmekből, a Redwall-könyvekből, Alan Lee és John Howe rajzaiból, de hatással voltak rá olyan játékok is, mint a Legend of Zelda, a Dark Souls vagy éppen az ICO.

kép:http://www.ghostofatale.com/wp-content/uploads/2018/02/22.jpg

A hangok és a zenék is remekül sikerültek. Mind a dalok, mind az egyes helyszínek témái nagyon rendben vannak, árad belőlük a hangulat. A játék során többször előfordul, hogy vándorénekes lévén elő kell adnunk valamit egy beszélgetés során. Ilyenkor a megfelelő dalt kell kiválasztanunk a daloskönyvünkből és azt Tilo szépen előadja, szerencsére nem QTE formájában.

Ghost of a Tale - Bard's Song - Heaven in a Bottle
Inditás gomb

Ghost of a Tale - Bard's Song - Heaven in a Bottle (00:00:39)

Míg minden mással nagyon elégedett voltam, egyedül a végjáték az, amit kissé sutának és összecsapottnak éreztem, ez az egyetlen, ami valamennyire kizökkentheti az embert az idillből.

Mindent összevetve egy remek kaland volt a Ghost of a Tale. Mi kb 20 óra alatt jutottunk a végére, szerintem ma ez egy nagyon ideális játékhossz. Remélem, anyagilag sikeres lesz a játék és tovább folytatódik Tilo szívet melengető története.

Ghost of a Tale - Final ReleaseTrailer
Inditás gomb

Ghost of a Tale - Final ReleaseTrailer (00:02:22)

Az eredeti komment hivatkozasa: http://www.rewired.hu/comment/164383#comment-164383

Neural Networks III: How would I implement one?

Fórum:

Címkék:

kép:https://i.imgur.com/FC1QvBY.jpg

In the third article in the series, I am attempting to keep everything fairly detailed and explain everything I do, as I dive deeply into actual implementation of the Feed-Forward Neural Network. To make the implementation process easier to comprehend, the article is divided into 5 sub-segments:

- Making a simple, Feed-Forward Neural Network structure
- Fixing the Neural Network’s bias/weight initial values
- Adding a learning algorithm to the Neural Network
- Multiple Input and Output Sets for our Neural Network
- Training for handwriting recognition with MNIST data set

Let’s jump right in!

I will use Java in this case, but any other programming language will follow the exact same route of ideas. I’m not going to use any exotic language specific solution, but will try to keep everything as generic as possible.

Making a simple, Feed-Forward Neural Network structure:

The structure of our entire Neural Network supposed to be very simple, as the theoretical example was in the previous article. I presume the entire codebase should cap around 150-200 lines of code, plus the helper utility classes.

First, let’s create a Network.java class, which represent our NN object.

We would need a few integer constant attributes here, which defines our network and doesn’t need to change over the program’s lifetime.

NETWORK_LAYER_SIZES” Contains the number or neurons in each of our layer.

NETWORK_SIZE” Contains the number of layers over our NN. We set this number to be associated from the NETWORK_LAYER_SIZES array’s length.

INPUT_SIZE” Contains the number of input neurons. Input layer is the first in the network, so the first number in the NETWORK_LAYER_SIZES will represent this variable.

OUTPUT_SIZE” Contains the number of output neurons in our NN. Output is the last layer, so it is represented by the last index in the NETWORK_LAYER_SIZES array.

Now we will declare a couple of variables to work with:

output” Contains the calculated output value of every neuron over our entire network. This value needs to be as precise as possible to give us accurate results, so we use Double as a datatype. Using a two dimensional array here is sufficient enough to store the given layer, and the given neuron positions as well.

weights” Stores all the weight data over the network. Note that this needs to be a three dimensional array to store all the necessary positions. The first value would be the given layer, the second is the given neuron, and the third is the previous neuron the weight is connected to. We need this previous neuron data because as we have learned in the previous article, a single neuron on the given layer is connected to all of the previous ones at the adjacent previous layer.

bias” Is a two dimensional array, similar as the output, because every neuron has one bias variable as well.

public class Network {
	public final int[] NETWORK_LAYER_SIZES;
	public final int NETWORK_SIZE;
	public final int INPUT_SIZE;
	public final int OUTPUT_SIZE;
 
	private double[][] output; //layer, neuron
	private double[][][] weights; //layer, neuron, previousNeuron 
	private double[][] bias; //layer, neuron
}

Our constructor will receive the NETWORK_LAYER_SIZES value from the initialization method, and all the rest of the constant and variable data can be calculated from it.

For initializing the output, weight and bias values, we assign the NETWORK_SIZE as the first dimension’s size. Also we need to iterate through a FOR loop to initialize all the rest of the elements over the second layer. Note that while every neuron has an output and a bias, the very first layer doesn’t have weights on it (being the input layer), so we start assigning weight values from the second layer in this loop.

public Network(int[] NETWORK_LAYER_SIZES) {
	this.NETWORK_LAYER_SIZES = NETWORK_LAYER_SIZES;
	this.NETWORK_SIZE = NETWORK_LAYER_SIZES.length;
	this.INPUT_SIZE = NETWORK_LAYER_SIZES[0];
	this.OUTPUT_SIZE = NETWORK_LAYER_SIZES[NETWORK_SIZE - 1];
 
	this.output = new double[NETWORK_SIZE][];
	this.weights = new double[NETWORK_SIZE][][];
	this.bias = new double[NETWORK_SIZE][];
 
	for (int i = 0; i < NETWORK_SIZE; i++) {
 
		this.output[i] = new double[NETWORK_LAYER_SIZES[i]];
		this.bias[i] = new double[NETWORK_LAYER_SIZES[i]];
 
		if (i > 0) {
			weights[i] = new double[NETWORK_LAYER_SIZES[i]][NETWORK_LAYER_SIZES[i - 1]];
		}
	}
}

We now have a basic initialization constructor, but we need to have a method that will calculate the FEED-FORWARDING values as well. Let’s call it “calculate”. This methods takes an array of doubles as an input parameter, and returns an array of doubles as an output.

public double[] calculate(double input[]) {
	if (input.length != this.INPUT_SIZE) {
		return null;
	}
 
	this.output[0] = input;
	for (int layer = 1; layer < NETWORK_SIZE; layer++) {
		for (int neuron = 0; neuron < NETWORK_LAYER_SIZES[layer]; neuron++) {
			double sum = bias[layer][neuron];
			for (int prevNeuron = 0; prevNeuron < NETWORK_LAYER_SIZES[layer - 1]; prevNeuron++) {
				sum += output[layer - 1][prevNeuron] * weights[layer][neuron][prevNeuron];
			}
			output[layer][neuron] = sigmoid(sum);
		}
	}
 
	return output[NETWORK_SIZE - 1];
}

The very first IF block check just makes sure that the input array’s size matches our network’s previously set INPUT_SIZE constant value. If it doesn’t we cannot do any calculations.
The next line just passes these input values to the output array’s first element, since it doesn’t need to do any calculations with it.
After that, we have a nested FOR loop that iterates through all the rest of the layers, while iterating through all the neurons as well in the given layer. Here, each of the neurons will apply the summarization with the bias, apply the weight multiplication over each of the previous neurons, iterating through yet another FOR loop. Finally we apply the sigmoid function to this summarized value.

The math for the sigmoid function can be represented by this in Java:

private static double sigmoid(double x) {
	return 1d / (1 + Math.exp( - x));
}

We can quickly make a Main method to test our current version of the network with some random values. Let’s instantiate our network and have the input and output layers contain 5-5 neurons, and have two hidden layers, containing 4 and 3 neurons. We can feed some random values as inputs like 0.2, 0.3, 0.1, 0.2, 0.5. Java has a good amount of integrated helper methods to make our life easier as a programmers, and the “Arrays.toString” can print out all the values on the given array in a nicely formatted, coma separated list.

public static void main(String[] args) {
	Network net = new Network(new int[]{5,4,3,5});
 
	double[] output = net.calculate(new double[]{0.2,0.3,0.1,0.2,0.5});
 
	System.out.println(Arrays.toString(output));
}

When we run this program, we notice an issue right away. No matter what input values are we entering, all five of the output values are always exactly 0.5. This occurs because all the weight and bias values are initialized as 0 instead of 1, which basically nullifies all of our calculated summary values, causing the sigmoid function to return us 0.5 every time as well.

Fixing the Neural Network’s bias/weight initial values:

We can change the weight/bias initialization lines at our constructor to start with 1, but I will go one step further and make those values randomized within a certain range. This will give us more flexible control over the network’s behavior right from the start.

I’m creating a helper class called “NetworkTools” to store all the array creating randomizer and related utility methods. These methods are going to become handy as we go on, and are very straight forward to understand. I’ve commented their functions at each of their header:

public class NetworkTools {
 
	//every value in this generated array will be the init_value
	public static double[] createArray(int size, double init_value) {
		if (size < 1) {
			return null;
		}
 
		double[] ar = new double[size];
		for (int i = 0; i < size; i++) {
			ar[i] = init_value;
		}
 
		return ar;
	}
 
	//every value in this generated 1 dimensional array will be random number, within a lower and upper bound
	public static double[] createRandomArray(int size, double lower_bound, double upper_bound) {
		if (size < 1) {
			return null;
		}
 
		double[] ar = new double[size];
		for (int i = 0; i < size; i++) {
			ar[i] = randomValue(lower_bound, upper_bound);
		}
		return ar;
	}
 
	//every value in this generated 2 dimensional array will be random number, within a lower and upper bound
	public static double[][] createRandomArray(int sizeX, int sizeY, double lower_bound, double upper_bound) {
		if (sizeX < 1 || sizeY < 1) {
			return null;
		}
 
		double[][] ar = new double[sizeX][sizeY];
		for (int i = 0; i < sizeX; i++) {
			ar[i] = createRandomArray(sizeY, lower_bound, upper_bound);
		}
 
		return ar;
	}
 
	//returns a random double within the desired lower and upper bound
	public static double randomValue(double lower_bound, double upper_bound) {
		return Math.random() * (upper_bound - lower_bound) + lower_bound;
	}
 
	//returns a specific amount of random unique (cannot appear more than once) integers, from the desired lower and upper bound 
	public static Integer[] randomValues(int lowerBound, int upperBound, int amount) {
 
		lowerBound--;
 
		if (amount > (upperBound - lowerBound)) {
			return null;
		}
 
		Integer[] values = new Integer[amount];
		for (int i = 0; i < amount; i++) {
			int n = (int)(Math.random() * (upperBound - lowerBound + 1) + lowerBound);
			while (containsValue(values, n)) {
				n = (int)(Math.random() * (upperBound - lowerBound + 1) + lowerBound);
			}
			values[i] = n;
		}
		return values;
	}
 
	//receives any datatype array as a first parameter, and checks if the provided second parameter value is contained in it
	public static < T extends Comparable < T >> boolean containsValue(T[] ar, T value) {
		for (int i = 0; i < ar.length; i++) {
			if (ar[i] != null) {
				if (value.compareTo(ar[i]) == 0) {
					return true;
				}
			}
 
		}
		return false;
	}
 
	//returns the highest value's index within the provided double array.
	public static int indexOfHighestValue(double[] values) {
		int index = 0;
		for (int i = 1; i < values.length; i++) {
			if (values[i] > values[index]) {
				index = i;
			}
		}
		return index;
	}
}

So going back to the Network constructor and changing the weight and bias initialization lines to produce some random values. These values absolutely doesn’t matter right now, they can be positive or negative also:

public Network(int[] NETWORK_LAYER_SIZES) {for (int i = 0; i < NETWORK_SIZE; i++) {this.bias[i] = NetworkTools.createRandomArray(NETWORK_LAYER_SIZES[i], -0.5, 0.7);
 
		if (i > 0) {
			weights[i] = NetworkTools.createRandomArray(NETWORK_LAYER_SIZES[i], NETWORK_LAYER_SIZES[i - 1], -1, 1);
		}
	}
}

Now every time we run the program and make one pass of feed-forwarding calculations, it will give us random output values, proving that the network works as intended. Without a learning algorithm however, the network is fairly useless in this state, so let’s tackle that issue as well.

Adding a learning algorithm to the Neural Network:

So for every given input value combination, we would need to have a “targeted” output value combination as well. With these values we can measure and compare how far or close the network is from the currently calculated output values. Let’s say the previously declared input values (0.2,0.3,0.1,0.2,0.5) we want the network to output ideally (1,0,0,0,0) instead of any other seemingly random numbers.

As explained in the previous article, this is where Backpropagation, our learning mechanism comes in and trying to predict each of the previous adjacent layers supposed weight and bias values, which would produce this final desired output. It will start from the last layer and try to predict what weight and bias combination could produce a value closer to the desired output results, once that is figured out, will jump to the previous adjacent layer and do these modification again and so on until it gets to the starting layer. We start from the last layer because those related weight and bias values have the greatest influence over the final output. Note that by the rules of the network, we can only change these bias and weight values if we want to influence these output values, we cannot change any other values directly.

These differences over the desired output and current output are called the “error signal”. Before making any changes to the weight/bias values, we finish the backpropagation completely and store this error signal from each layer (except the very first input layer).

Intuitively this seems like a very easy task to do. Just subtracting the targeted value from the current value, try nudging the weight/biases over some positive values and measure if we got closer or further from the desired output. If we got closer, then try adding more positive values until we reach the desired output, but if we got further away, start applying negative values instead and keep doing so. This would be exactly true for a simple input range, representing a straightforward curve:

kép:https://i.imgur.com/W77WOyG.png

But unfortunately, as we get more and more input values, the complexity of the whole Neural Network function gets significantly more complex as well, and predicting the exact “right” position and the path towards it becomes less and less obvious:

kép:https://i.imgur.com/3LgjejG.png

As you can see, having multiple local minimums can easily “fool” the algorithm, thinking that it goes the right way, but in reality it may just pursuit some local ones, which never going to produce the desired output. You can think of the algorithm as a “heavy ball” for weights. This ball will run down the slope where it started from, and stop at the bottom that it happen to find. Now for instance, if the initial weight value would be between 0 and 0.5 somewhere, and no matter where it would start to adjust, with a naïve “heavy ball” approach, it would slide down to be around ~0.65 and stop there, while we can clearly see that that would always produce a wrong result. This is the primary reason we use randomized values each time we start the training process, instead of setting them to 1, so every time there would be a new chance for these weights to propagate over the proper global minimum values.

Furthermore, to successful tackle this backpropagation, each neuron needs to have an “error signal” and an “output derivative” values, beside their regular output values. Our backpropagation error function, which calculates how close we are from the target output values looks like this:
E = ½ (target-output)^2.

I am not going to go into the details of all the related math in this article, because it’s a fairly large subject of its own. But for anyone interested, I can refer you to Ryan Harris over Youtube. He has excellent tutorial series for backpropagation algorithms, just to help you comprehend the whole concept easier:

Neural network tutorial: The back-propagation algorithm (Part 1)
Inditás gomb

Neural network tutorial: The back-propagation algorithm (Part 1) (00:13:01)

There are many good written articles over the net for it, Wikipedia is a great detailed source as well:
https://en.wikipedia.org/wiki/Backpropagation

Alright, going back to coding. We need to declare these two additional variables and initialize them at the constructor before we can use them:

public class Network {
	private double[][] errorSignal;
	private double[][] outputDerivative;
}
 
public Network(int[] NETWORK_LAYER_SIZES) {this.errorSignal = new double[NETWORK_SIZE][];
	this.outputDerivative = new double[NETWORK_SIZE][];
 
	for (int i = 0; i < NETWORK_SIZE; i++) {this.errorSignal[i] = new double[NETWORK_LAYER_SIZES[i]];
		this.outputDerivative[i] = new double[NETWORK_LAYER_SIZES[i]];}
}

The feed-forwarding calculation needs to be updated with these variables as well:

public double[] calculate(double input[]) {for (int layer = 1; layer < NETWORK_SIZE; layer++) {
		for (int neuron = 0; neuron < NETWORK_LAYER_SIZES[layer]; neuron++) {for (int prevNeuron = 0; prevNeuron < NETWORK_LAYER_SIZES[layer - 1]; prevNeuron++) {}
			output[layer][neuron] = sigmoid(sum);
			outputDerivative[layer][neuron] = output[layer][neuron] * (1 - output[layer][neuron]);
		}
	}}

Calculating the error needs another method, we will call this “backpropError”, which receives the target output array and does the error calculations for each layer, starting from the last one:

public void backpropError(double[] target) {
	for (int neuron = 0; neuron < NETWORK_LAYER_SIZES[NETWORK_SIZE - 1]; neuron++) { //for output layer neurons
		errorSignal[NETWORK_SIZE - 1][neuron] = (output[NETWORK_SIZE - 1][neuron] - target[neuron]) * outputDerivative[NETWORK_SIZE - 1][neuron];
	}
 
	for (int layer = NETWORK_SIZE - 2; layer > 0; layer--) { //for hidden layer neurons
		for (int neuron = 0; neuron < NETWORK_LAYER_SIZES[layer]; neuron++) {
			double sum = 0;
			for (int nextNeuron = 0; nextNeuron < NETWORK_LAYER_SIZES[layer + 1]; nextNeuron++) {
				sum += weights[layer + 1][nextNeuron][neuron] * errorSignal[layer + 1][nextNeuron];
			}
			this.errorSignal[layer][neuron] = sum * outputDerivative[layer][neuron];
		}
	}
}

Once we have these values, we can finally update the weights and biases over our network. We will need another method for this. Let’s call this “updateWeightsAndBiases”. It can receive 1 parameter called the “learning rate”. The learning rate is just a ratio value, indication how brave should the learning algorithm be over nudging those values in a positive or negative values. Setting this number to too small will produce a much slower learning periods, but setting it to too high may produce errors or anomalies over the calculations, making the whole learning process taking slower again.

public void updateWeightsAndBiases(double learningRate) {
	for (int layer = 1; layer < NETWORK_SIZE; layer++) {
		for (int neuron = 0; neuron < NETWORK_LAYER_SIZES[layer]; neuron++) {
			//for bias
			double delta = -learningRate * errorSignal[layer][neuron];
			bias[layer][neuron] += delta;
 
			//for weights
			for (int prevNeuron = 0; prevNeuron < NETWORK_LAYER_SIZES[layer - 1]; prevNeuron++) {
				//weights[layer, neuron, prevNeuron]
				weights[layer][neuron][prevNeuron] += delta * output[layer - 1][prevNeuron];
			}
		}
	}
}

Next, let’s have a method that will make our live easier and connect all these learning functionalities together. Let’s call it “train”. It receives the input array, the output array and a learning rate. It goes over all these previously mentioned calculatios:

public void train(double[] input, double[] target, double learningRate) {
	if (input.length != INPUT_SIZE || target.length != OUTPUT_SIZE) {
		return;
	}
 
	calculate(input);
	backpropError(target);
	updateWeightsAndBiases(learningRate);
}

We are now set to use our learning algorithm! Let’s change the main method to do so. We can use the same similar network setup, having for instance the input layer as 3 neurons values: 0.1, 0.5, 0.2, while having the output layer of 5 neurons, expecting the output to be for this given input combination to be 0, 1, 0, 0, 0. The FOR loop represents the number of times we are running the learning algorithm and applying the changes to the weights/biases.

public static void main(String[] args) {
	Network net = new Network(new int[]{3,4,3,5});
 
	double[] input = new double[]{0.1, 0.5, 0.2};
    double[] expected = new double[]{0, 1, 0, 0, 0};
 
	for (int i = 0; i < 1; i++) {
		net.train(input, expected, 1); //input, target, learningRate
	}
 
	double[] output = net.calculate(input);
 
	System.out.print("  current output neuron values: ");
	for (double neuronValue: output) {
		System.out.printf("%02.3f  ", neuronValue);
	}
 
	System.out.printf("\n expected output neuron values: ");
	for (double neuronValue: expected) {
		System.out.printf("%02.3f  ", neuronValue);
	}
}

Running the program gives us a seemingly far away result from desired:

output:
  current output neuron values: 0.744  0.667  0.566  0.576  0.388  
 expected output neuron values: 0.000  1.000  0.000  0.000  0.000

This is reasonable again, we ran the learning algorithm only once, and as we know already, it’s virtually impossible to “guess” the right weight/bias combination. The network needs many tries and measuring over and over, until it can get closer and closer. Let’s try running the learning algorithm 10 times for instance by changing the FOR loop value:

output:
  current output neuron values: 0.143  0.791  0.226  0.224  0.242  
 expected output neuron values: 0.000  1.000  0.000  0.000  0.000 

We can see that the output this time is getting actually closer to the desired values. The ones that should be zero are ~0.2, and the one that should be 1, is almost ~0.8. Ok, let’s try running the learning algorithm, say 10,000 times:

output:
  current output neuron values: 0.004  0.996  0.004  0.004  0.004  
 expected output neuron values: 0.000  1.000  0.000  0.000  0.000  

We can see that the values are getting really close to the desired ones, and the more and more we train the network, the more accurate will it actually be. It depends on us how close do we want to get to the desired values before we can safely say that the network knows the right output for the right input, and how much processing power do we want to trade in for the training. You can imagine that over a large network and large amount of input data, a couple of million iterations can take hours or even days.

Multiple Input and Output Sets for our Neural Network:

In most of the cases, we would have a large amount of different input sets and all of them need to produce a given targeted output sets. We could have different variable names for each selected input and desired output arrays, but you can imagine that this would start to get tedious even for a couple of hundred values, not talking about millions.

To tackle this issue, we need to be as efficient as possible and create a new class, which can contain and work with many-many input and their corresponding expected output values. Let’s call it “TrainSet”. I’m briefly going the talk about a few methods in it, because most of them are straight forward to understand just by looking at them.

So we have a constructor that can accept the input and output size, this will represent the number of neurons at the network’s input and output layer.

“addData(input[], expected[])” will expect two parameters, the first one being the currently inserted input array values and the second being currently expected output array values for it. You can call this method as many time you need, and add as many input/expected array combinations to the set, for instance with a simple FOR loop.

“getInput(index)” and “getOutput(index)” will get you back these input/expected array values from the given index point.

“extractBatch” Gives us the ability to extract only a given range of the preloaded set, instead of the all. This can be handy for instance if we have 7000 entries in the set, but we would like to work with only 20 for a given task.

The main method just generates some random input/expected values, stores them in the set with the help of the FOR loop, and outputs them in the end as a demonstration.

public class TrainSet {
 
	public final int INPUT_SIZE;
	public final int OUTPUT_SIZE;
 
	//double[][] <- index1: 0 = input, 1 = output || index2: index of element
	private ArrayList < double[][] > data = new ArrayList < >();
 
	public TrainSet(int INPUT_SIZE, int OUTPUT_SIZE) {
		this.INPUT_SIZE = INPUT_SIZE;
		this.OUTPUT_SIZE = OUTPUT_SIZE;
	}
 
	//adds new data to the data set
	public void addData(double[] in , double[] expected) {
		if ( in .length != INPUT_SIZE || expected.length != OUTPUT_SIZE) return;
		data.add(new double[][] { in ,
			expected
		});
	}
 
	public TrainSet extractBatch(int size) {
		if (size > 0 && size <= this.size()) {
			TrainSet set = new TrainSet(INPUT_SIZE, OUTPUT_SIZE);
			Integer[] ids = NetworkTools.randomValues(0, this.size() - 1, size);
			for (Integer i: ids) {
				set.addData(this.getInput(i), this.getOutput(i));
			}
			return set;
		} else return this;
	}
 
	public static void main(String[] args) {
		TrainSet set = new TrainSet(3, 2);
 
		for (int i = 0; i < 8; i++) {
			double[] a = new double[3];
			double[] b = new double[2];
			for (int k = 0; k < 3; k++) {
				a[k] = (double)((int)(Math.random() * 10)) / (double) 10;
				if (k < 2) {
					b[k] = (double)((int)(Math.random() * 10)) / (double) 10;
				}
			}
			set.addData(a, b);
		}
 
		System.out.println(set);
	}
 
	public String toString() {
		String s = "TrainSet [" + INPUT_SIZE + " ; " + OUTPUT_SIZE + "]\n";
		int index = 0;
		for (double[][] r: data) {
			s += index + ":   " + Arrays.toString(r[0]) + "  >-||-<  " + Arrays.toString(r[1]) + "\n";
			index++;
		}
		return s;
	}
 
	//how many data sets we got
	public int size() {
		return data.size();
	}
 
	//gets the input set from a certain index on the data set 
	public double[] getInput(int index) {
		if (index >= 0 && index < size()) return data.get(index)[0];
		else return null;
	}
 
	//gets the output set from a certain index on the data set 
	public double[] getOutput(int index) {
		if (index >= 0 && index < size()) return data.get(index)[1];
		else return null;
	}
 
	public int getINPUT_SIZE() {
		return INPUT_SIZE;
	}
 
	public int getOUTPUT_SIZE() {
		return OUTPUT_SIZE;
	}
}

Going back to our Network class, let’s create a method called “trainWithSet”. This method will accept a whole trainset to work with, a number of training loops we would like to go through the whole set, and the batchSize we would like to work with:

public void trainWithSet(TrainSet set, int loops, int batchSize) {
	if (set.INPUT_SIZE != INPUT_SIZE || set.OUTPUT_SIZE != OUTPUT_SIZE) {
		return;
	}
 
	for (int i = 0; i < loops; i++) {
		TrainSet batch = set.extractBatch(batchSize);
 
		for (int b = 0; b < batchSize; b++) {
			this.train(batch.getInput(b), batch.getOutput(b), 0.3);
		}
	}
}

We need a new main method to handle traning sets, let’s make one:

public static void main(String[] args) {
	Network net = new Network(new int[] {
		5,
		3,
		3,
		2
	});
 
	TrainSet set = new TrainSet(5, 2);
 
	set.addData(new double[]{0.1,0.2,0.3,0.4,0.5}, new double[]{0.9,0.1});
	set.addData(new double[]{0.9,0.8,0.7,0.6,0.2}, new double[]{0.1,0.9});
	set.addData(new double[]{0.3,0.8,0.7,0.4,0.1}, new double[]{0.3,0.7});
	set.addData(new double[]{0.9,0.3,0.4,0.5,0.6}, new double[]{0.7,0.3});
	set.addData(new double[]{0.2,0.9,0.4,0.2,0.4}, new double[]{0.2,0.4});
    set.addData(new double[]{0.1,0.1,0.9,0.9,0.9}, new double[]{0.5,0.5});
 
 
	net.trainWithSet(set, 1, 6);
 
	for (int i = 0; i < 6; i++) {
		System.out.println(Arrays.toString(net.calculate(set.getInput(i))));
	}
}

I’ve made a network with 5 neurons at the input layer, 2 at the output and 3 at both of the hidden layers. For this example this will be sufficient, but this is the time when we need to think of the hidden layer’s size. If we define the number of neurons too small here, the network won’t have enough space to “store” very large number of data combinations, because the new input values that would set the weights and biases, can override the already properly defined ones, resulting in never-ending try and error iterations, that will never produce accurate result for all the desired values.

On the other hand, having too large network size will make the network extremely slow to work with, and making it significantly slower to learn as well.

So we instantiated a new trainset in the main method, having the same number of input and output neuron numbers as our network does. We added 6 data sets, each containing the input set, and the expected output set for it.

Finally, we called each input set entry values (in our example, that’s 6 entries to loop through), and verify out network if it produces the expected output values, after the training.

If we run our program, we can see that the values are all random numbers all over the place:

output:
[0.5804082848557195, 0.611540224159821]
[0.5793365763365534, 0.6152768910621293]
[0.5792965979397438, 0.6135348171779963]
[0.5798916531162135, 0.6149473277301244]
[0.5799083251987178, 0.6139233850164606]
[0.5825736971539314, 0.6127042166996858]

This is fully expected now that we know how the training process works. Let’s notch up the training to run 1000 times:

output:
[0.8269183006326297, 0.1488344744465759]
[0.13914142176572553, 0.7727892885721617]
[0.16591764093195452, 0.7372080691272994]
[0.6711814111500592, 0.27195100535567884]
[0.3606707137762615, 0.5284685374836402]
[0.4670048361628152, 0.43512742680336075]

We can see that the numbers are converging closer and closer to the expected output values, the more and more training do we make before testing. This is fully expected again. Let’s try 100,000 training iterations anyway:

output:
[0.9000000328097575, 0.10000019245068295]
[0.10000119473600338, 0.9000012484104274]
[0.29999933445396226, 0.6999994676152578]
[0.6999999906432556, 0.29999997748811974]
[0.2000002150797167, 0.39999998997508834]
[0.5000000439132515, 0.500000037083972]

Yep, as expected, all the tested output values are getting extremely close to the expected values, after this many training iterations.

You can see where we are going with this. Yes, again referring back to the previous article, we can use this to train the network with large number of written single digit numbers, to “guess” our uniquely handwritten sample that we will provide to it.

Finally, training for handwriting recognition with MNIST data set:

MNIST is a large, open and free database of handwritten digit values, and their supposed output labels. It has a training set over 60,000 examples and test set of 10,000 examples:
http://yann.lecun.com/exdb/mnist/

Let’s download the training set of images and training set of labels and store them in /res folder. We can make another file here, called number.png, a 28*28pixel large file that will eventually contain our personally handwritten testable image.

We will make several classes to work with the MNIST dataset values and connect them with our network. First the “MnistDbFile.java” to help us work with the database files:

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
 
/**
 * MNIST database file containing entries that can represent image or label
 * data. Extends the standard random access file with methods for navigating
 * over the entries. The file format is basically idx with specific header
 * information. This includes a magic number for determining the type of stored
 * entries, count of entries.
 */
public abstract class MnistDbFile extends RandomAccessFile {
	private int count;
 
	/**
     * Creates new instance and reads the header information.
     * 
     * @param name
     *            the system-dependent filename
     * @param mode
     *            the access mode
     * @throws IOException
     * @throws FileNotFoundException
     * @see RandomAccessFile
     */
	public MnistDbFile(String name, String mode) throws IOException {
		super(name, mode);
		if (getMagicNumber() != readInt()) {
			throw new RuntimeException("This MNIST DB file " + name + " should start with the number " + getMagicNumber() + ".");
		}
		count = readInt();
	}
 
	/**
     * MNIST DB files start with unique integer number.
     * 
     * @return integer number that should be found in the beginning of the file.
     */
	protected abstract int getMagicNumber();
 
	/**
     * The current entry index.
     * 
     * @return long
     * @throws IOException
     */
	public long getCurrentIndex() throws IOException {
		return (getFilePointer() - getHeaderSize()) / getEntryLength() + 1;
	}
 
	/**
     * Set the required current entry index.
     * 
     * @param curr
     *            the entry index
     */
	public void setCurrentIndex(long curr) {
		try {
			if (curr < 0 || curr > count) {
				throw new RuntimeException(curr + " is not in the range 0 to " + count);
			}
			seek(getHeaderSize() + (curr - 1) * getEntryLength());
		} catch(IOException e) {
			throw new RuntimeException(e);
		}
	}
 
	public int getHeaderSize() {
		return 8; // two integers
	}
 
	/**
     * Number of bytes for each entry.
     * Defaults to 1.
     * 
     * @return int
     */
	public int getEntryLength() {
		return 1;
	}
 
	/**
     * Move to the next entry.
     * 
     * @throws IOException
     */
	public void next() throws IOException {
		if (getCurrentIndex() < count) {
			skipBytes(getEntryLength());
		}
	}
 
	/**
     * Move to the previous entry.
     * 
     * @throws IOException
     */
	public void prev() throws IOException {
		if (getCurrentIndex() > 0) {
			seek(getFilePointer() - getEntryLength());
		}
	}
 
	public int getCount() {
		return count;
	}
}

Next is the “MnistImageFile.java” to work with the images in the database:

import java.io.FileNotFoundException;
import java.io.IOException;
 
/**
 * 
 * MNIST database image file. Contains additional header information for the
 * number of rows and columns per each entry.
 * 
 */
public class MnistImageFile extends MnistDbFile {
	private int rows;
	private int cols;
 
	/**
     * Creates new MNIST database image file ready for reading.
     * 
     * @param name
     *            the system-dependent filename
     * @param mode
     *            the access mode
     * @throws IOException
     * @throws FileNotFoundException
     */
	public MnistImageFile(String name, String mode) throws FileNotFoundException,
	IOException {
		super(name, mode);
 
		// read header information
		rows = readInt();
		cols = readInt();
	}
 
	/**
     * Reads the image at the current position.
     * 
     * @return matrix representing the image
     * @throws IOException
     */
	public int[][] readImage() throws IOException {
		int[][] dat = new int[getRows()][getCols()];
		for (int i = 0; i < getCols(); i++) {
			for (int j = 0; j < getRows(); j++) {
				dat[i][j] = readUnsignedByte();
			}
		}
		return dat;
	}
 
	/**
     * Move the cursor to the next image.
     * 
     * @throws IOException
     */
	public void nextImage() throws IOException {
		super.next();
	}
 
	/**
     * Move the cursor to the previous image.
     * 
     * @throws IOException
     */
	public void prevImage() throws IOException {
		super.prev();
	}
 
	@Override
	protected int getMagicNumber() {
		return 2051;
	}
 
	/**
     * Number of rows per image.
     * 
     * @return int
     */
	public int getRows() {
		return rows;
	}
 
	/**
     * Number of columns per image.
     * 
     * @return int
     */
	public int getCols() {
		return cols;
	}
 
	@Override
	public int getEntryLength() {
		return cols * rows;
	}
 
	@Override
	public int getHeaderSize() {
		return super.getHeaderSize() + 8; // to more integers - rows and columns
	}
}

Next is the “MnistLabelFile.java” to help us work with the labels over the database:

import java.io.FileNotFoundException;
import java.io.IOException;
 
/**
 * 
 * MNIST database label file.
 * 
 */
public class MnistLabelFile extends MnistDbFile {
 
	/**
     * Creates new MNIST database label file ready for reading.
     * 
     * @param name
     *            the system-dependent filename
     * @param mode
     *            the access mode
     * @throws IOException
     * @throws FileNotFoundException
     */
	public MnistLabelFile(String name, String mode) throws IOException {
		super(name, mode);
	}
 
	/**
     * Reads the integer at the current position.
     * 
     * @return integer representing the label
     * @throws IOException
     */
	public int readLabel() throws IOException {
		return readUnsignedByte();
	}
 
	/** Read the specified number of labels from the current position*/
	public int[] readLabels(int num) throws IOException {
		int[] out = new int[num];
		for (int i = 0; i < num; i++) out[i] = readLabel();
		return out;
	}
 
	@Override
	protected int getMagicNumber() {
		return 2049;
	}
}

And finally, the “Mnist.java” file, that will contain our main method to run the training algorithms, connect them with the training sets, and finally test our handwritten number and try to guess its value:

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
 
import javax.imageio.ImageIO;
 
public class Mnist {
 
	public static void main(String[] args) {
		Network network = new Network(new int[]{784, 70, 35, 10});
 
		TrainSet set = createTrainSet(0, 5000);
		trainData(network, set, 10, 20, 5000);
 
		testMyImage(network);
	}
 
	public static void testMyImage(Network net) {
		BufferedImage img = null;
		try {
			img = ImageIO.read(new File("res/number.png"));
		} catch(IOException e) {
			e.printStackTrace();
		}
		double[] input = new double[784];
		for (int i = 0; i < 28; i++) {
			for (int n = 0; n < 28; n++) {
				input[n * 28 + i] = (float)(new Color(img.getRGB(i, n)).getRed()) / 256f;
			}
		}
 
		System.out.print("output neuron values: ");
		double[] output = net.calculate(input);
		for (double neuronValue: output) {
			System.out.printf("%02.3f  ", neuronValue);
		}
		System.out.println();
		System.out.print("corresponding number:     0      1      2      3      4      5      6      7      8      9");
		System.out.println();
 
		System.out.println("I think, that the handwritten number is: " + NetworkTools.indexOfHighestValue(output) + "!");
	}
 
	public static TrainSet createTrainSet(int start, int end) {
 
		TrainSet set = new TrainSet(28 * 28, 10);
 
		try {
 
			String path = new File("").getAbsolutePath();
 
			MnistImageFile m = new MnistImageFile(path + "/res/trainImage.idx3-ubyte", "rw");
			MnistLabelFile l = new MnistLabelFile(path + "/res/trainLabel.idx1-ubyte", "rw");
 
			for (int i = start; i <= end; i++) {
				if (i % 100 == 0) {
					System.out.println("prepared: " + i);
				}
 
				double[] input = new double[28 * 28];
				double[] output = new double[10];
 
				output[l.readLabel()] = 1d;
				for (int j = 0; j < 28 * 28; j++) {
					input[j] = (double) m.read() / (double) 256; //images are from 0-256 but we want 0-1 for our network to learn.
				}
 
				set.addData(input, output);
				m.next();
				l.next();
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
 
		return set;
	}
 
	public static void trainData(Network net, TrainSet set, int epochs, int loops, int batch_size) {
		for (int e = 0; e < epochs; e++) {
			net.trainWithSet(set, loops, batch_size);
			System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>   " + e + "   <<<<<<<<<<<<<<<<<<<<<<<<<<");
		}
	}
}

Let’s take a look at the main method in the “Mnist.java” class. The input neuron array size is 784, each one representing a single pixel value from a written number (from 28*28 images). An output neuron array size can be 10, each one representing a single digit number, from 0-9. The two hidden layer’s neuron sizes are set 70 and 35 in this case.

The “createTrainSet” method gives us the ability to choose only a range of batch set’s from the 60,000+ values. Setting this to a reasonable small number helps us reduce the time needed to load up the desired number of training values. In this example, we are using the values from 0 to 5000 from the 60,000.

The “trainData” method does all the training steps. We pass the created neural network to it, then the created trainSet. After that, we pass the number of “epoch” we want to loop through, then the number of “iterations” we would like to loop through. Finally, we pass the number of batch size we would like to work with. We preloaded 5000 images so might as well pass all those, but we can always chose a smaller or bigger number.

By “iteration” we mean the regular of times we loop through the training methods, as we did in the previous examples. On the other hand, “Epoch” in the neural network industry means the number of times rerun all the iteration loops with all the working datasets. You can think of the two terms as nested loops. “Iterations” being the inner loop, while “epoch” being the outer loop. The final results will be more accurate as more and more training iterations and epochs do we make, with more and more unique datasets. Naturally, the larger these numbers get, the slower our whole training process will get also.

The “testMyImage” methods will load our custom handwritten image, and tries to guess its digit value, based on the network’s trained knowledge. Let’s write any number with a mouse, with white brush over a completely black background. These pixels will represent input values from range from 0 (being completely black) to 1 (being completely white). In my case, I wrote number 3:

kép:https://i.imgur.com/00CJKGH.png

Let’s run the program. As you can see, this significantly takes longer than our previous small examples. We are working with larger amount of data over a larger network. This is a good time to mention, that the training normally only needs to occur once, even if it takes hours or days to setup. Once we properly trained our network, all the weight and bias values can be serialized and saved to a file for instance, so every time when we want to read a new handwritten image and ask the network for its guessed digit value, it can process it almost instantaneously. I will not go in detail of discussing the serialization process in this article, but will assume that the reader at this level does know what I’m talking about, or can figure it out very easily.

output:
prepared: 0
prepared: 100
prepared: 200
prepared: 300
prepared: 400
prepared: 500
prepared: 600
prepared: 700
prepared: 800
prepared: 900
prepared: 1000
prepared: 1100
prepared: 1200
prepared: 1300
prepared: 1400
prepared: 1500
prepared: 1600
prepared: 1700
prepared: 1800
prepared: 1900
prepared: 2000
prepared: 2100
prepared: 2200
prepared: 2300
prepared: 2400
prepared: 2500
prepared: 2600
prepared: 2700
prepared: 2800
prepared: 2900
prepared: 3000
prepared: 3100
prepared: 3200
prepared: 3300
prepared: 3400
prepared: 3500
prepared: 3600
prepared: 3700
prepared: 3800
prepared: 3900
prepared: 4000
prepared: 4100
prepared: 4200
prepared: 4300
prepared: 4400
prepared: 4500
prepared: 4600
prepared: 4700
prepared: 4800
prepared: 4900
prepared: 5000
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 0 <<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 1 <<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 2 <<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 3 <<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 4 <<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 5 <<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 6 <<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 7 <<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 8 <<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>> epoch: 9 <<<<<<<<<<<<<<<<<<<<<<<<<<
 output neuron values: 0.030  0.001  0.000  0.256  0.000  0.002  0.000  0.001  0.000  0.000  
 corresponding number:     0      1      2      3      4      5      6      7      8      9 
I think, that the handwritten number is: 3!

Did the network produce an accurate result? If yes, excellent! If not, don’t give up! Keep fiddling with the parameter values, give the network some more storage range in form of neurons, more testing data, or more iteration/epoch loops and retry the results until you manage to get it right.

Got any inspiration where else could you use this technology?

Into the Breach betekintő

Fórum:

Az Into the Breach egy tökéletes kispoén játék, ami sokszor újrajátszva is élvezetes marad. Ugyanannak a Subset Gamesnek a keze munkáját dícséri, akiét az FTL is. Ahhoz hasonlóan ezt is ízléses pixelgrafika és midi zene jellemzi, de ez körökre osztott.

Ben Prunty - Into the Breach OST - full album (2018) Inditás gomb

Ben Prunty - Into the Breach OST - full album (2018) (01:02:27)

Logikai játék. Adott három mech, mindegyik más eszközökkel felszerelve, ezekkel kell a bogárszerű idegenek (Vek) támadásától megvédeni a városokat, és ha lehet, kiirtani őket. A Vekek is sokfélék, sokféle képességgel, ők lépnek először, majd támadni készülnek – hogy hogyan és hova, azt látni fogjuk a játéktéren. Most a mechjeink lépnek: igy elkezdhetünk elhárítani vagy elterelni a várost érő csapásokat, illetve irtani vagy éppen egymás megsebzésére rábírni az ellent. Alaposan át kell gondolni minden lépést, gyakran csak nagyon kacifántos megoldással érhető el, hogy ne szenvedjen visszafordíthatatlan sérülést a város, és mi magunk sem – olykor pedig csak csökkenteni tudjuk a kárt. Ha nagyon muszáj, visszaugorhatunk az időben a körünk elejére, de csatánként csak egyszer.
Elsősorban a háztömbökre kell vigyáznunk, mert ha ezek sérülnek, pusztul a lakosság (ez a pontszámunkat érinti), de ami még fontosabb, hogy csökken a Power Grid ereje is, márpedig ha ez nullára esik, a játéknak vége. Ha magas az érték, az azért is jó, mert nő a százalékos valószínűsége annak is, hogy néha lerázzák magukról a támadást az épületek, meg hát a végjátékra sem ártana bőven tartogatnunk belőle... Másodsorban a mechjeinket féltjük: ha elfogy az életerejük, az adott csata hátralévő részében csak ócskavasnak jók, és meghal a pilótájuk is. Pedig ők igen hasznos skilleket kapnak a játék folyamán (már egy első szintű emberünk elvesztése sem öröm, hát még egy teljesen kiképzetté). 


Ezt a karikatúrát a játékban hozandó döntésekről Strato mester találta. :-)

Ezen felül minden csatatéren van valami plusz feladat is, ami megnehezíti az életünket, de új lehetőségeket kínál, és ha sikerül megoldani, jutalmakat jelent. Ilyen például egy lerombolandó gát, ami ha átszakad, a víz elsodorja a közelépen lévő Vekeket, vagy egy erőmű, ami nehezen védhető pozícióban állandó céltáblája a bogaraknak, de ha megvédjük, növeli a Power Grid értékét...

Into the Breach Official Launch Trailer Inditás gomb

Into the Breach Official Launch Trailer (00:01:11)

A csatatérre olykor időkapszulák hullanak, amiket megmentve értékes fejlesztéseket szerezhetünk a mechekhez. Ha egy egész szigetet megtisztítunk, szintén ilyeneket vásárolhatunk a csaták során felhalmozott pontjainkból. A mechek fejlesztett reaktort kaphatnak, amivel új rendszereket üzemelhetnek be, vagy a meglevők plusz képességeit nyithatják meg. A maradék pontokból pedig valamelyest kijavítgathatjuk a Vekek tépázta Power Gridet.
Aztán nekiveselkedhetünk a következő szigetnek, ahol számottevően erősebb bogarak várnak ránk. Legalább két sziget kipucolása után megpróbálkozhatunk a végső küldetéssel – minél több szigeten fejlődtünk, annál hatékonyabban vehetjük fel itt a harcot, de annál ádázabbak a bogarak is.
Akár győzünk itt, akár elbukunk, a háború bármelyik pontján, egy pilótánkat visszaküldhetjük az időben, így egy pici előnnyel kezdhetünk a következő játékba. Ezen felül különböző achievementek teljesítésével újabb mech csapatokat nyithatunk meg, akik teljesen másképpen harcolnak, mint a többi – ezzel is növelve az újrajátszás élményét.
Megint egyszerű de nagyszerű kis játék született a Subset Gamestől, örülök neki, és várom a következőt!

Into the Breach - Combat Music Inditás gomb

Into the Breach - Combat Music (00:03:10)

Neural Networks II: How do they work, where can I use them?

Fórum:

Címkék:

kép:https://i.imgur.com/FC1QvBY.jpg
In the second article in the series, I am attempting to:
  • Very briefly mention a few examples of all the Neural Network types and branches, since there are many. 
  • Focus on the most oldest and most simple one, the “Fully Connected, Feed Forward Neural Network”
  • Explain in great detail how it works using intuition and graphs, rather than math, to make it easy as possible to understand.
  • Explain the commonly used related terminology.
  • Show a real life example where and how you could use it.
 
The first steps to achieve artificial neural networks were made 75 years ago, and it became one of the hottest emerging technologies in recent years. The original idea was to produce a working mathematical abstraction, how would a biological brain function in theory, as I've mentioned in the previous article.
 
You don't have to be a neuroscientist to have at least a very basic understanding how would a biological brain work. Having a large number of brain-cells called "neurons", that can form connections called "synapses" between each other, based on the various signals that they receive from out body over our lifetime. If you receive a similar experience, the similar neurons will fire up with those connections, so you will remember the given situation easier and react to it faster, more accurately.
 
There are many-many types of Neural Networks branches and sub-branches nowadays, all of them trying to archive being closest to "perfect" solution for the given idea. The search is still ongoing, we still don't know how exactly the biological brain works, but we don't even know if that is the best way to achieve intelligence also. We may going to come up with even more efficient way than our current biological solution, like we did in many other areas in the modern industrial world.
 
Some of main aNN branch examples include the "Feed Forward Neural Networks", that are referred sometimes as "Conventional" neural networks. This is the earliest and oldest solution, based on the idea where neuron connection are "fed-forward" between neurons, so the information can travel through them in simple intuitive way, usually starting from leftmost and ending up in the rightmost positions.
 
The most well-known sub-branches here include the "Convolutional Neural Networks", where the connections are filtered and grouped between neurons, to simplify and scale down large amount of information to abstracted representations. This is generally used for image recognitions nowadays. Other well-known sub-branch is the "Fully Connected Neural Networks". Here, each neuron in a given layer is connected with every single neuron on the previous layer.
 
More modern main branch examples are the "Recurrent Neural Networks", where connections can form circles or reach similar non-conventional connections between each other. Some sub-branch examples can include "Bi-directional NN", or "Long Short-Term Memory NN". The latter example is generally used for speech recognition.
 
"Spiking Neural Networks" are sometimes referred as the third generation of NN, which can activate neuron connection in a seemingly randomly "spiking" way, and are probably the closest real representations of the biological brain solutions nowadays.
 
In this article we are going to deal with (you guessed it), the oldest and simplest one to tackle: the Fully Connected, Feed Forward Neural Networks.
 
Let’s understand step-by-step what do they consist of and how they work first, then later on we can talk about how we can use them.
 
What is a Fully Connected, Feed Forward Neural Network?
 
From the highest level, think of it as a calculating box where on one side you can feed in some information, and on the other side you can receive the calculated results:
 
kép:https://i.imgur.com/A0LWkLq.jpg
 
You can have more than one input and output values, technically any number of input or output values you would require, even very large ones:
 
kép:https://i.imgur.com/subBMJW.jpg
 
If you open the box, you will see all the neurons some layers separating them. The very first layer is the “input layer” and each neuron there will store an input value. Similarly the very last layer is the “output layer”, each neuron there will store the final output value:
 
kép:https://i.imgur.com/s5iHctX.jpg
 
Those in between layers are referred as “hidden layers”. They are called "hidden" because we never see (nor we really care) what happens in them, we just want them to help figure out the right results for out final “output layer”. The number of these hidden layers can be several, but usually a few is enough, as the larger this number gets, the slower all the calculations can take.
 
As I’ve said before, in FCNN each neurons in a given layer are connected to all the neurons in previous adjacent layers. One single connection has to be adjacent, we cannot skip over a layer, and so one connection between two neurons would be represented like this:
 
kép:https://i.imgur.com/x6Wk5VI.jpg
 
Connecting one neuron to all from the previous layer can be represented like this:
 
kép:https://i.imgur.com/qzTJiqO.jpg
 
After finishing populating all the rest of the connections, the network will look like this, hence the name “Fully connected”:
 
kép:https://i.imgur.com/0RfKlUy.jpg
 
Let’s break down this some more. Probably the most interesting component here is the “Neuron”. What would that be and how does it work?
 
This can get fairly “mathy”, but I will try to spare you by avoiding referring to math, and just giving the intuitive explanation whenever I can.
 
If we focus on one neuron, we can see that it can receive many values from one side, apply a summary function that adds these values up, and lastly it will apply a “Sigmoid” function to this sum, before releasing the neuron’s calculated output.
 
kép:https://i.imgur.com/IKKutPg.jpg
 
The sigmoid is an “S” shaped function as you can see in this graph, and the purpose of it to transform the sum value between 0 and 1. Even if the sum turns out to be a crazily large or crazily small number for instance, it will always be “corrected” back somewhere between 0 and 1 with this function. We are doing this to simplify working with the data in the network. It’s much simpler to understand the numbers beings closer to 1 as “perhaps yes”, and the numbers being close to 0 as “perhaps no”.
 
kép:https://i.imgur.com/Lz82eVY.png
 
What do I mean by “perhaps”? As I’ve said in the first article, neural networks by design are not meant for super precise calculations like we would expect from normal computers, but to do good approximations, and they will do better and better approximations as they train more.
 
Going back to our example, let’s assume we have 3 neurons with output values between 0 and 1 somewhere: 0.8, 0.3, 0.5:
 
kép:https://i.imgur.com/HpiYEUE.jpg
 
The sum function will add all the received values up.
 
sum(0.8, 0.3, 1.6)  = 0.8 + 0.3 + 0.5 = 1.6
 
After that, the neuron will apply the Sigmoid function to this value so we will squeeze any result back between 0 and 1 somewhere, resulting 0.832 as the output value from this neuron:
 
sigmoid(1.6) = 0.832
 
This would be the formula for the Sigmoid function, for those who would like to see the math as well:
 
kép:https://i.imgur.com/p3Su53a.jpg
 
 
If we continue doing this over every neuron, until we get the final output layer, we will get our final calculated values, but you perhaps realized: we would have the same output results every time for the same given input values. In many practical cases we cannot modify the input value since we are receiving them from some other sources, also the summary and the sigmoid function’s behavior is fixed as well, but we would still like to influence and shape the outputted values somehow. Because of this need, we invented the idea of “Weights”, that are basically custom numbers, stored at the connections between the neurons. People usually refer to connections between neurons simply as “Weights”.
 
So how do “Weights” come in play?
Weights are getting multiplied with the neuron output, before that value gets summarized with the rest in the summary function, so for example if all the weights will be 1, nothing would change:
 
kép:https://i.imgur.com/yPchuhO.jpg
 
sum (0.8, 0.3, 0.5) = 0.8*1 + 0.3*1 + 0.5*1 = 1.6
 
But if we turn these weight values up or down somewhere, the outputted value can be very different:
 
kép:https://i.imgur.com/idwKgeJ.jpg
 
sum (0.8, 0.3, 0.5) = 0.8*-0.5 + 0.3*2.2 + 0.5*0.4 = -0.4 + 0.66 + 0.2 = 0.46
 
Now this solutions would be almost perfect, but people found out over time, that there may still be cases when even applying heavy Weight modifications all around the network, the final outputted values would still not be close to desired numbers, because of the Sigmoid function design. Here was the concept of “Bias” born.
 
“Bias” is very similar to Weights as being a single modifiable arbitrary number, but the difference is that it only applies to every neuron once, in the Sigmoid function, to translate it left or right.
 
Imagine a situation where your final values after applying the Summary function with Weights are converging to near 0. But after applying the Sigmoid function as well, it will bump back the output value to somewhere around 0.5, while you would rather keep that value indication 0.  This is where a Bias can be applied and will basically translate the whole sigmoid function to a direction, modifying the output greatly. Let’s see the difference with a bias of -5 or +5:
 
kép:https://i.imgur.com/Lj0Rk3N.png
 
As we can see, if we would add a Bias of -5 (red graph) to the summary before applying the Sigmoid function would result the neuron output very close to 1, while with the bias of 5 (blue graph), the output would be very close to 0.
 
So we’re happy now, with all these flexibility we really could archive any desired final output values!
 
The basic concept of “Fully Connected, Feed Forward Neural Network” is established. How or where could we use it?
 
Let’s have a nice practical example: We want it to read written number from 0 to 9. How can we approach this problem with our newly setup Neural Network?
 
First of all, let’s clear our objective: to turn any of these written “three” number images, or any similar ones, to result “3”:
 
kép:https://i.imgur.com/lUsf7X9.png
 
 
That includes all these written “four” number images, to “4”:
 
kép:https://i.imgur.com/iecL0HO.png
 
… and so on, so on.
 
We would need to turn all these images to input values first.
Let’s take a closer look at one of them. We can see that it’s been made of individual pixels. 28 rows * 28 columns of them:
 
kép:https://i.imgur.com/zAKEqpT.jpg
 
Each of these pixels have a brightness value, some of them are very bright, and some of them are darker. If we represent the brightest “unused” pixels with 0.0 and as they got darker, with a number closer and closer to 1.0, indicating that they have some sort of “activated” values there:
 
kép:https://i.imgur.com/CeYu7a6.jpg
 
If we convert all the remaining pixels to number representations as well, and write these values down in one long row, we halve all the input neuron values ready to be processed with our NN, all 784 (28*28) of them!
 
As for the output neurons, the most straightforward is to have one for each desired number (0-9). So 10 neurons in total.
 
kép:https://i.imgur.com/KkJUhGQ.jpg
 
If we plug in the digitized values to the input layer, from the image that represents written number three, we would like to receive 0.0 on all of the output neurons, except on the fourth one, that would need to be 1.0 ideally, to clearly represent number “3” ideally. (Implying the first neuron represents “0”, the second “1”, and so on until the 10th neuron, representing “9”.)
 
kép:https://i.imgur.com/CyWDBrz.jpg
 
But if we do that, we will find out that the output layer’s neuron values are nowhere near this but show some utter garbage:
 
kép:https://i.imgur.com/30oMUWC.jpg
 
That’s because the network haven’t been “Trained” yet.
 
“Training” the network means (re)adjusting all the Weights and Biases over the network to certain positions, so if we plug in the said input values, the network should produce the calculated output closest to possible to the desired ideal output.
 
We could try to manually adjust any the Weight or Bias number to some positive or negative number values, but will quickly realize that with even a fair number of neurons, there are just so many combinations it’s humanly not comprehendible to do so.
 
This is where the concept of “Backpropagation” comes extremely handy.
 
Backpropagation is one of the key features at the neural networks and is a form of a learning algorithms. It’s probably one of the most confusing concepts of it however. Simplifying it as much as possible, the basic idea is to take that utter garbage output from the neural network output, try to compare it our initially desired output, and see how far each of those outputted values are from the desired ones.
 
This number is called the “Error Bias” and if we have this number, the algorithm will try to adjust the weights and biases accordingly, starting from the rightmost layers, and work themselves back until they reach the input layer. We start from the back because the final output is at the back, and the connected Weights and Biases that are affecting that layer directly are in the previous layer, and we apply this idea over each layer.
 
After the Backpropagation is finished, we re-do the Feed-Forward step again and see if we got closer to the given value, by comparing the actual and the desired number again. A proper training can take hundreds, or millions of Feed-Forward and Backpropagation steps, until the network is conditioned to give us the closest numbers to the desired ones. Now we need to do this training process for every new input values and still make sure that the network remains giving valid results for the previous input values as well. You can begin to understand, that properly training a network over large amount of input values, to always outputs accurately close to the desired outputs is extremely hard to archive and usually takes very large number of training steps. But this is where the whole industry is working hard by discovering creative and different ways to approach this difficult issue.
 

 

Megszavazta a nép: Monster Hunter: World betekintő

Fórum:

A rövid verzió: Bedőltem a marketingnek, de kicsit sem bántam meg!

Kifejtés: Van valami ezekben a típusú játékokban, ami erősen vonz, megmagyarázhatatlanul. Óriás szörnyek, látványos fegyverek, beindul a nyálelválasztásom, ha ilyet látok. Nézegettem a MHW béta videókat, és nagyon tetszett, amit láttam. Aztán elkezdtek befutni az értékelések, és mindenki szerette: a kritikusok és a játékosok is. Pont eladtam pár társast, gondoltam egye fene, megveszem az Xbox One verziót. Ez volt a megjelenés napját követően, azaz úgy másfél hete. Azóta beletettem a játék szerint 79 órát, és még csak a 16. küldetésnél vagyok a 25 lépéses story questben.

Rögtön kezdem a negatívummal: Sima Xbox One S-en nem fut szépen a játék. Eleve nem is full HD, hanem valamivel kisebb felbontás (850p körüli, szerencsére nem 720p), és valami adaptív technikának „hála”, mozgás közben a játék grafikája erősen elmosódott, néhol majdnem szemet bántó. Viszont ennek köszönhetően a 25+ FPS stabilan megvan, szóval valamit valamiért, de azért ez kicsit csalódás volt. Nagyon nem olyan a kinézet, mint az újabb generációs konzolokon. Persze önmagában azért szép, meg 2 perc után megszokja az ember szeme, de azért mégis szomorkodtam miatta. 

A játék maga viszont bőven kárpótolt. Röviden arról van szó, hogy a rendlekezésre álló 5-6 terület valamelyikére bemész, megkeresed az épp aktuálisan vadászott szörnyet, majd agyonvered egyedül, vagy 3 másik játékossal egyetemben. És ennyi. Nincs túlspilázva, nincs mindenféle nyakatekert indoklás, csak egy egyszerű kérés: „Tábort vernénk a dzsungelben, de ott ólálkodik ez a rohadék, verd má' le!”. 

Viszont a felkészülés a vadászatra, na az megér egy misét. Először is, ott vannak a fegyverek. Az a helyzet, hogy a játékban 14 különböző fegyverfajta van, és mind a 14 teljesen másmilyen játékstílust igényel. És itt most nem arra gondolok, hogy pl. ott a négy lőfegyver, és mind a négy kb. ugyanazt csinálja, csak más animációval, meg az egyik AOE, a másik meg single target... Teljesen más animációk, kombók, gombok tartoznak az egyes fegyverekhez. A gunlance melee távban hatásos, lehet vele ütni is, és kitérés helyett pajzzsal blokkolsz. Az íj középtávú fegyver, rohangálsz a szörnytől pár méterre, ugrálsz előle, míg a két blowgun közül a heavy a nyers sebzést adja, a light pedig mindenféle státusz effektet. Ha ez nem lenne elég, a lőfegyvereknél mindenféle elemű és spec hatású lőszert használhatsz – és nyilván a fegyvereket fejleszteni is kell. Többféle fa áll rendelkezésre a fejlesztéshez... oké, hogy hosszúkard, de acél vagy csont? A csont többet sebez, de hamarabb életlenedik (fontos szerepe van a játékban az élességnek, rendszeresen fenni kell a fegyvert), az acél jobban bírja. És mindkettőnek számtalan fejlesztési ága van, elemi sebzések (tűz, víz, villám), kritikus sebzés, státusz effektek (mérgezés, fárasztás, stun); rengeteg a lehetőség. És akkor ott a számtalan páncél szett, minden darabon egy vagy több speciális skill, amit csak páncéllal/nyaklánccal lehet megszerezni...

Monster Hunter: World - Third Fleet Trailer Inditás gomb

Monster Hunter: World - Third Fleet Trailer (00:03:27)

Aztán ott vannak a mindenféle craftolható segédletek. Százféle ital, csapdák, kenőcsök, távcső. Sőt, van egy karra szerelhető csúzli; na ahhoz is ezer féle lövedéket lehet készíteni. És persze gyűjteni, a gyűjtögetés fontos! Persze indulás előtt még nem árt enni sem a kantinban, ahol a macskák (igen, japán játék, a szakácsok macskák, és szólóban van egy palico, azaz macska társad, akinek szintén gyártatod a felszerelést, cserébe segít a harcokban) a számtalan ételfajta közül elkészítik azt, ami éppen szükséges (sokféle buffot adnak).

Aztán elindulsz, és tátod a szád néha, olyan dolgok történnek a játékban. Az adott térképen általában 3-4-féle főboss van, de mellette számtalan kisebb hecsedli is – ezeket nem kötelező ütlegelni, simán elkerülhetők többségében. Szaladgálsz körbe, kutatod a nyomokat – minden megtalált nyomért pontokat kapsz, ha elég sokat elérsz, akkor az adott szörny ismerete bővül, ennek 3 szintje van. A jegyzeteid között ilyenkor meg tudod nézni az adott szörny adatait: általános viselkedése és taktikája, gyenge pontjai, illetve hogy mely elemekre érzékeny és immunis.

Ha kellően magas a szörnyismereted, akkor a térképre belépve az első nyom megtalálása után jelzi a játék a legrövidebb útvonalat a szörnyhöz. Odaérsz, és kezdődik a móka. Kifejezetten változatos, és sokszor nagyon nehéz ellenfelek vannak – nem annyira bonyolultak, mint egy Dark Souls boss, de azért nagyon nem áll messze. Remek képességekkel és animációkkal rendelkeznek, komolyan, élmény minden harc. Fontos szerepe van, hogy kiismerd a jeleket a nagyobb támadásai előtt, főleg, ha lassabb fegyverrel játszol. Nem árt a környezetre is figyelni, vannak használható elemek: magasról ugorva a szörny hátán találhatod magad, vagy éppen gyorsan kilőve egy békát elkábul az ellen – sok-sok ilyen van. Plusz – az előbb említetteknek megfelelően – vannak a szörnyeknek gyenge pontjai: van, amelyiknek a feje, másiknak a szárnya, lába, hasa... Sőt, némelyiket (farok, szárny) le is lehet metszeni, ezzel pl. a wyverneknél az egyik legkellemetlenebb mérgező támadását ki lehet zárni a küzdelemből. Gyakran bizonyos mennyiségű bevitt sebzés után megfutamodnak a szörnyek, és elmennek pihengetni – ilyenkor, ha nem követed elég gyorsan, biza lassan visszaregenerálja magát. Ja, és a legtöbb küldetésnek 50 perces időlimitje is van...

Monster Hunter: World - Elder Dragons Trailer Inditás gomb

Monster Hunter: World - Elder Dragons Trailer (00:03:01)

Ami viszont óriási fun (elsőre): turf war! Nincs annál királyabb látvány, amikor épp egy lapítós gyíkot ölsz, és egyszerre csak beront egy hatalmas dínó, felkapja, megrázza és odébb hajítja – aztán persze futás, mert te leszel a következő célpont! Ugyanis az a helyzet, hogy a szörnyek nem statikusak, hanem mászkálnak a térképen. És simán előfordul, hogy amíg az egyik főellenelet gyepálod, megjelenik a pálya másik főellenfele, és a két szörny egymásnak esik (persze túl egyszerű lenne, ha kivárnád, így random téged is megtámadnak, sőt olyan is, hogy ketten egyszerre, ami nem egy vidám történés). Egészen elképesztő, az összes ilyen párosításnak saját animációi vannak, hihetetlen látvány tud lenni egy-egy küzdelem.

Igazából ennyi maga a játék. Questet elfogadod, felkészülsz, vadászol, legyőzöd, begyűjtöd a jutalmat, fejlesztesz, és mehet újra az unalomig ismert körforgás. Viszont valahogy sikerült olyan elegyet gyúrniuk, hogy egyáltalán nem lesz unalmas, még nekem sem, pedig én aztán nagyon nem bírom az ilyen farmolós játékokat. 79 óra, és még csak 5 fegyverrel játszottam a sokból, jelenlegi 32 főellenfélből eddig 13-ra vadásztam, és ez a 13 is csak az alap, gyengébb verzió volt. Sok-sok órányi játékot látok még ebben.

Részemről 5/7!

Az eredeti komment hivatkozása: http://www.rewired.hu/comment/157194#comment-157194

Neural Networks: Why do we care and what are they?

Fórum:

Címkék:

kép:https://i.imgur.com/FC1QvBY.jpg
Neural Networks, among similarly high tech sci-fi sounding terms are used more and more commonly in the articles around the Internet.

In this article I am attempting to:
  • Give a few examples why would we care about this technology at all.
  • Demystify the terminologies like Neural Networks, Artificial Intelligence, Machine Learning and Deep Learning.
  • Classify them with simple terms, where they belong and how do they relate to each other.


Let's have a quick overview about the current state of the technology:

Amazon Go
We Stole Tampons from the Cashier-less Amazon Go Store Inditás gomb

We Stole Tampons from the Cashier-less Amazon Go Store (00:13:08)


Last Monday, Amazon opened Amazon Go, a convenience store at Seattle. Their selling point focuses on cashier-less and cashier line-less experience, to greatly speed up the whole shopping process. You enter the store by launching their app and scanning the displayed QR code at the gate. When you walk out from the store, all the bought items will be charged to your Amazon account after a few moments.

The magic of this technology is in the store. They've installed hundreds of cameras at the celling, so they can track and process every item's position, whenever you pick them up or put them back. Behind this technology is a heavy processing power and a machine learning algorithm that can track and understand what happens at the store at any moment.

Amazon used similar machine learning technologies to suggest relevant product for potential customers, based on their previous buying or browsing behaviors. This approach made Amazon the number 1 e-commerce retailer in the world.

Twitter
HIDDEN CAMERA: Twitter Engineers To Inditás gomb

HIDDEN CAMERA: Twitter Engineers To "Ban a Way of Talking" Through "Shadow Banning" (00:15:15)


Project Veritas, an undercover journalist activist group presented to the public that Twitter is perhaps using machine learning algorithms that can suppress articles, stories, tweets with certain political views and promote ones that are different kind of political views. On similar idea, Facebook announced that it will battle the so called "fake news" stories and will suppress them from our feed, preventing them from spreading around.

YouTube
YouTube Content ID Inditás gomb

YouTube Content ID (00:02:06)


YouTube is using its own machine learning technology implementation, called Content ID, to scan the content of every user's uploaded videos and find the ones that are breaking their Terms of Services and Copyright laws. By the way, Google is using machine learning for almost all of their services. For search results, speech recognition, translation, maps, etc., with great success.

Self-Driving Cars
Waymo's fully self-driving cars are here Inditás gomb

Waymo's fully self-driving cars are here (00:02:48)


Self driving cars is another emerging market for Artificial Intelligence, large number of companies are pushing out their own version of self-driving algorithms, so they can save time and money for many people and companies around the world. Tesla, BMW, Volvo, GM, Ford, Nissan, Toyota, Google, even Apple is working on their solutions and most of them aims to be street ready around 2020-2021.

Targeting ads using ultrasound + microphone
Targeting ads generally is a huge field nowadays and every ad company is trying to introduce more and more creative approaches to get ahead of the competition. One less known idea lays around the fact that the installed application can access most of the mobile phone hardware, so theoretically they can easily listen to microphone input signals. Retail stores can emit ultrasound signals from certain products and if that signal gets picked up by the app (for instance the person spend more than a few seconds in from of a certain item), it can automatically report to ad companies that the user was interested about the product, so a little extra push, in a form of carefully targeted ad may cause the person decide to buy it.

Blizzard
Blizzard announced that they may ban Overwatch players for "toxic comments" on social media, like YouTube, Facebook and similar places. Gathering and processing data this size, also making the required connections between them certainly needs their own machine learning strategies and processing power.

Facebook
Facebook patented a technology that allows to track dust or fingerprints smudges on camera lenses, this way the image recognition algorithms can recognize if any of the presented pictures are made with the same camera or not. They claimed that they never put this patented technology in use, but nevertheless it’s a great idea, with many different application possibilities from development perspective.

Boston Dynamic
Atlas, The Next Generation Inditás gomb

Atlas, The Next Generation (00:02:42)


Boston Dynamic is one of the leaders in robotics by building one of the most advanced ones on earth. They are using efficient machine learning technologies to teach their robots for doing certain tasks and overcoming certain problems.

Ok… Artificial Intelligence, Machine Learning, and Neural Networks ... what do they exactly mean and how do these terms relate to each other?

We learned that these technologies are popping out almost everywhere and becoming more and more relevant to our normal days in every aspects that we do, aiding or controlling our lives in one way or another. Reading all these “buzzwords” in technical articles around the Internet, you probably noticed that many of these terms are used interchangeably, or without any explanatory context. So let’s demystify their meaning and let’s properly categorize them for future references.

First of all, let’s clear their meaning:

Artificial Intelligence, or AI has the broadest meaning of all the three mentioned.

It usually attempts to mimic "cognitive" functions in humans and other beings, for example learning, adapting, judgment, evaluation, logic, problem solving.

Generally speaking, an AI usually does:
  • Learn - by observing, sensing, or any ways that it can gather data.
  • Process - by logic, adapting, evaluating, or judging the data.
  • Apply - by solving the given problem.
     
AI can be as simple for instance, as the ghosts in Pacman. Each have their own objectives and each tries to accomplish them by observing the player's behavior and position, so they can process that data and react upon it.

AI can be a chess player that tries to outsmart a human player.

AI can also be a search engine that gives you more relevant results to any of your search terms than any human could ever do, given the amount of constantly changing data and human behavior around the whole Internet.

Machine Learning or ML, has again many implementation and a fairly broad meaning.

Usually we can generalize the ideas behind it by stating: Machine Learning is subset of Computer Science, and its objective is to create systems that are programmed and controlled by the processed data, rather than specifically instructed by human programmers. In other words, Machine Learning algorithms are attempting to program themselves, rather than relying on human programmers to do so.

Neural Networks, or more accurately referred as Artificial Neural Networks, are a subset of Computer Science, and their objective is to create systems that resembles natural neural networks, like our human brains for instance, so they can produce similar cognitive capabilities. Again, there are many implementation of this idea, but generally it’s based on the model of artificial neurons spread across at least three, or more layers.

We will get into the details of the "how exactly" in the next article.

Neural network are great approach to identify non-linear patterns (for linear patterns, classical computing is better). Patterns where there is no clear one-to-one relation between the output and the input values. Neural networks are also excellent for approximations.

We also hear a lot about Deep Learning and that is just one, more complex implementation on the idea of Neural Networks involving much more layers. All that can create much greater level of abstraction than we normally would use for simpler tasks. Think of the complexity required for image recognition, search engines, translations.

We learned now the general meanings behind these few terms, but how do they relate to each other then?

Artificial Intelligence has been around quite some time now, and some implementations of Machine Learning is used to create much more efficient Artificial Intelligences that just wasn't a possibility before. Following this combining idea, Machine Learning is using the technologies of Neural Networks to implement its learning algorithms.

So as we can see, all of these technologies can function and work by themselves, but also they can be combined with each other to create more efficient solutions to certain problems. Most of the times however the latter is the case nowadays. All of the mentioned three technologies are combined and used together, as the currently most efficient and effective solution to the given problems: our currently most advanced versions of Artificial Intelligences are created with a Machine Learning algorithms that are using Neural Networks as their learning and data processing mechanism.
 
kép:https://i.imgur.com/oIVNOqB.png
 
In summary:
  • We were given a few examples why would we care about this technology at all?
  • We demystified the terminologies like Neural Networks, Artificial Intelligence, Machine Learning and Deep Learning.
  • We classified them with simple terms, explained where they belong, and how do they relate to each other.

In next articles I will explain in simplified steps how Neural Networks work, and will provide a programming example that any of the readers could implement and try out themselves as well. Furthermore, I will talk about the relations and differences between Artificial Neural Networks and Natural Neural Networks (our human brain, for example). I will talk about the concept of consciousness, as a natural question that tipically follows these ideas.
 

RW Top 10: Az FPS-történelem tíz legjobb shotgunja

Fórum:

Címkék:

Elhatároztam, hogy idén illően köszöntöm a szeretet ünnepét: jó sok söréttel és brutalitással! Elég régóta űzöm a szabadidőmet FPS-ek nyüstölésével,  így összeszedtem a tíz legjobb shotgunt a műfajból. A lista természetesen szubjektív, de a saját tetszési indexem mellett próbáltam az egyes fegyverek erejét, hasznosságát és tüzelési sebességét is számba venni, így biztosan kellemeset puskázhat az, aki innen választ magának partnert a harchoz. Vágjunk, vagyis inkább lőjünk bele!


10. Team Fortress 2: Scattergun / Force-A-Nature
 

A Team Fortress 2 agilis Scoutjának kedvenc fegyvere. Első ránézésre hagyományos duplacsövűnek tűnik a kicsike, de tényleg csak első ránézésre: gyors tüzelésre alkalmas ismétlőpuskával van dolgunk, aminek speciális dobtárába akár hat töltényt is belepakolhatunk. A lefűrészelt cső miatt a szórása hatalmas, így távolról nem jelent fenyegetést, közvetlen közelről azonban hatalmasat sebez, és még a felkészültebb Heavy-knek is fejtörést tud okozni.

Kicsit őrültebb verziója az unlockolható Force-A-Nature, amibe kevesebb töltény fér ugyan, viszont kétszer olyan gyorsan lehet elsütni, hatalmas visszarúgása miatt pedig shotgun jumpra is alkalmas.


9. Postal 2: Csak egy puska... macskával
 

Még most, a Steamre ömlő szemét és a Battlefront II loot boxainak korában is nyilvánvaló, hogy ha igazán ízléstelen játékra vágyik az ember, akkor a Postal 2-nél fog kiakadni a szennydetektor. Random járókelők ásóval való agyonverése? Igen! A politikailag korrekt viselkedés körbehögése? Nyilván! Hugyozás határok nélkül? Alap! Amikor először kapjuk kezünkbe a játék puskáját, még nem tudjuk, milyen extra fícsörrel kedveskedtek nekünk a Running With Scissors jómunkásemberei, de aztán összefutunk egy macskával... A gyanútlan állatot ráhúzhatjuk a fegyver csövére, és hangtompítóként használhatjuk, amíg néhány lövést követően cafatokra nem robban. Szegény cica!


8. Bioshock: Shotgun


Az Irrational Games játékának egyik legemlékezetesebb pillanata az a rész, amikor az orvosi szinten megtaláljuk ezt a kellemes steampunk-gyilkolóeköszt, hogy aztán mindjárt tesztelhessük is egy adag életünkre törő spliceren. A fegyver dörrenése számukra hívószó az örök vadászmezőkre, mivel általában már egy fejet ért találattól is kidőlnek, ha pedig mégsem, aggodalomra semmi ok: közvetlen közelre csak jól és még jobban lehet célozni. Kezdetben szűkös tárán és sebzésén gyorsan javíthatunk, a sima lőszer mellett pedig a big daddy-k legnagyobb örömére elektromos és robbanó töltényeket is használhatunk. A második legjobb fegyver a játékban, de csak azért, mert minden Bioshock-fan tudja, hogy a csavarkulcsnak nincsen párja.


7. Half-Life: SPAS-12
 

Az érzetre kitűnő mordályok mintapéldája: 1998-ban, Gordon Freeman aranykorának kezdetén nem volt még egy olyan shotgun, aminek animációi és hanghatásai megközelítették volna a SPAS-12 szintjét. Már kézbe venni és újratölteni is igazi élmény, két tüzelési módjának köszönhetően pedig nemcsak közelről, hanem közepes távolságról is hatékony játszópajtás. Elsütése után még a látszólag tonnányi lőszert magukba szívó tengerészgyalogosok sem fognak sokat ellenkezni.

A SPAS-12-től nem marad el sokkal a Half-Life 2-es változat sem, nyolc töltény viszont mindig több lesz hatnál, így egyértelmű, melyikük a jobb.


6. F.E.A.R.: VK-12
 

Mivel lehet abszolút emlékezetessé varázsolni egy egyébként is bivalyerős puskát? A Monolith szerint egy ügyes bullet time fícsörrel, és bizony nem tévednek: van valami felemelő abban, hogy még a legmagasabb nehézségi fokozaton is könnyedén csinálhatunk rántottát egy egész szobányi katonából. Szóródik a sörét, törnek a tereptárgyak, szakadnak a végtagok, a pusztítás öröme pedig betölti a képernyőt. A VK-12-nek minden egyes szava költészet.


5. Painkiller: Fagyasztópuska
 

Ha egy FPS-ben mindjárt az első szembejövő sírkőnél az ember kezébe nyomnak egy shotgunt, akkor tudja, hogy nem lesz egyszerű dolga, és ez a Painkillerben sincs másként. Daniel Garnerre csőstül ömlenek a borzalmasnál borzalmasabb pokolfajzatok, szóval fürgén kell bunny hoppolnia, ha ép bőrrel akarja megúszni túlvilági kalandját. Ebben segít ez a kellemesen ördögien festő puska, ami első blikkre csak a kisebb szörnyekre jelent közvetlen veszélyt, de ha okosan használjuk, a játék végéig hű társunk marad. Speciális töltetével a legtöbb nagyobb ellenfél lefagyasztható, majd szilánkokra robbantható, erről pedig a Pusztító (na meg a Duke 3D) óta tudjuk, hogy remek móka.


4. Blood: Sawed-off Shotgun
 

Nicsak, még egy Monolith-játék? Ezek a srácok aztán tudnak shotgunt csinálni, hiszen nem elég, hogy kétszer szerepelnek a listán, a Blood puskájával még a Build engine másik két nagyágyúját, a Duke Nukem 3D-t és a Shadow Warriort is sikerült maguk mögé utasítaniuk. Ha be kell mutatnom ezt az alattomos kis lefűrészelt csövűt, a hibátlan szó jut eszembe elsőre: feelingben és hasznosságban is ez az FPS-történelem egyik legfrankóbb fegyvere, valósággal döglenek tőle a sipákoló kultisták. A két tüzelési móddal gyors egymásutánban vagy egyszerre engedhetjük útjára a töltényeket, a sebes újratöltésnek köszönhetően pedig folyamatos tűz alatt tarthatjuk a jónépet. Erre nagy szükségünk lesz, mivel Tchernobog hívei bizony célozni is megtanultak a nagy szektázásban.


3. Wolfenstein: The New Order, The Old Blood és The New Colossus: Automatic Shotgun / Schockhammer X
 

Amikor a nácik a hatvanas években kifejlesztették az auto shotgunt, nem gondoltak arra, hogy mi van akkor, ha BJ Blazkowicz ráteszi a kezét a német precizitás eme gyöngyszemére. A válasz egyszerű: rengeteg halál és apokaliptikus tűzerő. Teljesen mindegy, mi kerül a célkeresztbe, biztosan el fog pusztulni, ha ezzel a szörnyeteggel kell farkasszemet néznie. Az auto shotgunnál még a tár mérete sem negatívum: olyan nevetséges szintre fejleszthető, hogy mire kifogyna, már bőven fekszik mindenki.

A New Colossus Schockhammer X névre hallgató fejlesztett változata még brutálisabb: rotorjának köszönhetően egyszerre három töltényt is kilőhetünk vele. Mein Leben!


2. Unreal széria: Flak Cannon
 

A flak cannon az intim szféra védelmének tökéletes eszköze: a csövéből kiáramló izzó fémszilánkok hibaszázalék nélkül darálnak apró darabokra bárkit, aki a közeledbe férkőzik. Közepes távolságból ugyan már nem halálos, lövésének véletlenszerű alakzata azonban veszélyes és kiszámíthatatlan, így a gyors visszavonulás fedezésében is kiváló partner. Már a lőszere miatt sem hagyományos shotgun, de ez az elsütése után senkit sem fog zavarni, mivel érzésre ugyanazt a kérlelhetetlen erőt testesíti meg, mint klasszikusabb társai. Másodlagosan gránátvetőként viselkedik, és annak is kiváló.

Melyik az egyetlen rossz Unreal-játék? Az Unreal 2. Melyik epizódban nem szerepel ez a csodálatos fegyver? Az Unreal 2-ben. Az összefüggés egyértelmű.


1. Doom széria: Super Shotgun
 

Az ikon, a legenda, a menő shotgunok nagypapája és példaképe. Ha valaki azzal kezdi el vádolni a Doom 2-t, hogy az nem több az első rész kiegészítőjénél, csak rá kell vágni, hogy „de abban van a super shotgun”, és máris megnyertük a vitát. Ennek jó oka van: a széria eredeti puskája is kiváló harcostárs, a super shotgun azonban ugyanolyan hasznos, miközben jóval nagyobb pusztítást lehet vele véghez vinni. A rusnya kakodémon már akár két jól elhelyezett találattól kileheli a lelkét, egy zombikkal teli szobát pedig eggyel is simán ki lehet üríteni. Ereje annyira tekintélyt parancsoló, hogy még a minden más fegyvert „brutálisabbá” varázsoló Brutal Doom sem tudott javítani rajta. Ezt elvárni sem lehetett volna Sargeant Mark IV kiváló modjától, hiszen ami tökéletes, az tökéletes, és a lista első helyét érdemli.


+1. Quake Champions: „Starting Shotgun”
 

Mivel a Quake Champions jelenleg early accessben tengődik, a végleges verzió megjelenése pedig látszólag még nagyon messze van a kaputól, így a listára már nem fért fel a játék legnagyobb anomáliája, a kezdőfegyvernek választható shotgun. A Quake első részében a sima puska bizony iszonyúan gyenge és jellegtelen volt, itt viszont túlkompenzáltak az id Software-nél: lehet, hogy a „starting shotgun” nem sebez akkorát, mint a pályákon felkapkodható kétcsövű fajta, a szórása viszont jóval kisebb, így egész egyszerűen sokkal hasznosabb fegyver nagyobbik testvérénél. Nem mondanám, hogy ideális egyensúly, de ettől még kiváló érzés veszélyesnek lenni respawn után.

Kimaradt volna valami? Valamelyik kéziágyúnak előrébb kellett volna végeznie? Előfordulhat, hiszen ahány FPS, annyi shotgun és eltérő kedvenc, szóval kommentekben jöhetnek más elképzelések, esetleg ötletek további top 10-es listákról. A tűzerő legyen veletek!

​RetroWiRED: Outcast

Fórum:

Amik a '80-as években a side-scrollerek és platformerek vagy a '90-es évek közepétől az FPS-ek azzá váltak mára a nyílt világú akció-kalandok. A legmenőbb műfajok egyike, melyből valamirevaló kiadónak kell saját frencsájz. És különben is, négyzetméterekben magasztalható játéktér és karakterfejlesztés kötelező mindenbe, mert punktum! (És lootboxok, ja, az más téma, most hagyjuk inkább.) A '90-es évek második felében azonban mindez még teljesen másképp nézett ki, még szerencsétlen GTA is csak felülnézetből kínált remek mókát. Pedig mindenből kétségbeesetten próbáltak 3D-s játékot csinálni, a korszellembe az is beleillett volna, ha Side-scroller 3D néven adnak ki valami torzszülöttet. Az eredmény: baltával faragott grafika, idegesítő irányítás, trollkodó kamerakezelés mindenütt. Persze a jobbak már akkor is tűrhetőbben csinálták, de sokat kellett küzdenie az új trenddel a 2D-s dicsőséghez szokott konzervatív játékosoknak. Vagy azoknak, akik egész egyszerűen a gördülékeny élményhez, a csiszolt játékokhoz szoktak. A nagy homokozók korai szárnypróbálgatásai közé tartozott az 1999-es Outcast is, a belga Appeal remeke, és hiába bukott, az egyik legjelentősebb előképe lett később csúcsra jutó hullámnak, aminek azóta is isszuk a levét.
 
 Nem a véletlen műve, hogy filmes poszternek álcázza magát a játék dobozborítója (forrás: Mobygames)
 
A játék története ott indul, hogy hősünk, Cutter Slade egy tudóscsoportot kísér át egy párhuzamos univerzumba, mert ahogy azt minden klisékódex előírja, az interdimenzionális portált nyitogató kísérlet leheletnyit balul sült el, és mindjárt itt a világvége, hiába van még egy rakat lap a maja naptárban. Tengerészgyalogosból rövidesen megváltóvá vedlünk át, amikor a túloldalt, Adelphán arra térünk magunkhoz, hogy mi vagyunk az Ulukai, aki most már két világnak, bennük az embereknek és talanoknak is az egyedüli reménysége. Hajdanán valahol a 90%-ánál maradt abba a messianisztikus küldetésem, tavaly sok év után újrakezdtem a modern rendszerekre újrahangolt 1.1-gyel, hogy adjak a nosztalgiának, és idő felkészüljek az igazi feldolgozásra, a minap befutott Second Contactra.

Kezdjük mindjárt a külcsínnel, mert mégiscsak ez volt az, ami szanaszéjjel büntetett már első ránézésre is mindent. A játék motorja híres arról, hogy legalábbis részben voxeles technológiát használt, így a lekerekített formák egészen döbbenetesnek hatottak akkor, amikor Croft kisasszony másodlagos nemi jellegei védőszemüveg nélkül még monitoron át is gond nélkül kiszúrták az egyszeri játékos szemét. De a vízualitással (tudom, ezért bünti jár) is képtelenség volt betelnem, a nagyobb dózisban csobogó H2O látványa mindent vitt. Egyáltalán elképesztő volt ebben a nagy, szép és szabad világban mászkálni, még akkor is, ha az egykori maximális 512x384-es felbontás visszalépés lett volna már akkor is, ha támogatásra talált volna nálam. Így maradt a 400x300, miközben jellemzően 800x600-ban játszottam akkoriban, de még így is olvadoztam a végeredménytől. A töltési idők alatt mondjuk inkább szunyókáltam, de 64 MB RAM-mal már villámgyorssá volt tehető. Abból régen 3D-kártya nélkül tudtam erényt kovácsolni, hogy legalább a procim nem volt kínos, de ezért utólag is benyújtották a számlát. Ugyanis bár már felhúzható felbontás a mai szintre, de a régi CPU-hajcsár engine-nek hála az én i5-ömmel be kell érnem 720p-vel, ami manapság a remélem komoly, mert viccnek durva lenne kategória. Jó, azt el kell ismerni, hogy ezzel a régi grafikával ez igazán sokat nem számít, még csak a pálmafák erezetéről sem ezért maradtam le. Az viszont csak természetes, hogy ma már az állak maradnak a helyükön, ez nem egy időtálló pixelcsoda, nagyon is avíttasan és egyenetlenül tud kinézni. A hajdanán eseménynek számító gömbölyű formákhoz pedig, lássuk be, felnövögetve már volt idő hozzászokni.
 
Az NPC-k inkább együttélnek a játékkal, mint -halnak, és tudják is mi a dolguk, ha "véletlenül" megjelenik rajtuk egy öklömnyi célzópötty
 
Nemcsak a szemek, de a fülek ingerét is igencsak meggyőzően szolgálta ki a játék. A Moszkvai Szimfonikusok előadásában élvezhetjük Lennie Moore zenéjét, mely méltán számít a saját kategóriájában klasszikusnak, jómagam kevés játék muzsikáit hallgattam ennyire rongyosra. Megjegyzem, az alapbeállításokon valami hihetetlen módon nem stimmel a hangerő, de némi csúszkatologatás után csak sikerült megoldani, hogy az NPC-ket, a mordályokat és a hegedűszót is megfelelően halljam. Üt még mindig, leginkább azzal tudnék csak belekötni, hogy úgyszólván szinte már túlságosan is „nagyotmondó” a játékhoz, de ezt inkább bóknak szánom.

Mindennél meghatározóbb volt azonban az átélt, mi több, átjátszott szabadság, a – közhellyel szólva – élő-lélegző világ. Élmény a különböző éghajlati jellemzőkkel bíró területek között utazni, azokat bejárni. Vagy legalábbis az volt. Manapság ugyanis méretekben már olyannyira sikerült meghaladni az Adelpha-cafatokat, hogy megmosolyogtatóan gyorsan bejárhatók. A játék határozottan nem cső, de már messze nem hat gigászinak, mint annak idején. Különösen jót lehet azon mulatni, amikor Okasankaarban, a vizes világban köpésre vannak egymástól a szigetek, és miközben az út hosszúságán méláznak az átvezetőben, a kikötőtől méterekre siklunk el – a videóban és a valós pozíciónkat tekintve egyaránt. Az összevissza ténfergő, életüket élő NPC-k ugyan már akkor sem számítottak újdonságnak, de 3D-ben ezt korábban nem nagyon sikerült ilyen hatékonyan visszaadni, inkább csak más nézetekből. Gondoljunk például az itt elmaradó napszakváltásokat is tudó Ultimákra. Az újabb áttörés pedig 2001-ben ment végbe, amikor egy másik európai kiscsapat játéka, egy bizonyos Gothic vált kultklasszikussá, és mosott le immerzióra mindent (tényleg mindent), beleértve – valljuk be – az Outcastot is. Összességében az atmoszféra most is ott van, a világ igéző, de most már ennek az átérzéséhez nem árt egy jó adag nosztalgiafaktor sem, ha saját emlékek nincsenek, akkor pedig egy kis retrósznobizmus – mert régen minden jobb volt, még a rossz és közepes játékok is! – segítheti a rózsaszín szemüveg felcsatolását.
 

Adelphán a twon-ha az ember és a talan legjobb barátja
 
Ahogy azóta is, akkor is küzdöttek ennek a nagyon tág és kulimászos határú műfajnak a képviselői, hogy összefésüljék a különböző mechanikadarabkákat valami értelmezhetővé. Ott van például mindjárt a Quantic Dream szárnypróbálgatása, a kortárs Omikron: The Nomad Soul. Abban a mászkálós kalandot, ami mellett a bénácska, minijátékérzetet bunyós és lövöldözős rész szinte értelmezhetetlen színvonalú volt. Így lehet ugyan érdekes játékot alkotni, de konzisztenst és jól játszhatót nem. A mai napig ezt látjuk, amikor az Assassin’s Creed és bármely rokona borzasztó felszínesnek hat, ha véletlenül külön-külön nézi az ember a felsorakoztatott mechanikákat. Az öregedés tehát garantált. De az igazi nagy 3D-s szabadságot biztosító akció-kalandnak az Outcast volt számomra az áttörés, a csoda. A mai napig elmondható, hogy a különböző elemek illesztékei között a lehetőségekhez képest meglepően kevéssé látszanak Frankenstein doktor öltései, mint oly sok más esetben.

Az adelphai homokozás azért is nem válik vontatottá, mert a világ méretei – ahogy már említettem – nem túl nagyok már, ráadásul akár több hátat is szerezhetünk a különböző helyszínek bejárására a portálok és saját teleportációs eszközeink pedig szintén instant élménnyé teszik az utazást. Lóti-futi persze akad bőven, hiszen itt a talanok, ahogy a hősöket illik, postásnak nézik. De hát ésszel játszva nyilván akkor érdemes másfelé venni az irányt, ha már több munkával is haladt a csicska hős, így máris kevésbé feltűnő a Fedex-átok.


Nem erre van kitalálva a játék, de FPS-ként is mehet az akció
 
A nézdahátam lövölde (mely mellesleg FPS-esíthető, sőt kvázi felülnézetig kizoomolható) a saját barátságos elvárásaimhoz képest is meglepően folyékony, bár én kellően empatikus tudok lenni a játékmúzeum-szökevényekkel. Ahhoz képest viszont mindenképpen jól teljesít, hogy abban a korban bár létezett a TPS műfaj, de – MDK ide vagy oda – igazi standard nélküli próbálkozások voltak, melyek megközelítőleg sem rendelkeztek az FPS-ekhez hasonló státusszal. Ehhez képest itt elég jól működik, de hozzá kell tenni, hogy a lézeres célzással az ellenségre húzó fegyverek mai szemmel egy konzolos akciójáték érzetét adják vissza, hiába volt 1999-ben PC-exkluzív egerészős játék az Outcast. Nem is volt hát nehéz dolguk az 1.1-gyel, ami látszólag a legkérdőjelesebb rész lehetett volna a kontrolleres irányítást tekintve, az remekül működik, sőt azt érzi az ember, hogy ennek ilyennek kellett volna lennie mindig is, vagyis a megjelenést meg nem élő tervezett Dreamcast-port működhetett volna. A játék azonban az állíthatatlan nehézség szint ellenére sem vért izzasztó egy kicsit is rutinosabb játékos számára. Hajdanán az alappisztollyal persze meg kellett küzdeni a komolyabb ellenfelekkel, de a megfelelő fejlesztésekkel és az erősebb fegyverekkel játszi könnyedséggel lehet ízekre szedni bárkit. Míg az első pisztolyunk mindössze tárbővítést kap, más fegyverek alternatív tüzelési módokat is: a második számú pisztolyszerűségünkből például lehet géppisztoly vagy lőhet pattogó lövedékeket. Ma már nevetek azok, hogy valaha kihívásnak tűnt. Némi odafigyeléssel ellenfeleink csigaként vánszorgó lövedékei között magabiztosabban szlalomozhatunk, mint Cutter Slade Neo lenne. Ugyan az újabb területek a kezdetinél erősebb ellenfeleket is hoznak, de ahogy folyamatosan rávesszük a zsarnokkal szembeni sztrájkra a talanokat, úgy gyengíthetjük is őket, ami már csak a bosszantóan gyorsan újratermelődő őrjáratok miatt sem árt.

Ami a feladványokat illeti, mindig azt szerettem, hogy többnyire logikusak és életszerűek. Akkoriban éppen csúnyán megorroltam a hagyományos, point ’n’ click kalandokra, konkrétan a Monkey Island 2 adott akkora pofont, hogy duzzogva olyan mosolyszünetet tartottam velük, amit azóta is bizonyára kukoricán térdepelve emlegetnek. Így őszinte örömmel fogadtam a kézzelfoghatóbb élményt. Azóta én is változtam, és bár nem kérkednék azzal, hogy okosabb lettem, de míg a kritizáltak kevésbé fognak már ki rajtam (vagy legalábbis könnyebben találok végigjátszást az interneten), az Outcast már túlságosan könnyű (persze már tudom mit kell csinálni, de akkor is kevésbé kell gondolkodni), mondhatni jól beleillene a mai fősodratba is a szint, bár quest marker és szájbarágás nélkül talán mégse. Mert az utóbbi hiányzik, mindent a karakterek mondanak el nekünk, ugyanakkor a küldetésekben a naplónk, az angolon túli (igen, itt kibővül a világnyelv értelme, de komolyan) talan kifejezésekben pedig egy lexikon van a segítségünkre. Az egész játékra az jellemző, hogy ha mi magunk tényleg fel akarjuk fedezni, akkor minden könnyen evidenssé válik. Ha azt várjuk, hogy felfedeztesse magát velünk, akkor viszont nagyot kell csalódnunk, viszont azt is el kell ismerni, hogy néhány NPC-t könnyű elkerülni elsőre. Eljátszhatjuk a messiás helyett a pusztítót is, de sok köszönet nem lesz benne, ha az NPC-k nem segítenek, a fontos karakterek halála pedig azonnal a játék végét jelenti.
 

A lebegve lobogó lángok titkát őrző terembe csak buggal lehet bebocsátást nyerni 
 
A játék nagy erényei közé jegyzem fel az ügyesen áramvonalasító megoldásokat is, amelyek jól épültek be a sci-fi lore-ba. Az automatikus térképező berendezésünk például kijelzi az ellenséget vagy a gyógyítókat, és meglepően hasznos, mégsem hat játékon kívüli csalásnak, mert teljesen természetesnek tűnik a megvalósítása miatt, hogy efféle segítséggel bizony rendelkeznünk kell. Szintén normálisnak tűnik így, ahogy a felszedhető cuccokra felhívja a figyelmünket, de hogy a minden egyes újratermelődő kristálynál vagy fémdarabkánál hallgatni is kell, hogy azt bemondja, az idővel éppen annyira szórakoztató, mint a StarCraftban néhány másodpercenként hallgatni, hogy nincs elég pylonunk, csak itt kevésbé létkérdés maga az információ is. Én például azért vettem fel számolatlanul a kiszúrt javakat, hogy kussoljon végre, és már direkt arra törekedtem, hogy megelőzzem a mantráját. Végül is így is lehet motiválni a gyűjtögetést, főleg a sok újratermelődő nyersanyaggal. A kedvenc húzásom viszont az, hogy mindenki, a legutolsó NPC is megszólítható, ha nem nevesített karakter, legalább az általános információs köröket le lehet futni vele. És még valamit, ami máshonnan szinte bántóan hiányzik: útbaigazítást lehet kérni a keresett karakterekhez, ilyenkor elmondják, hogy merre találjuk, milyen messze van, esetleg mozgásban van-e, ha a közelben lófrál, rá is mutatnak, vicces is, amikor a falon át mutatják az irányt.

A játékban még tutorial is akad, ami a Half-Life menetelése idején már korántsem volt meglepő. Sikerült azt beleszőni a sztoriba is, az alapok elsajátítására éppen elég, és ha a lopakodós rész nem megy, az sem gond, ha sokat bénázunk, az instruktorunk összekacsint velünk, és inkább behazudja, hogy sikerrel vettük az akadályt, mint az égéseink nézésével kínozza magát. Az az igazság, hogy lopakodásra sokkal több szükség később sem lesz, ahogy az ökölharc is marad olyannyira haszontalannak, ahogy elsőre tűnik. A használati tárgyakhoz, fegyverekhez gyorstalpalót nem kapunk, kénytelenek leszünk próba útján kiismerni őket. Vagy felütni a kézikönyvet, ami éppen akkoriban kezdett erősen kikopni a divatból, de valójában a kor RPG-ihez és stratégiáihoz még mindig erősen ajánlott volt (sokkal inkább, mint az Outcasthoz), és valójában ott vannak benne a szükséges információk, melyeket a játékban obskúrus nevek mögé rejtett tárgyakról tudni érdemes.


Az operatőr most elég kretén módon tartja a kamerát

A világ háttere nem túlbonyolított, de ahhoz éppen eléggé kidolgozott és konzisztens, hogy felkeltse az érdeklődést, egyúttal magyarázatot kínál a felmerülő kérdésekre, furcsaságokra. A gyakran önreflektív humor és főleg Cutter szarkasztikus-cinikus akcióhősöket idéző beszólásai garantálják azt a könnyedséget, amire szükség van, még az is értelmet nyer, hogy a megváltójuknak miért kell visszavásárolnia a saját felszerelési "szent" tárgyait. Sőt még arra is odafigyeltek, hogy az állás elmentése is játékon belüli legyen, és egy Gaamsav nevű kristályba tudjuk elmenteni a pillanatnyi állapotunkat, ami azonban egyáltlaán nem azonnali, és hanggal jár, ezzel lebuktatva minket a közelben ólálkodó ellenség előtt. Ugyanakkor a női (fő)szereplővel való civódások szavatossága már lejárt, annak idején is voltak játékok legalább más műfajokban, melyek jobban csinálták (pl. Broken Sword), ma meg már elég sablonos kötelező gyakorlatnak hat. A konkrét sztorival is az a baj, hogy az sem annyira lenyűgöző már, mint amilyennek régen tűnt. Minden érdekessége és a jó ötletek ellenére a fordulatok nyilvánvalók (talán a végén van egy, a vártnál bevállalósabb történés, de természetesen spoilerezés az nuku), a főgonosz a taglalt motivációi ellenére is egysíkú. Vele szemben a legtöbb nevesített mellékkarakter még mindig egyéniség tud lenni, többnyire a szórakoztató, ritkábban a kissé fárasztó fajtából. Ahhoz, hogy legalább a zsánerhez mérten újra nagy számként élhessem át, mint régen, az egész megérdemelne egy alapos, "mélyítősebb" átírást, mert a potenciál ott van benne. Azt már mondani sem kell, hogy az egykor filmnek ható párbeszédeket és többi passzívabb jelenetet már távolról sem evidens elképzelni nagyvásznon.
 
Nem hallgathatom el viszont az Outcast legidegesítőbb vonásait sem. Hiába az önreflektív utalások és a világépítés, az nem elég mindenre. A talanok soraiban ugyanis nincsenek nők és gyerekek, mind egy külön világban élnek, tehát csak férfiakkal találkozhatunk – és még egyvalakivel. Ez számomra most már inkább bosszantó, mint poén, de a fő gond az az, hogy ez mekkora spórolást leplez. Alig néhány különböző kinézetű idegen polgárral találkozhatunk, és ebben benne vannak a nevesítettek is. A shamazok (afféle papok, gyógyítók) is mind ugyanúgy néznek ki, csak a ruhájuk színének árnyalata különbözik. Ha mindehhez hozzávesszük, hogy mennyi vadidegen névbe futunk bele… Szóval alig azonosíthatóvá válnak a karakterek, mert egyedi kinézettel nem bírnak, és többnyire beazonosítható nevük sincs, ha mégis, akkor is kereshettük a klóntengerben Obalokót és Umulgalót. Ha valami, ez határozottan nem erősíti az immerziót, a történet átélhetőségét. És ebből látszik, hogy a fentebb méltatott útbaigazítás nemcsak ügyes, de kifejezetten szükséges elem is a játszhatósághoz, mert nélküle rövid távon az őrület lenne a sorsa az egyszeri játékosnak.

A játék sosem volt bugmentes, könnyen el lehetett akadni akár sok óra után is véglegesen. Ahol én annak idején elakadtam, abba most is belefutottam, de fogalmam sincs, hogy bug-e, vagy direkt indokolatlanul lassan reagál a játék egy bizonyos tettünkre. Mindegy, átverekedtem magam rajta, és szerencsére az 1.1 tényleg problémamentesebb, mint a régi verzió, az 1.1. előtt modern gépeken még a GOG-os verzióról is újra és újra lepattantam technikai okokból.  A legkomolyabb problémának végülis az bizonyult, hogy a régen is elérhetetlen 100%-os teljesítés, így az achievementek egy része sem hozható össze, mert nem hiszi el a játék. Ez van, ezt azért túl lehet élni. Amikor viszont a napokban feltettem újra, hogy lövök képeket belőle, mert a korábbiakat eltüntettem, azzal szembesültem, hogy a Steam-felhőből kettő kivételével az összes mentésem eltűnt. Nem tudom, hogy kinek a hibája ez, de ebbe még sosem futottam bele, ráadásul ezekkel is sikerült új, bár a világot nem összedöntő bugokat előcsalogatnom.
 
A Second Contact miatt is joggal vetődik fel az egyébként is nyilvánvaló kérdés: megállhatja-e az Outcast a helyét 2017-ben? A legújabb iterációról természetesen nem most nyilatkozom, de annak is eljön az ideje. Viszont éppen azért aggódom miatta, mert az alapokat már kikezdte az idő. Ha egy mondatban kellene összefoglalni: az Outcast most is egy remek kaland tud lenni, melyben melyben korát megelőzően és autentikusnak hatóan vonták össze a narratívát, a világot és a cselekményt, erős sármmal, és ha kissé hullámzó minőségű, de mégiscsak szórakoztató poénokkal és beszólásokkal fűszerezték azt meg. Ugyanakkor a legtöbb húzását, ami miatt új és friss volt a játék, már megismételték sokszor, többnyire jobban, nagyobban is. Nem az a játék, amit ma fenntartások nélkül ajánlok pótlásra, mert más klasszikusokhoz képest sokkal kevésbé van esélye akár megközelítő élményt is nyújtani, mint a maga idejében. De az arra fogékony retrógyomrúak számára minden hibája mélyén még mindig ott vannak azon erényei, ami csak különös, érdekes és sajátos bájjal rendelkező kalanddá tette. Azonban az egész üvölt egy tisztességesen modernizált verzióért, legfőképpen egy valódi, teljes értékű remake-ért (vagy folytatásért), hogy minél fogyaszthatóbb legyen, és ne csak a régi rajongók tudják csillogó szemmel játszani.

Beszámoló: Wolfenstein II: The New Colossus

Fórum:

Talán nem túlzás azt állítani, hogy 2014 egyik legnagyobb meglepetése a Wolfenstein: The New Order volt, több szempontból is. Egyrészt a fejlesztőstúdió első játéka volt – a volt Starbreeze Studios-os fejlesztőktől ugyan számítani lehetett a korrekt minőségű munkára, ám a sikert a pedigré sosem garantálja. Plusz meglehetősen hányattatott előélete volt a szériának, ugyanis a 2009-es epizód, ami ráadásul már a második reboot volt, eléggé nagyot bukott – a kritikusok és a játékosok többsége is általában egy átlagos produktumként tekintett rá, az okkultista náci vonal már rókabőr szagú volt, és sokan gyűlölték a hatalmas, hubszerűen kialakított várost, amiből a sztori előre haladtával lehetett elcsatangolni az egyes missziókra.
 
Ezek után valóságos atomcsapásként hatott a New Order: nem elég, hogy az előző rész sztorijának elemeire építkeztek, még ugrottak is egyet az időben, hogy a játékos (és a főhős) egy nácik által uralt világban térjen magához, ahol az atombombát a Harmadik Birodalom dobta le New Yorkra, és fejlett technológiájának hála, már a csillagok meghódítása felé kacsingat a rezsim. A játék alá tolt dizájn, a néhol ironikus felhangok, egy kiváló, emberré kerekített Blazkowicz, a remek zene, az id Tech 5 lehetőségekhez mérten kiváló használata, együttesen végül egy olyan egyjátékos kampányt eredményezett, mely nemcsak visszarakta a térképre a frencsájzt, de egyenes utat biztosított a további folytatásoknak.
 
 
Megmutassam a… gyermekjáték-kollekciómat?
 
A játékmenet gyakorlatilag az előző részben lefektetett alapokat követi, de persze vannak változások. A főhadiszállásunk ezúttal a náci hadigépezet meglovasított ékköve, egy hatalmas tengeralattjáró, melynek bizonyos részei le vannak zárva, és csak a sztori előre haladásával nyílnak meg, ahogy költöznek be új emberek/cserélődik a legénység. Lesz rajta egy sztorimisszió is, de egyéb tevékenységeink miatt is hangsúlyos a helyszín.
 
 
Összesen hat mellékküldetést érhetünk el rajta, melyek közül három triviális, míg három a játékmenetet erősen befolyásoló szerkentyűkhöz (contraption) kapcsolódik. A játék felétől elérhetővé váló eszközök közül az első egy páncélszerűség, amivel alapvetően falakat törhetünk át, dobozokat törhetünk szét, vagy nekifutva az ellenfeleknek, meg is ölhetjük őket. A gólyalábakkal addig elérhetetlen helyekre is eljuthatunk, az összehúzó szerkentyűvel pedig nagyon szűk helyeken mászhatunk keresztül. A fő képességek mellett van két másik előnye is a szerkezeteknek (pl. a páncél birtokában nem esünk el, ha a közelünkben felrobban valami), és egy negyediket pedig az előbb említett mellékküldetésekkel aktiválhatunk. Ezek a főhadiszállás egy addig lezárt részére visznek el, és érdemes is megcsinálni őket, mert a jutalom jelentős (páncélregeneráció, a túltöltött élet visszacsökkenésének elhagyása, hosszabb idő összeszűkült állapotban).
 
Perk is kapcsolódik a szerkentyűkhöz, melyek azok felvétele után válnak fejleszthetővé. Ha már itt tartunk: ezek a fejleszthető képességek egymástól teljesen függetlenek, és alapvetően az adott játékstílusunkra erősítenek rá. Minden perk öt szintet fejleszthető, és egyre erősebb bónuszt ad. Pl. ha duálfegyveres módban szeretjük irtani a nácikat, akkor bizonyos számú ellenfél e módon való megölése után, 20%-kal több muníciót vihetünk magunkkal, ami ötödik szinten már duplázza a kezdeti mennyiséget. Persze egy ilyen perk egy fegyvert forgatva is jól jön, így nem árt előre kinézni a nekünk kellőket, és azokat gyorsan felszintezve élvezni azok előnyeit a saját gyilkolási stílusunkkal.
 
 
Fontos még, hogy a sztori során egy ilyen szerkezetet kapunk csak, a továbbiakat az Überkommandant missziók során lehet összeszedni. Ezzel pedig el is érkeztünk a játék sztori utáni részéhez, a maximalista gyűjtögetők Mekkájához. A wolfos arany, meg egyéb biszbaszok gyűjtögetésének már hagyománya van, és itt sem kell csalódnia az erre vágyóknak. A felvehető olvasnivalók mellett (melyek egyébként jópofa adalékai a lore-nak), aranytárgyakat, hírességek kártyáit, koncepcióképeket, gyermekjátékokat (Max Hass részére), halálkártyákat, illetve lemezeket gyűjthetünk. Ezeket lehet a sztori alatt is felszedegetni, de mivel amúgy sem tudunk mindent összeszedni, érdemes a kampány lezárultával koncentrálni az összeszedésükre.
 
Található ugyanis egy haditérkép a főhadiszálláson, melyen plusz missziók érhetőek el. Ezek megnyitásához a sztoriban kell előre haladni (de annak végeztével is elérhetőek, sőt, az egyik csak akkor érhető el), és összeszedni az Enigma-kódokat. Utóbbiakat a náci tisztek dobják, mind a sztori, mind a mellékküldetések alatt. (A tiszteket amúgy már csak azért is megéri minél hamarabb eltenni láb alól, mert egyrészt riadót fújnak, másrészt halálukkor felfedik a térképen a gyűjthető cuccok helyét). Az Enigma-kódokat összegyűjtve a sztori második felétől elérhető dekódolóval tudjuk feltörni a magas rangú tisztek tartózkodási helyét. Ez gyakorlatilag annyit jelent, hogy a meghatározott darab kódot beadva a gépbe (listáról választunk egy tisztet a megadott kódszámért), előjön egy minijáték (egyszerű ábrapárosítás), amelyet megoldva a haditérképen mehetünk is levadászni az illetőt. Ezek a missziók a sztoritérképeken játszódnak, de általában azért van némi változás rajtuk (pl. nappal helyett éjszaka, ha volt tűz korábban, akkor mostanra kialudt, stb.). A leginkább átalakított talán B. J. családi otthona volt, aminél a sztori alatti napos, nyílt vidék ellenében, a mellékküldetés alatt éjszaka, ködben, falakkal körbekerített filmforgatási helyszínre térünk vissza. Plusz általában az ellenkező irányban kell végigmenni a térképeken. Ilyenkor már elérhető az összes gyűjthető cucc, ráadásul ha az Überkommandantokból összeszedhető összes halálkártyát begyűjtjük, kapunk egy plusz missziót, teljesen eredeti helyszínnel.
 
 
A főhadiszálláson található még pár időtöltési lehetőség trófeavadászoknak, pl. van egy lőtér, ahol a legjobb pontszámra lehet hajtani, illetve egy ’killhouse’, amiben egy akadályokkal megrakott terepen kell végigmenni, lelőve az ellenségtáblákat, és a legjobb időt futni (illetve a trófeához a második legjobbat).
 
Ami még a játékmenettel kapcsolatban kimaradt, az az, hogy a fegyverek ismét fejleszthetőek. A pályákon található upgrade kiteket kell magunkhoz venni, és három-három ponton javíthatjuk őket. Ez lehet hangtompító, távcső, sebzésnövelés, tárkapacitás-növelés, vagy gránátoknál plusz effekt (pl. elektromos kisülés robotok ellen). Ezeknek nem muszáj aktiválva lenniük, ha kell, ki is kapcsolhatjuk őket (a gépkarabély pl. távcsővel nem tud sorozatot leadni, így ha nem akarunk épp messzire lövöldözni, érdemes is levenni ilyenkor). Lesz továbbá egy fegyver, melyet a sztoriban az elején megejtett választás függvényében kapunk meg, a másik meg elérhetetlen lesz. Az egyik a lézerfegyver (mely ugyan leolvasztja a leolvasztható felületeket, de konkrét lyukat már nem vághatunk vele), a másik egy dízellel töltött, robbantható csomagocskákat lövöldöző stukker. Az alaparzenál mellett felvehető még négy, ideiglenesen hordozható fegyver a náci szuperkatonáktól, amikkel lassabban mozgunk, cserébe még effektívebbek tudnak lenni, ha nagyüzemű aprításra kerül a sor.
 
 
Grafika, hangok, bugok
 
Kezdjünk a legjobbal, ez a zene. Mick Gordon bábáskodott ezúttal is a muzsikák felett, amikből a konkrét játék alatt korrekt, ám nem túl kiemelkedő taktusok szólalnak meg (azért amikor tüzet fújó acélparipánkon lovaglunk, akkor a zene is rásegít az élményre :). Az extratávot viszont ezúttal is legyalogolta hűsünk, ugyanis a gyűjthető bakelitek esetében nem csak értelmetlen szemetet szedünk össze - fülbemászó, és mindenképp különleges élményt adó, igazi zenékkel ajándékozott meg minket a mester, melyeket az említett lemezekkel nyithatunk meg. Mindenképp jár érte az elismerés.
 
A grafikáért a legutóbbi Doomban debütált id Tech 6 felel, aminek következményeként az év egyik legdögösebb látványa kel életre monitorunkon – már ha újabb AMD-s VGA dohog a PC-nkben. Történt ugyanis, hogy a Tech 6 egy nagyobb ráncfelvarrást kapott a háttérben, az AMD pedig (látva a Vulkan API alatt látott teljesítménynövekedést a kártyáikon) beállított egy táska pénzzel a kiadóhoz, amik így együtt azt eredményezték, hogy egy középkategóriás AMD kártyán akár a legmagasabb minőségben lehet játszani 60+ FPS mellett. Viszont aki Nvidia-tulaj, annak meg fog gyűlni a baja a játékkal, a Steam-fórumot böngészve, se vége, se hossza az ilyen kártyát birtoklók sirámainak. Ehhez még hozzá lehet tenni azt is, hogy az OpenGL-támogatást kivették a motorból, így aki régebbi kártyával akarna próbálkozni alacsonyabb részletesség mellett, annak előbb be kell újítania egy új hardverbe.
 
 
Bugokkal egyébként én nem nagyon találkoztam. Az egyik az volt, hogy aszinkron compute mellett a grafika kimerevedett, míg a hangok mentek tovább, azt kikapcsolva ez megoldódott. A másik az volt, hogy néha a lelőtt ellenfelek belelógtak a tereptárgyakba/falakba. Ezen felül még azt hiszem New Orleans környékén volt olyan, hogy párszor kifagyott a játék (összesen talán kétszer), illetve a progiból való kilépéskor volt, hogy befagyott a játék, és feladatkezelőből kellett kilőni.
 
 
Terror Billy hazatér
 
A sztoriról nem akarok sokat elárulni, de azért annyit mindenképp megjegyeznék, hogy a játék felénél látható fordulat valószínűleg az év egyik legnagyobb meglepetése, én teljesen elképedve néztem, mikor megtörtént. Ez a közjáték egyébként elég sok dolgot megváltoztat – Blazko halni akaró, kivénhedt csatalóként viselkedik addig, aki a két gyerekét váró Anyától próbál távolodni érzelmileg. Utána viszont nincs megállás, maximális fokozatra kapcsol a forradalom. B. J. egyébként ezen epizód alatt ízig-vérig emberré válik, minden félelme, esendősége, múltjának pillanatai felszínre kerülnek, és talán ez az egyik legnagyobb erőssége a játéknak. Mellette pedig a többi karakter is hasonlóan kiválóra sikerült: Anya (akinek a végén van egy nagyon erős jelenete, azt is mindenképp látni kell, játéktörténeti pillanat), Horton, Fergus stb., mind emlékezetes lesz, köszönhetően a jól megírt dialógusoknak és a vérprofi szinkronoknak.
 
A játék elején egyébként újra le kell játszani az előző rész választásos pillanatát, amelynek hatása, hogy eltérő karakterek lesznek mellettünk, ezáltal pedig eltérő animációkat kapunk a sztori folyamán. Mindenképp dicséretes, így a DLC-kre várás közben gyakorlatilag mindenki újrázhatja a játékot, akár teljesen más stílusban (a lopakodás most is valós alternatíva a progiban).
 
Mindent összevetve, az idei év egyik legjobb játéka az új Wolfenstein, mely csak annyiban okozott meglepetést, hogy a készítők nem okoztak csalódást. Magas nehézség mellett kellően biztosít kihívást, a hozzám hasonló gyűjtögetők pedig akár egy végigjátszás alatt már bele tudnak tenni 40+ órát a játékba (az I am death incarnate! önmagában elég időrabló a rengeteg halál miatt). Ajánlani viszont egyelőre inkább csak AMD-s VGA-tulajoknak tudom, a többiek mindenképp várjanak még pár hetet. Viszont amint stabilizálódott a játék új driverek és patchek következtében, senki ne habozzon sokat, mert nagyon megéri a pénzét az alkotás.
 
9/10

A Warhammer 40,000 világa kókuszdióhéjban #38: Necromunda bolygója

Fórum:

Az Araneus-térséget a Technológia Sötét Korában, nagyjából a huszonöt-huszonhatodik évezred táján lakta be az emberiség. Bányászatra és ipari termelésre épülő kolóniákat hoztak létre a Sol rendszerhez relatíve közel található, hat rendszerből álló területen. Mint kiderült, a rendszereket ismeretlen eredetű warp-kapuk kötötték össze, amik lehetővé tették, hogy a lassan önállóan is űrjáró technológiát kiépítő rendszerek kapcsolatban maradjanak egymással. Az Istencsászár eljövetelének idejére az Araneus-térség techno-nemesi házak uralta birodalom volt, amely kölcsönösen mit sem tudott egymásról az Ember Birodalmával. Ez a Császár Nagy Kereszteshadjáratának vége felé változott meg. Az Impérium egy kisebb, nem különösebben felfegyverzett flotillája, miután eltévedt a warpban, véletlenül a techno-nemesek egyik félreeső protektorátusa közelében lépett vissza az anyagi világba. Mielőtt még újabb warp-ugrást hajthattak volna végre, a kis hajókat támadás érte. Kibernetizált katonák szálltak át rájuk, és csakhamar elfoglalták őket: ám asztropatáik eddigre üzenetet tudtak küldeni minderről a Sol rendszerbe.


Asztropatikus segélykiáltás

Terra küldöttséget menesztett az újonan felfedezett emberi csoportosuláshoz. Olvasóim tudják, hogy az Ember Birodalma ekkor ereje teljében volt, és javában foglalta el az egész Galaxis valamennyi emberlakta, vagy emberi életre alkalmas világát. Araneus nemesei viszont csak annyit tudtak, hogy őket, akik több ezer éve uralkodnak az általuk ismert rendszerek felett, megkereste valami önjelölt uralkodó, akinek az első találkozáskor különösebb erőfeszítés nélkül foglalták el a hajóit. Meghallgatták a követek javaslatát, mely szerint térjenek meg a Császár kebelére, leplezetlenül kinevették a követeket, majd miután visszanyerték komolyságukat, ők is ajánlatot tettek: ha behódol, és adót fizet, ez a Császár teljes jogú tagja lehet Araneusnak, és élvezheti az ő fejlett technikájuk, és a velük való kereskedelem előnyeit.

A Császár olyannyira méltányolta ezt a nagyvonalú ajánlatot, hogy mindjárt bőkezű ajándékkal válaszolt, a Hetedik Gárdista Légió és kisegítő erői képében. Hashin Yonnad parancsnok, híres hadvezér, és számos hadjárat hőse, a rend teljes harminckilencedik házának élén látott neki a térség pacifikálásának. Flottája Tallarnnál gyülekezett. Az Öklök húszezer gárdistáját millió és millió halandó katona, sok ezer hadihajó, titánok, és skitarii hadosztályok támogatták. Hashin Yonnad keményebb diókat is feltört már kisebb haderővel, és bár óvatosan, átgondoltan nyomult előre, bizony két hónap múltán a körülzárt központi rendszer kivételével a teljes Araneus-térség az övé volt. A maradék techno-nemes vezetők készek voltak a megadásra.


Az Öklök a csatamezőn

Ekkor azonban minden résztvevő fél számára váratlan dolog történt. A warp-kapu rendszer beszakadt, és a kapukból valami ismeretlen dolog áramlott ki. Valamennyi rendszert támadás érte, mégpedig azonosítatatlan xeno forrásból. Az Öklöket és szövetségeseiket elsöpörte a példátlanul ádáz támadás. Hashin Yonnad fogcsikorgatva úgy döntött: a rendszerek többségét sorsára hagyja, hogy a maradékot esélye legyen megvédeni. Ez a veterán parancsnok minden tudását latba vetve lassította le az idegen áradatot, de megállítani még ő sem tudta. Amikor végül már csak a központi bolygót tartották, vállvetve a maradék techno-nemes sereggel, végül úgy látta, nem kockáztathatja meg, hogy ez az ismeretlen ellenség továbbterjedjen. Inváziója kezdetén minden eshetőségre készen aláaknázta a warp-kapukat, és most működésbe hozta a tölteteket, elvágva magát minden segítségtől, de talán csapdába ejtve itt az idegeneket. Meglepő módon azonban a kapuk megsemmisülésével a támadók egyszerűen eltűntek. 

Sem Hashin Yonnad, sem az Araneusiak, de még Terra lordjai sem értették a dolgot - a Császár pedig nem kommentálta. Mindenesetre, bár a központi rendszer túlélte a kettős inváziót, a térség többi világa teljesen romba dőlt. Maga Araneus Prime is árnyéka volt egykori önmagának. Az egész bolygót beborító város üszkös rom volt csupán, mely felett mérges égéstermékek köde örvénylett. Mindössze kaptárvárosainak viharvert tornyai emelkedtek ki többé-kevésbé épen a pusztaságból, fentről tekintve a félhalott világra. Ekkor kezdték azon a néven emlegetni, amelyen máig hírhedt: az élőholt bolygó, Necromunda.


Ez ugyan nem Necromunda, de jól visszaadja a szennyezett felszín fölé magasodó kaptárváros hangulatát

Funkciója nem változott számottevően. Az Impérium azóta is ugyanúgy ipari termelésre használja, és az eltelt évezredek alatt szárazra facsarták valamennyi nyersanyagforrását. Manapság így a régi korok hulladékát éli fel: a törmelékből jut alapanyagokhoz, és olykor értékes, régi technológiához. A bolygó felszínét mérges ipari hamu borítja, mely felett ugyancsak korrozív gázokkal terhes szél fúj. A légkör mérgező része fölé magasodnak a hatalmas kaptár-tornyok, melyeket megerősített vasutak kötnek össze - ezek időnként visszaverik a hamupusztákhoz alkalmazkodott mutáns hordák támadásait. A lakosság túlnyomó része azonban a tornyokban él. Létszámuk messze-messze túlhaladja azt, amit a bolygó el tudna tartani, szükségleteiket bolygóközi importból fedezik Necromunda urai. A vezető nemesi házak a tornyok felső emeletein tanyáznak: ők friss levegőt szívnak, valódi ételt esznek, és olykor még az égboltot is látják. A kisebb házaknak, lejjebb, már csak újrahasznosított élelem és levegő jut, kisebb és rosszabb minőségű élettér, őalattuk az ipari és kereskedelmi rész helyzete még rosszabb - de ők még így is abszolút luxusnak élik ezt meg, mert tudják, hogy még ők is a torony felső részében laknak, viszonylagos biztonságban, rendben, és többé-kevésbé biztos a napi betevő falatjuk. Az alsóbb részek azonban egyre régebbiek, állapotuk egyre rosszabb. Omladozó fémbarlagok szövevényén folyik át a felső szintek ipari szennyvize, felette agyonhasznált levegő kavarog. Potenciális nyersanyagforrásnak is tekinthető, halálosan veszélyes elhagyott iparterületekért, vagy csak egy falat újrahasznosított élelemért csapnak itt össze az alsóbb szintek lakói, akik a túlélésért mind valamelyik Ház bandáihoz csapódnak. A sikeresebb bandák több évig is túlélnek, a még sikeresebbek felszerelik magukat legyőzött ellenfeleik eszközeiből, és pénzzé tett javaik ellenértékéből. Némelyikük még a Háza figyelmét is felkelti, és nagy ritkán feljebb jutnak a ranglétrán, ezáltal a kaptár-toronyban is. Többségük azonban fiatalon meghal valahol egy elhagyatott folyosón, egy golyó, lézerlövedék, valamilyen ipari mérgezés, az omladozó fémlabirintusban bekövetkező baleset, vagy valamilyen fertőzés következtében.


A kaptár lakosságának legnagyobb része ilyen élettereken tölti a rendszerint igen rövid időt, ami megadatik neki

A legnagyobb, és legfontosabb kaptártorony a Primus torony, ismertebb nevén a Palatinus. Utóbbi nevét onnan kapta, hogy a csúcsán ékeskedik a Helmawr ház palota-komplexuma. Innen uralja világát a bolygó kormányzója, Lord Gerontius Helmawr. Számtalan fiatalító kezelés és kibernetikus beültetések következtében immáron hosszú évszázadok óta Necromunda teljhatalmú ura ő. Mindaddig, amíg a Dézsmát időben beszolgáltatja, bírja az Impérium támogatását, és hogy ez mekkora túlerőt jelent, azt Necromundán soha nem fogják elfelejteni. Cserébe részt ád Terrának a még mindíg hatalmas termelőkapacitásból, ami a rendelkezésére áll, sőt, ezt túl is tudja teljesíteni: a többi terméke értékesítéséből komoly vagyona, befolyása van Impérium szerte. Ezen felül fejadót is fizet: a kaptárok lakosságának egy bizonyos százaléka a birodalmi sereget erősíti. Egyfelől a sereg a lehető legjobb emberanyagot követeli, másfelől a katonák életszínvonala messze túlhaladja az átlagos kaptárlakóét, így ők maguk is logikusnak tartják, hogy vetélkedni kelljen ezért a magas tisztségért. Ezért aztán az újoncok rendszerint Lord Helmawr saját seregéből kerülnek ki. Ezt kifelé bolygóvédelmi alakulatnak nevezik, odahaza azonban csak Pókoknak vagy Csúcslakóknak hívják őket. Valójában ez a legnagyobb és legerősebb banda, akik hosszú generációk óta tartják uralkodó pozíciójukat, ezáltal szavatolva Lord Helmawr kegyét. Ő rendet tarttat velük a kaptártoronyban, cserébe a magasabb emeleteken szállásolja őket, jobb ellátmányt, fegyvereket, és kibernetikus beültetéseket biztosít nekik. A Pókok hűsége így megkérdőjelezhetetlen, ütőképességük pedig - saját jól felfogott érdekükben - igazolja rémisztő hírnevüket.


A kibernetizált, harci drogokkal ellátott Pókoktól még a legelvetemültebb bandák is tartanak

A legfelsőbb emeleteken találhatóak továbbá az űrkikötők, melyek szintén Lord Helmawr kezében vannak, ezáltal szavatolva űrszállítási monopóliumát - uralmának egy újabb eszközét. Egy kivétellel. Itt található ugyanis az Öklök rendjének egyik kolostorerődje, amely nem csak a bolygó védelmét szavatolja, de a bandaháborúk gyorsította természetes szelekciót kihasználva a rend toborzóhelye is. Ha egy bandatag igazi csúcsragadozójává válik a kaptárnak, olykor emlékeztetőt kap róla, hogy még mindíg csak halandó: az Öklök felderítői levadásszák, és elragadják az erődbe, hogy gárdista-jelöltet faragjanak belőle.
Vaskos fallakon és ellenőrzött kapukon túl, lejjebb, de még mindíg a csúcs közelében tanyáznak a főnemesi házak. Ezek gyakorlatilag semmit sem termelnek, tevékenységük szinte száz százalékban a hatalom öncélú hajszolására illetve megtartására irányul, házasságok, szerődések, manipuláció, politika, és hasonló szép eszközök útján. Valamennyien versengenek Lord Helmawr kegyéért: akire a lord rámosolyog, már a puszta presztízs okán értékes szerődéseket szerezhet, míg akiről csupán a pletyka elterjed, hogy elfordult volna tőle, arra a többi ház máris éhes cápaként veti rá magát. Példa rájuk a hírhedt Ulanti ház.
Újabb fal mögött, és újabb néhány mérfölddel lejjebb már a kisebb házak birodalma húzódik. Ezek alattvalói végzik a tényleges termelést, mindegyikük más és más specializált szektor mestere. Olyan régóta van ez így, hogy mára már ránézésre is különöznek egymástól, alkata, kiállása, no meg persze jellegzetes öltözéke és díszei messziről elárulják valakiről, melyik házhoz tartozik. Mindőjük saját fegyveres erejeként használja a nekik felesküdött bandákat, és úgy politikai-gazdasági, mint titokban fegyveres harcot is folytatnak egymással területekért, erőforrásokért, illetve a régi sérelmek okán. 


A Cawdor ház címere, és Klovis, a Megváltó

A Cawdor ház a Vezeklés Szektájának erőssége. Ennek tanai szerint az Istencsászár meghasonlott az emberiség bűneitől, ezért folyamatos vezekléssel kell őt engesztelni, hogy haragját elkerüljük. Aki pedig nem tesz így, ne adj Istencsászár nem osztaná a szekta tanait, az eretnek, akit ki kell purgálni, mielőtt még rájuk hívná az Ő haragját. A szekta más házak hívei között is jelen van, de a Cawdor házban hivatalos vallás, továbbá előszeretettel támogatják a hittérítőket mások területein is, különösen ha azok az adott térség urai ellen prédikálnak. Érthető módon ez nem javítja a ház kapcsolatát a többivel. Tanaik értelmében arcukat nem mutatják meg idegeneknek, így ijesztő mintájú maszkokat, és csukját hordanak. Hivatalosan nem tagja a háznak, de támogatásukat élvezi Klovis, a Megváltó, ez a hírhedten fanatikus, erőszakos, és hatékony szektavezér.


A Delaque ház címere, és egy tipikus Delaque bandatag

A Delaque ház közeli kapcsolatot ápol Lord Gerontiuséval, és nem csupán termékeikel látják el, de információval is. Ők ugyanis kémek. Minden házban, sőt, minden üzemegységben megvannak az embereik, semmi sem történhet a tudtuk nélkül. Hírnevüket megjelenésük is alátámasztja. Hagyományosan sötét területeikhez igazodott, fényérzékeny szemeiket sötét szemüveg, vagy implantok védik, hosszú kabátjaik számtalan zsebében fegyverek és csempészáruk lapulnak. Bőrük sápadt, fejük kopasz, hangjuk rekedt, suttogó.  


Az Escher ház címere, és Őrült Donna Ulanti

Állítólag az Escher ház vegyipari monopóliumának kellemetlen melékhatása, hogy az Escher férfiak csökevényes roncsok. A házat így teljes egészében nők irányítják. Ádázak, rátermettek, és büszkék, és nagyon rosszul viselik ha valaki lenézi a nőket - ez nem használ a hagyományosan macsó Goliath házzal való kapcsolatuknak. Kedvez viszont az Orlock házzal valónak, akikkel nem hivatalos szövetségesek. Bár az Ulani ház szülötte, de technikailag mégis inkább Escher híresség Őrült Donna, az alsó kaptár hírhedt nőstényördöge.


A Goliath ház címere, és egy bandatagjuk, aki az alsó szintek egy mutáns szörnyével végzett éppen

A Goliath ház területein az élet nehezebb, mint a többi házén, amire ők büszkék. Szemükben a szívósság, de főleg a nyers erő, és a termet mindennél fontosabb, lenézik a nyiszlett okostónikat, és bizonyos mértékben a nőket is. Felpumpált fizikumú nehézfiúik duzzadó izmaikat amennyire csak lehet közszemlére teszik, modern barbárként mutatkoznak, és legtöbbször viselkednek is. Punktaréj, tüskés bőrpántok, láncok jellemzik öltözéküket, míg gladiátorvermeik és életre-halálra vívott párbajaik sokat elárulnak társadalmukról.


Az Orlock ház címere, és egy emberük

Az Orlock ház a vasról híres, amelyet a területüket képező salakvermekből nyernek ki. Ebben a salakban még mindíg van annyi érc, amivel el tudják látni kohóikat, és azok termékeiből élnek. A salak kitermelése időtlen idők óta zajlik, így előfordult már, hogy kaptárrengéshez, helyi omlásokhoz vezetett, az így keletkezett hatalmas üregek okán. Hagyományosan nagy gavallérok a nőkkel szemben, és igen jó kapcsolatot ápolnak az Escher házzal. Nem így a Delaque-al. Hoszzú ideig amazok szállítottak ugyanis a főnemes Ulanti háznak, ám aztán Orlock pénzen bérelt bandák felrobbantottak jópár stratégiai fontosságú vezetéket a kaptár alsó szintjein. Ezek Delaque gyárakat tápláltak addig, és kiesésükkel a ház nem volt képes betartani szerződéses vállalását, az Orlock pedig a helyükre léphetett. Ez hosszú-hosszú ellenségeskedéshez vezetett, melynek során jóval később Delaque orgyilkos végzett Lord Hagen Orlockkal is. A hidegháború azóta is csak fokozódik.


Van Saar végrehajtó, és a ház címere

A Van Saar ház gyártja a legjobb minőségű termékeket. Busás összeget ér bármi, amit az ő mesterembereik készítettek. Nem csoda hát, hogy a ház igen vagyonos. Végrehajtóikat könnyű felismerni teshezálló kezeslábasukról, amelyek védik viselőjüket az extrém környezeti hatásoktól, és jelzik is azokat - előfordul például olyan példány, amelynek egy része elszíneződik, ha mérgező a levegő, így viselője és társai időben észreveszik azt. A ház tagjai jellemzően igen komoly, már-már sótlan emberek, akik mély tiszteletben tartják a rendet, rendszert, hierarchiát. A Van Saarhoz hűséges férfiak között divat az ápolt szakáll. Hozzáértésük okán a Birodalmi Sereg előszeretettel sorozza be a ház tagjait technikusnak.

A negyvenedik évezred közepe táján lezajlott Drypus incidens jól szemlélteti, hogyan is zajlik a politikai élet a házak és bandáik között: A már említett értékes Ulanti szerződés irányába, mint láttuk, megnyitotta az Orlock ház útját a már tárgyalt szabotázs. Ám, bár a szerződéshez tartozó erőforrások és területek jó része tulajdonjogilag az Ulanti ház birtokában volt, és a Delaque ház csak használhatta azokat a szerződés okán, mégsem voltak hajlandóak átadni őket a szerződéssel együtt. A területeket lezárták, aláaknázták, vagy blokád alatt tartották. Ez nyilván nem tett jót az eleve feszült helyzetnek. 
Mármost az Orlock ház saját erőből is meg tudta volna oldani a nyersanyagok utánpótlását, nem rendelkeztek azonban a szükséges üzem-és robbanóanyaggal, már csak azért sem, mert ezek folyását elapasztotta a Delaque blokád. Az akkori Orlock vezető, Második Lord Ammonus Orlock tucatnyi bandát küldött hát, tulajdon fia vezetésével, hogy átvegyék az uralmat a Drypus forrás felett, ami üzemanyagban gazdag volt. A Delaque ház visszavonulni kényszerült, de tettek róla, hogy ha az övék nem lehet a forrás, más se termelhessen ott. Felgyújtották az üzemanyagot, felrobbantva ezáltal az egész forrást. Számtalan Orlock bandatag és még több munkás veszett oda.


Ezt már a kormányzó sem hagyhatta szó nélkül. A Helmawr ház érdekei azonban ekkoriban számos helyen egyeztek a Delaqueéival, ami kényes helyzetbe hozta. Nyíltan elítélte hát a házat, és minden szerződést megsemmisítettek kettejük között, titokban azonban éppen hogy támogatásáról biztosította, és a kieső bevételeket meghaladó összegeket ígért, ha a Helmawrok nem hivatalos kémei lesznek. Ugyanakkor szankciókkal sújtotta az Orlock házat is - újabb gesztus a Delaque felé. Mivel, úgymond, nem tudtak rendet tartani a bandáik között, száműzette velük a forráson rajtaütő Orlock erők maréknyi túlélőjét. Ezek között volt Kagil Orlock is, a ház fejének örököse, így nem csoda, hogy vonakodott eleget tenni az ítéletnek - Lord Helmawr (Gerontius őse) azonban tudatta velük, hogy ez az Ulanti szerződés megvonásával járna. Lord Ammonous háza nem bírta volna el az annyi vér árán kicsikart paktum elvesztését, így nehéz szívvel engedett a nyomásnak.
A Delaque és Orlock házak kapcsolata azóta is egyre feszültebb, míg az előbbi és a Helmawr házé azóta is szoros, bár titkos. Az Ulanti ház pedig mit sem törődik vele hogy hányan haltak meg értük, és óramű pontosan behajtja a szerződésében szereplő javakat.


A Necromundai Nyolcadik Regiment katonái pók szimbólummal jelölték meg tankjukat

A bolygóról újoncozott katonák is híresek.
A nemesi házak, különösen az Ulanti, híres tiszetket adtak az Impériumnak: Hito Ulanti főhadnagy például nem kisebb személynek, mint Lord Solar Machariusnak, az Impérium szentjének volt a jobb keze.
Ami pedig a közkatonákat illeti, a seregbe Necromundáról besorozott bandák már eleve összeszokott osztagokat alkotnak, és ezt a hasznos köteléket a sereg sem szokta széttépni. Más bakáknál gyakrabban rendelkeznek kibernetikus beültetésekkel, általában megbízhatóan értenek számos közelharci-és távolsági fegyverhez, és elvitathatatlan a városi harcban szerzett tapasztalatuk, így kiképzésük, és a számukra kiválasztott célpontok is építenek erre. A Necromundai Regimentek katonáinak többsége a Pókok közül kerül a seregbe, és előszeretettel tetováltatnak arcukra pók jelet, ezért a leginkább illusztris nyolcadik regimentjük is a Necromundai Pókok néven híresült el.


Kétszeresen is veterán katonát díszít a póktetoválás: a kaptár bandaháborúi után a birodalmi sereg túlélője is 

A Nyolcadik hősiességéről számos történet szól ugyan, ám sajnálatos módon ezek szinte mind a halálukkal, és az újraalapításukkal végződnek. 
Lord Solar Macharius halála után erői között polgárháború tört ki, és a császárhű oldal katonái vissza kényszerültek vonulni Deucalion bolygójáról. A támadókat sajnos az Alfa légió beszivárgói segítették, így átcsúsztak a részben árulónak bizonyult bolygóvédelmi erőkön, és ágyúik bombázni kezdték a sereget éppen amikor a legsebezhetőbb volt: amikor felszállásra vártak a csapatszállítóikban. Raevan Mortz ezredes és a Pókók nélkül az egész hadsereg ott pusztult volna: ő azonban, miután elesett felettesétől átvette a parancsnokságot, kitört a Nyolcadikkal a kikötőből, és a sűrűn beépített bolygó számukra otthonos felszínén az ellenséges tüzérség ellen vezette a Necromundaiakat. Öngyilkos akciója elnémította annyi időre az ágyúkat, hogy a sereg többi része fel tudjon szállni, köztük Solon hadúrral, a császárhű erők fővezérével, aki hosszú idő után megnyerte a polgárháborút.
Hasonlóan felemelő, de szomorú szerepet töltöttek be a Cicatrix Maledictum kitörése utáni időszakban is. A Mordia közelében található Stygius bolygót, amit hősiesen tartottak árulókkal és démonokkal szemben, elnyelte a warp, elemésztve szinte a teljes Nyolcadig regimentet.


Ez a szép szál deli legény nem Lord Gerontius Helmawr, de nagyon hasonlít

Ahogyan ezután az Immatérium áradása elvágta a híres-hírhedt bolygót a külvilágtól, megingott Lord Gerontius pozíciója is. Ahogy nyilvánvalóvá vált, hogy a potentát immár nem számíthat Terra erejére, a házak azonnal áskálódni kezdtek ellene, és a Helmawr ház csakhamar háborúban állt - mindíg másokkal, ahogyan a vén róka Gerontius ígéretekkel, fenyegetésekkel, manipulációval egymás ellen fordította, maga mellé állította, vagy csak hamis célpontok ellen irányította vélt és valós ellenfeleit. A Pókok bevetése, és az, hogy az Öklök gárdistái a kormányzó mellett álltak, bizony megfontolandóvá tette a Helmawr ház nyílt megtámadását, és a lord éveket nyert, de a végtelenségig ő sem tudta elodázni az összecsapást. Minőség tekintetében mindenképpen a kormányzónál volt az erőfölény, a kaptárvárosok lakossága azonban olyan elsöprő mennyiségű bandának adott otthont, ami idővel áttörte az ellenállást, és a Palatinus legfelsőbb szintjeire kényszerítette őket. Mielőtt azonban végleg szorult volna a hurok, végül hírét vették, hogy Lord Protektor Roboute Guilliman a rendszer felé tart seregével. Necromunda lakóiban soha el nem halványuló nyomot hagyott az a bizonyos ősi eset, amikor uraik ujjat húztak az Impériummal. A lázadás úgy szűnt meg, mintha soha el sem kezdődött volna. Lord Gerontius szokásos körmönfontsággal szabott ki büntetéseket, vagy éppen hagyta függőben őket, hadd féljenek tovább. Megérdemelt, és meg nem érdemelt, de stratégiailag előnyös jutalmakat osztott. Nemeseket végeztetett ki, vagy ami még rosszabb, fosztott meg vagyonuktól és vetette a többi martalékául, míg másokat előnyösebb helyzetbe hozott. Szerződéseket vont meg és kötött újra. Munkálkodása eredményeként visszaállt a sok száz évig megszokott, kipróbált status quo: a Lord Protektor már a megszokott állapotában találta a híres-hírhedt bolygót, amikor megérkezett.


A cikk az új Necromunda megjelenése előtt íródott, így könnyen lehet, hogy a benne írtak néhány hónap múlva elavulnak, de legfeljebb majd írok még egyet :-)

További 40K cikkek

REWiRED - Kutyus felfedő szétszéledés - 2014-2057 © Minden Jog Fenntartva!
Virtuális valóság és Kecskeklónozó központ - Oculus MegaRift - PS21 - Mozi - 4D - Bajuszpödrés
Médiaajánlat/Borsós Brassói Árak
Rohadt Impresszum!