I have been working on a new strategy game. It’s a real-time strategy game which is planned for release on Android. Ports for desktop (PC, Mac, Linux) as well as iOS will be done if proven successful.
The war game is a combination of Empires of Steel, WeeWar, Mother of All Battles by Sean O’Connor, Advance War, as well as Command & Conquer. The game will initially feature single player game play only. Please note, the graphics are not final yet. The tilesets will go out to the artist pretty soon.
The next major update for Age of Conquest will include tournament functionality! So, if you have not done so yet, I strongly advice you to practice Age of Conquest ONLINE v3. The tournaments will initially only be available for desktop (PC, Mac, Linux) and later expanded to Android.
Release Date: Feb. 2011.
1st Tournament: Free to Enter (no subscription required), US$1000 Prize Money
Also, currently underway are translations to German, French, Spanish & Japanese. If you would like to add yet another translation, please contact me for details.
My thanks go to all the contributors for their hard work!
Age of Conquest ONLINE v3 now features game signatures! The signature shows the avatar, clan, clan logo, the overall rating and season ratings (RS). The signature URL is given as follows:
Replace <username> with your Age of Conquest username. For integration into a forum, you could use the following BB Code. The code links to the homepage of Age of Conquest:
What are “triggers” are you probably asking yourself? Has he finally lost his mind? Not yet! Triggers are custom events that can be added to map scenarios. A trigger can either be shown at random or at a fixed turn. Triggers serve a game by providing “outside” events to a game, rather than everything being player generated.
The following triggers are currently available:
Announcement: to display announcements. You could for example create an announcement that will be shown at turn 2 to all players telling them to attack Rome.
Economy: you could say for turn 4, everyone will get an extra 17′000 gold in their treasury due to good economic time.
Plague: a plague has killed 87% of the human population at turn 5. Once a plague has hit, income will be reduced as less population will not be able to produce as much income.
There are currently no triggers defined in any scenario (to my knowledge?). If you are a map maker and would like to test the feature, open the map editor and fill in the corresponding fields in the “Trigger” tab. Hit test to see it live in action.
The latest update for Age of Conquest ONLINE v3 includes five additional actions. The actions are available on both Android and desktop (PC, Mac, Linux), except the call to arms function is only available on desktop at the moment. The five actions include:
Support - can be used to send gold to other empires. The functionality is limited to 40′000 gold per transaction.
Purchase - can be used to purchase neutral provinces. The provinces are rather expensive and can be acquired for 100′000 gold or more depending on the province’s value (production, population).
Call to Arms – can be used to rally troops from multiple provinces that are in range (radius 3). The troops become available the next turn. It helps prevent depletion of population on a province.
Espionage - can be utilized to spy on other empires. Functions include locating an enemy ruler, their treasury, economy or reading their messages.
Sabotage - can be utilized to steal gold from foreign rulers or reduce their morale.
[Call to Arms], [Espionage] and [Sabotage] are disabled by default and have to be set if a new game is created. [Support] and [Purchase] are new and become available also in games already in progress. [Support] and [Purchase] can be disabled as needed.
Please note, the purchases refer to the orders made through http://www.ageofconquest.com only and do not include purchases via 3rd party distributors of Age of Conquest (don’t have any numbers yet).
Age of Conquest ONLINE v3 now features an overview map. The map can be viewed during game setup and during game-play. The overview map shows the empires, economy and population sizes.
Also, please join noblemaster’s game in the Casual realm!
Beta-Testing for Age of Conquest III (standalone/single player) version is coming to a close. I just sent out the final beta-test notice to some of the testers. Please check your spam filter to find out if you are included in the final round (only Windows + Macintosh).
In other news, I am planning to release Age of Conquest ONLINE in about one month from now and need beta-testers for the online version as well. You will receive a free one year subscription to the online version for participating, plus being added to the credits. Also, you will get a headstart by getting to play around with it first. Please email me your username and operating system (Windows, Macintosh, Linux or UNIX) if you would like to participate. Send your email to contact at ageofconquest dot com.
Planned Release Date:
Age of Conquest III: Nov. 17 (GamersGate, ageofconquest.com)
Age of Conquest ONLINE: Nov. 17 (ageofconquest.com)
Release dates are pretty fixed, unless there are not enough volunteers to beta-test Age of Conquest ONLINE.
We need beta-testers for Age of Conquest III (single player standalone version). The approximate test-date is middle of October. We need a quick turnaround for testing (3 days max). Let us know if you are interested and what platform (Windows, Macintosh or Linux) you will be using.
Please contact us at the email address listed on our web site.
Thanks!
Edit I: beta-testers will appear in the game credits!
Edit II: Let’s make this a paid beta-test (PayPal ony). The whole test shouldn’t take much more than 1-2 hours. I need bug reports for Windows, Macintosh & Linux. I need 3 beta-testers for each platform (9 total). You will receive a payment of $25 for sending me the test report, plus have your name added to the credits of the game. Please email me know if you would like to participate. Let me know which platforms you can test for (you only need to do one). It’s first-come first-serve. Thanks!
Age of Conquest III will have linked users and clans. All the users and clans, wherever they appear inside the various panels will be clickable and will open an information panel.
The user information panel will contain the following components:
Information about the user such as his location, birthday, standings and awards.
A button that allows to contact the user directly via private messaging system.
Add a user to the friend list; or block the user from contacting you.
A reporting button to report suspected cheaters.
Administrators will be able to view last logins and other user related information. There is admin functionality available to administrate the user if you are an administrator.
The same will be available for clans. The clan information panel will display the clan owers, admins and honor members. Also, it will be possible to directly apply to become a member of the clan.
A beta version of the Age of Conquest Map Editor has been released! The editor features the full map editing functionality. The editor also includes and a map upload & download system. Submit your creations now!
Visit the Age of Conquest Modding Discussions & Workshop forum on the Multiplayer Hub for download and information.
I couldn’t find a good star rating component for Java Swing, so I rolled my own. The star rating component displays the current current rating (yellow stars), as well as a “selected” rating (reddish stars). The “selected” rating can be changed by a user. If the “selected” rating is changed, all the listeners will be notified of the change.
Example (5 stars, 3.78 average rating, 3 stars initial selection):
StarRater starRater = new StarRater(5, 3.61, 3);
starRater.addStarListener(new StarRater.StarListener() {
public void handleSelection(int selection) {
// a new number of stars has been selected
do something...
}
});
add(starRater); // add the component to the container...
The star rating component will initially be used to rate maps in Age of Conquest.
Here is the download for both source code & star images (Photoshop). Note that I included the star images as byte array in the source code for your convenience. You are obviously free to use your own as well. Please consider both source code as well as images in the Public Domain. If you would like to credit me for the work that’s great, otherwise, no problem either:
Age of Conquest will have a new game type available. King of the Hill will require a player or a team to hold a certain area on the map for a given time to win the game. Target flags will define the zone.
For additional suggestions, please post your ideas here in the blog!
The color selector (JColorChooser) for Java is rather ugly, so I decided to write my own color chooser. The color chooser is made up of two components:
ColorSelector: A button which displays the currently selected color and pops up the ColorSwatch when clicked.
ColorSwatch: Displays a color swatch with clickable colors. The color swatch expects a two-dimensional array of colors as input that will be displayed in the swatch.
The color selector and swatch will be used for Age of Conquest to make it more convenient to select a color in the map editor (less cumbersome). Please note, the five columns to the left are specifically designed colors for Age of Conquest to give maps a medieval look & feel. Although other colors can be chosen as well, it is recommended to use the medieval colors when creating new scenarios for the game.
Here is the code for both components. Please consider the code Public Domain. Feel free to use and modify it any way you please. Although, I would appreciate to be credited, it is not necessary to do so. Enjoy!
ColorSelector.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JPopupMenu;
/**
* Represents a color selector.
*
* @author noblemaster
* @since August 16, 2010
*/
public class ColorSelector extends JButton {
/** The default colors. */
private static final int[][] DEFAULT_COLORS = new int[][] {
{ 0xFFFFFF, 0xEEEEEE, 0xDDDDDD, 0xCCCCCC
, 0xBBBBBB, 0xAAAAAA, 0xFFCC00, 0xFF9900
, 0xFF6600, 0xFF3300, 0x999999, 0x888888
, 0x666666, 0x444444, 0x222222, 0x000000 },
{ 0x99CC00, 0x000000, 0x000000, 0x000000
, 0x000000, 0xCC9900, 0xFFCC33, 0xFFCC66
, 0xFF9966, 0xFF6633, 0xCC3300, 0x000000
, 0x000000, 0x000000, 0x000000, 0xCC0033 },
{ 0xCCFF00, 0xCCFF33, 0x333300, 0x666600
, 0x999900, 0xCCCC00, 0xFFFF00, 0xCC9933
, 0xCC6633, 0x330000, 0x660000, 0x990000
, 0xCC0000, 0xFF0000, 0xFF3366, 0xFF0033 },
{ 0x99FF00, 0xCCFF66, 0x99CC33, 0x666633
, 0x999933, 0xCCCC33, 0xFFFF33, 0x996600
, 0x993300, 0x663333, 0x993333, 0xCC3333
, 0xFF3333, 0xCC3366, 0xFF6699, 0xFF0066 },
{ 0x66FF00, 0x99FF66, 0x66CC33, 0x669900
, 0x999966, 0xCCCC66, 0xFFFF66, 0x996633
, 0x663300, 0x996666, 0xCC6666, 0xFF6666
, 0x990033, 0xCC3399, 0xFF66CC, 0xFF0099 },
{ 0x33FF00, 0x66FF33, 0x339900, 0x66CC00
, 0x99FF33, 0xCCCC99, 0xFFFF99, 0xCC9966
, 0xCC6600, 0xCC9999, 0xFF9999, 0xFF3399
, 0xCC0066, 0x990066, 0xFF33CC, 0xFF00CC },
{ 0x00CC00, 0x33CC00, 0x336600, 0x669933
, 0x99CC66, 0xCCFF99, 0xFFFFCC, 0xFFCC99
, 0xFF9933, 0xFFCCCC, 0xFF99CC, 0xCC6699
, 0x993366, 0x660033, 0xCC0099, 0x330033 },
{ 0x33CC33, 0x66CC66, 0x00FF00, 0x33FF33
, 0x66FF66, 0x99FF99, 0xCCFFCC, 0xFFFFE3
, 0xFFFFFF, 0xFFE3FF, 0xCC99CC, 0x996699
, 0x993399, 0x990099, 0x663366, 0x660066 },
{ 0x006600, 0x336633, 0x009900, 0x339933
, 0x669966, 0x99CC99, 0xE3FFFF, 0xFFFFFF
, 0xFFFFFF, 0xFFCCFF, 0xFF99FF, 0xFF66FF
, 0xFF33FF, 0xFF00FF, 0xCC66CC, 0xCC33CC },
{ 0x003300, 0x00CC33, 0x006633, 0x339966
, 0x66CC99, 0x99FFCC, 0xCCFFFF, 0x3399FF
, 0x99CCFF, 0xCCCCFF, 0xCC99FF, 0x9966CC
, 0x663399, 0x330066, 0x9900CC, 0xCC00CC },
{ 0x00FF33, 0x33FF66, 0x009933, 0x00CC66
, 0x33FF99, 0x99FFFF, 0x99CCCC, 0x0066CC
, 0x6699CC, 0x9999FF, 0x9999CC, 0x9933FF
, 0x6600CC, 0x660099, 0xCC33FF, 0xCC00FF },
{ 0x00FF66, 0x66FF99, 0x33CC66, 0x009966
, 0x66FFFF, 0x66CCCC, 0x669999, 0x003366
, 0x336699, 0x6666FF, 0x6666CC, 0x666699
, 0x330099, 0x9933CC, 0xCC66FF, 0x9900FF },
{ 0x00FF99, 0x66FFCC, 0x33CC99, 0x33FFFF
, 0x33CCCC, 0x339999, 0x336666, 0x006699
, 0x003399, 0x3333FF, 0x3333CC, 0x333399
, 0x333366, 0x6633CC, 0x9966FF, 0x6600FF },
{ 0x00FFCC, 0x33FFCC, 0x00FFFF, 0x00CCCC
, 0x009999, 0x006666, 0x003333, 0x3399CC
, 0x3366CC, 0x0000FF, 0x0000CC, 0x000099
, 0x000066, 0x000033, 0x6633FF, 0x3300FF },
{ 0x00CC99, 0x000000, 0x000000, 0x000000
, 0x000000, 0x0099CC, 0x33CCFF, 0x66CCFF
, 0x6699FF, 0x3366FF, 0x0033CC, 0x000000
, 0x000000, 0x000000, 0x000000, 0x3300CC },
{ 0x000000, 0x222222, 0x444444, 0x666666
, 0x888888, 0x999999, 0x00CCFF, 0x0099FF
, 0x0066FF, 0x0033FF, 0xAAAAAA, 0xBBBBBB
, 0xCCCCCC, 0xDDDDDD, 0xEEEEEE, 0xFFFFFF },
};
/** The rollover color. */
private static final Color ROLLOVER_COLOR = new Color(0x20ffffff, true);
/** The current color. */
private Color color;
/** The available colors. */
private Color[][] colors;
/**
* The constructor.
*/
public ColorSelector() {
this(Color.RED, getDefaultColors());
}
/**
* The constructor.
*
* @param color The active color.
* @param colors The colors to select from.
*/
public ColorSelector(Color color, Color[][] colors) {
this.color = color;
this.colors = colors;
// set background
setOpaque(false);
// listen to clicks and display popup as needed
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// create and show swatch
final JPopupMenu popup = new JPopupMenu();
popup.setOpaque(false);
ColorSwatch swatch = new ColorSwatch(ColorSelector.this.colors);
swatch.addColorListener(new ColorSwatch.ColorListener() {
public void handleColor(Color color) {
// set the new color
if (color != null) {
ColorSelector.this.setColor(color);
}
// hide the popup
popup.setVisible(false);
}
});
popup.add(swatch);
popup.show(ColorSelector.this, getWidth() / 2, getHeight() / 2);
}
});
}
/**
* Returns the color.
*
* @return The color.
*/
public Color getColor() {
return color;
}
/**
* Sets the color.
*
* @param color The color.
*/
public void setColor(Color color) {
this.color = color;
}
/**
* Returns the colors.
*
* @return The colors.
*/
public Color[][] getColors() {
return colors;
}
/**
* Sets the colors.
*
* @param colors The colors.
*/
public void setColors(Color[][] colors) {
this.colors = colors;
}
/**
* Returns the base colors.
*
* @return The base colors.
*/
public static Color[][] getDefaultColors() {
Color[][] colors = new Color[DEFAULT_COLORS.length][DEFAULT_COLORS[0].length];
for (int y = 0; y < colors.length; y++) {
for (int x = 0; x < colors[0].length; x++) {
colors[y][x] = new Color(DEFAULT_COLORS[y][x]);
}
}
return colors;
}
/**
* Returns the preferred size.
*
* @return The preferred size.
*/
@Override
public Dimension getPreferredSize() {
return new Dimension(60, 30);
}
/**
* Returns the margin.
*
* @return The margin.
*/
private int margin() {
return 3;
}
/**
* Draws this component.
*
* @param g Where to draw to.
*/
@Override
public void paint(Graphics g) {
// use antialiasing
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int width = getWidth();
int height = getHeight();
int x = 0;
int y = 0;
int margin = margin();
// draw border
getBorder().paintBorder(this, g, 0, 0, width - 1, height - 1);
// draw the color
g.setColor(color);
g.fillRoundRect(x + margin, y + margin
, width - (2 * margin), height - (2 * margin), 5, 5);
// draw effect as need
ButtonModel model = getModel();
if (model.isPressed()) {
g.setColor(ROLLOVER_COLOR);
g.fillRoundRect(x + margin, y + margin
, width - (2 * margin), height - (2 * margin), 5, 5);
g.fillRoundRect(x + margin, y + margin
, width - (2 * margin), height - (2 * margin), 5, 5);
}
else if (model.isRollover()) {
g.setColor(ROLLOVER_COLOR);
g.fillRoundRect(x + margin, y + margin
, width - (2 * margin), height - (2 * margin), 5, 5);
}
}
}
ColorSwatch.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.event.MouseInputListener;
/**
* Displays a color swatch.
*
* @author noblemaster
* @since August 16, 2010
*/
public class ColorSwatch extends JPanel {
/** The rollover color. */
private static final Color ROLLOVER_COLOR = new Color(0x80ffffff, true);
/** The listener. */
public static interface ColorListener {
/**
* Called if a color has been activated.
*
* @param color The color.
*/
void handleColor(Color color);
}
/** The listeners. */
private transient List
listeners = new ArrayList();
/** The colors. */
private Color[][] colors;
/** The rollover color. */
private Color rolloverColor = null;
/**
* The constructor.
*/
public ColorSwatch() {
this(new Color[0][0]);
}
/**
* The constructor.
*
* @param colors The colors to select from.
*/
public ColorSwatch(Color[][] colors) {
this.colors = colors;
// set look
setOpaque(true);
setBackground(Color.WHITE);
setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
// add listener
MouseInputListener mouseListener = new MouseInputListener() {
public void mousePressed(MouseEvent event) {
Color color = getColor(event.getX(), event.getY());
// notify about selection
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).handleColor(color);
}
}
public void mouseMoved(MouseEvent event) {
rolloverColor = getColor(event.getX(), event.getY());
repaint();
}
public void mouseDragged(MouseEvent event) {
// not used
}
public void mouseReleased(MouseEvent event) {
// not used
}
public void mouseClicked(MouseEvent arg0) {
// not used
}
public void mouseEntered(MouseEvent arg0) {
// not used
}
public void mouseExited(MouseEvent arg0) {
rolloverColor = null;
repaint();
}
};
addMouseListener(mouseListener);
addMouseMotionListener(mouseListener);
}
/**
* Returns the colors.
*
* @return The colors.
*/
public Color[][] getColors() {
return colors;
}
/**
* Sets the colors.
*
* @param colors The colors.
*/
public void setColors(Color[][] colors) {
this.colors = colors;
}
/**
* Returns the preferred size.
*
* @return The preferred size.
*/
@Override
public Dimension getPreferredSize() {
int colorSize = getColorSize();
int colorSpacing = getColorSpacing();
int margin = getMargin();
return new Dimension((colorSize + colorSpacing) * colors[0].length
+ (2 * margin) - colorSpacing
, (colorSize + colorSpacing) * colors.length
+ (2 * margin) - colorSpacing);
}
/**
* Returns the margin/insets from where the colors are painted. Override this method to paint the colors
* further inside.
*
* @return The margin.
*/
public int getMargin() {
return 2;
}
/**
* Returns the color for the given coordinate.
*
* @param x The x coordinate.
* @param y The y coordinate.
* @return The color or null if not found.
*/
private Color getColor(int x, int y) {
int margin = getMargin();
int colorSize = getColorSize();
int colorSpacing = getColorSpacing();
x -= margin;
y -= margin;
int col = x / (colorSize + colorSpacing);
int row = y / (colorSize + colorSpacing);
if ((col < 0) || (col >= colors[0].length) || (row < 0)
|| (row >= colors.length)) {
return null;
}
else {
return colors[row][col];
}
}
/**
* Returns the spacing.
*
* @return The spacing.
*/
private int getColorSpacing() {
return getColorSize() > 2 ? 1 : 0;
}
/**
* Returns the size of a color thingy.
*
* @return The color size in pixels.
*/
private int getColorSize() {
if ((colors[0].length <= 12) && (colors.length <= 8)) {
return 15;
}
else if ((colors[0].length <= 24) && (colors.length <= 16)) {
return 7;
}
else if ((colors[0].length <= 48) && (colors.length <= 32)) {
return 5;
}
else if ((colors[0].length <= 96) && (colors.length <= 64)) {
return 3;
}
else {
return 1;
}
}
/**
* Draws this component.
*
* @param g Where to draw to.
*/
@Override
protected void paintComponent(Graphics g) {
// use antialiasing
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int width = getWidth();
int height = getHeight();
int margin = getMargin();
int colorSize = getColorSize();
int colorSpacing = getColorSpacing();
// background fill
g.setColor(getBackground());
g.fillRect(0, 0, width, height);
// draw the colors
for (int y = 0; y < colors.length; y++) {
for (int x = 0; x < colors[0].length; x++) { Color color = colors[y][x]; g.setColor(color); g.fillRect(x * (colorSize + colorSpacing) + margin , y * (colorSize + colorSpacing) + margin , colorSize , colorSize); // draw rollover? if (colorSpacing > 0) {
if (color == rolloverColor) {
g.setColor(ROLLOVER_COLOR);
g.fillRect(x * (colorSize + colorSpacing) + margin
, y * (colorSize + colorSpacing) + margin
, colorSize
, colorSize);
}
}
}
}
}
/**
* Adds a listener.
*
* @param listener The listener.
*/
public void addColorListener(ColorListener listener) {
listeners.add(listener);
}
/**
* Removes a listener.
*
* @param listener The listener.
*/
public void removeColorListener(ColorListener listener) {
listeners.remove(listener);
}
}
Age of Conquest III will feature two new GUI components: slider and progress bar. Both components have been designed by Sergey “Serjio” Churbanov who created most other graphics for Age of Conquest III as well.