home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
linuxmafia.com 2016
/
linuxmafia.com.tar
/
linuxmafia.com
/
pub
/
palmos
/
unlicensed
/
wabburami.java
< prev
Wrap
Text File
|
2000-12-01
|
20KB
|
754 lines
//
// Wabburami.java
//
import waba.ui.*;
import waba.fx.*;
import waba.sys.*;
import extra.ui.*;
import wabadma.ui.*;
import wabadma.util.*;
/**
* The classic game of Hammurabi for the JavaOne 1999 KVM.
*<P>
* Play the part of the ruler of ancient Babylon with this
* great-great-great-granddaddy of empire building games.
*<P>
* The foundation of this Spotlet is Sun's Rumor game that was
* distributed at the 1999 JavaOne developer conference; all the event
* and text handling comes directly from that code. Everything else
* was converted from the C version of the game (see below). I won't
* claim that the coding is incredibly clean or well-implemented, but this
* is more a demonstration that an ordinary Java engineer can write a
* functional KVM application than anything else (although there's no
* data access of any kind).
*<P>
* Based on C code from the Open License Software Supplement (Skunkware)
* that I found at ftp.sco.com/skunkware/ and seemed to me to be close enough
* to the original version (in BASIC?) to use as the basis for this code. : )
*<P>
* TODO:
*<LI> Add saving of high scores and perhaps game state in a .pdb file.
*<P>
*
* @author Jim Lesko -- Jim@MartianWind.com * @version 0.9
*
* version 0.9w: 07 Nov 2000
* modified into waba by dmarcher@pobox.com
*
*/
public class Wabburami extends ExtraMainWindow {
static String TITLE="Wabburami";
static String VERSION="0.9w(b10)";
static String VERSIONDATE="2000 Nov 07";
static DLWRandom r;
// UI objects:
MenuBar mb;
//static Button newButton; // unused
static Button exitButton; // exit the game
static Button doneButton; // done with turn
static Button buyButton; // buy acres
static Button sellButton; // sell acres
static Button plantMaxButton; // plant Max. acres
static Button feedNeededButton; // feed Min. Needed bushels
static Button plantRbButton; // plant using Remaining bushels
static Button feedRbButton; // feed Remaining bushels
static Button bsPlusButton; // increase buy/sell #
static Button bsMinusButton; // decrease buy/sell #
static Button feedAcresButton; // feed min. bushels to tend acres
static Button plantAvgButton; // plant min. so avg. yields feeds all
static NumericEdit buysellEdit; // # of acres to buy or sell
static NumericEdit feedEdit; // # of bushels to feed people
static NumericEdit plantEdit; // # of acres to plant
static OutputBox out;
static Label statusLabel;
// UI state:
static int lineAscent;
static int lineHeight;
FontMetrics fm;
// Game variables:
static boolean playing;
static boolean hard; // hard difficulty (otherwise it's easy)
static int year; // Turn number
static int acres; // Acres owned
static int bushels; // Bushels in storage
static int pop; // Population of city
static int immigrants; // How many folks immigrated
static int starved; // How many died of starvation
static int rats; // How many bushels rats destroyed
static int harvest; // Size of last year's harvest
static int acreCost; // Cost of an acre in bushels
static boolean plague; // Plagues struck this turn.
static int plagueCount; // How many died of plague
// Game finals: (some of these will probably change to vars. when
// easy/hard difficulty is added.)
private final static int PLANT_MAX_PER_PERSON = 10;
private final static int PLANT_ACRES_PER_BUSHEL = 2;
private final static int BUSHELS_NEEDED_PER_PERSON = 20;
private final static int MAX_RAT_PCT = 60;
private final static int PLAGUE_PCT = 10;
private final static int MAX_IMMIGRANTS = 50;
private final static int AVG_YIELD = 3;
// finals locating ui objects:
private final static int W=160; // Width
private final static int H=160; // Height
private final static int L=0; // Left edge
private final static int R=159; // Right edge
private final static int T=0; // Top edge
private final static int B=159; // Bottom edge
private final static int G_H=15;// generic height used by many objects
private final static int YEAR_X=120;
private final static int YEAR_Y=2;
private final static int YEAR_W=W-YEAR_X+1;
private final static int OUT_H=78;
private final static int[] LINES_A = {94,95};
private final static int OUT_Y=16;
private final static int STATUS_Y=98;
private final static int BUYSELL_Y=112;
private final static int FEED_Y=128;
private final static int PLANT_Y=144;
private final static int EXIT_Y=128;
private final static int DONE_Y=144;
private final static int[][] LABEL_LOCS =
{
{0, BUYSELL_Y, 70, G_H},
{0, FEED_Y, 55, G_H},
{0, PLANT_Y, 55, G_H}
};
private final static String[] LABEL_TXTS =
{
"Trade Acres:",
"Feed Bushels:",
"Plant Acres:"
};
private final static int E_X=55; // x of *Edit
private final static int E_W=25; // w of *Edit
private final static int ED_B_W=29; // w of Exit & Done Buttons
private final static int BS_B_W=22; // w of Buy & Sell Buttons
/*
* X Layouts: (button widths: Buy&Sell 24, Exit&Done 32, others 15)
*
* Buy/Sell Acres:
* [Label 0..69] [Edit 55..79] [- 83] [+ 99] [Buy 115] [Sell 138]
*
* Feed:
* [Label 0..54] [Edit 55..79] [ 83] [R 99] [! 115] [Exit 131]
*
* Plant:
* [Label 0..54] [Edit 55..79] [ 83] [R 99] [> 115] [Done 131]
*
*/
private final static int BS_M_X=83; // x of Minus Button
private final static int BS_P_X=99; // x of Plus Button
private final static int BUY_X=115; // x of Buy Button
private final static int SELL_X=138; // x of Sell Button
private final static int PF_A_X=83; // x of A Buttons
private final static int RB_X=99; // x of *RbButton
private final static int PLANT_MAX_X=115; // x of Plant Max Button
private final static int FEED_NEEDED_X=115;// x of Feed Needed Button
private final static int ED_B_X=131; // x of Edit & Done Buttons
private final static String aboutText =
TITLE + "\n" + VERSION + "\n" + VERSIONDATE;
//"Greetings, Wabburami.";
private final static String helpText1 =
"You have"+
" inherited control of Babylon and are charged with"+
" growing it into a great nation. You must utilize careful"+
" land management, distribute food to your subjects, and permit"+
" those subjects to tend to your crops. Rats, starvation, and"+
" plague are the enemies which you must fight.";
//"against every step of the way.";
private final static String helpText2 =
"Each year you must decide whether to buy or sell land, how much grain"+
" to feed the people, and how many acres to plant. Once you've"+
" allocated your resources by entering the appropriate amounts and"+
" tapping the 'Done' button, you will be told of the"+
" results of your decisions.";
//"The game ends only when you sell all"+
//" your land or tap the 'Exit' button.";
//"Go now -- Babylon awaits your enlightened rule.";
private final static String historyText =
"Wabburami is a Waba version of the classic Hammurabi game. Its"+
" implementation is based on the following versions:\n"+
"Focal version by ? DEC programmer\n"+
"Basic version by David H. Ahl\n"+
"C version by ? SCO contributer\n"+
"Java KVM version by Jim Lesko\n"+ //JavaOne 1999
"Waba (this) version by Dave Archer";
private final static String keyText1 =
"To save time writing digits in the 3 numeric fields, you may also"+
" use the following buttons as shortcuts.\n"+
"\nTrading Buttons:\n"+
" [-] decreases acres to trade\n"+
" [+] increases acres to trade\n"+
" [Buy] buys # of acres displayed\n"+
" [Sell] sells # of acres displayed";
private final static String keyText2 =
"Feed Buttons:\n"+
" [A] feed enough people to tend crops\n"+
" [R] feed with remaining bushels\n"+
" [!] feed enough for all people\n"+
"Plant Buttons:\n"+
" [A] plant enough for average yield\n"+
" [R] plant with remaining bushels\n"+
" [>] plant as many acres as possible";
/**
* App starts here. Need to check for saved game and/or prompt
* for new game.
*
* Currently just starts a new game.
*/
public Wabburami() {
super(TITLE); // adding ,true double-buffers but is slow
r=new DLWRandom();
fm=getFontMetrics(defaultFont);
lineAscent=fm.getAscent();
lineHeight=fm.getHeight();
String[] mls1={"File","New","Quit"};
String[] mls2={"Options","Help1","Help2","Key1","Key2","History","About"};
mb = new MenuBar();
mb.add(new Menu(mls1));
mb.add(new Menu(mls2));
setMenuBar(mb);
InitNewGame(false); // init easy game
StartGame();
}
/**
* Initialize variables for a new game.
*
*/
private void InitNewGame(boolean hard) {
this.hard = hard;
year = 1;
acres = 1000;
bushels = 2800;
pop = 100;
starved = 0;
rats = 200;
harvest = 3000;
acreCost= 0;
immigrants = 5;
plague = false;
plagueCount=0;
}
/**
* Game (new or saved) starts here. Create UI structures,
* display beginning info, and begin allowing UI events.
*/
private void StartGame() {
CreateUI();
// show first (or last) turn
showReport();
playing = true;
this.repaint();
}
/**
* Generic Button setup.
*
*/
private Button addNewButton(String s, int x, int y, int w, int h) {
Button b = new Button(s);
b.setRect(x,y,w,h);
add(b);
return b;
}
/**
* Create UI structures.
*
*/
private void CreateUI() {
// add buttons
exitButton = addNewButton("Exit", ED_B_X, EXIT_Y, ED_B_W, G_H);
doneButton = addNewButton("Done", ED_B_X, DONE_Y, ED_B_W, G_H);
buyButton = addNewButton("Buy", BUY_X, BUYSELL_Y, BS_B_W, G_H);
sellButton = addNewButton("Sell", SELL_X, BUYSELL_Y, BS_B_W, G_H);
feedNeededButton = addNewButton("!", FEED_NEEDED_X, FEED_Y, G_H, G_H);
plantMaxButton = addNewButton(">", PLANT_MAX_X, PLANT_Y, G_H, G_H);
feedRbButton = addNewButton("R", RB_X, FEED_Y, G_H, G_H);
plantRbButton = addNewButton("R", RB_X, PLANT_Y, G_H, G_H);
bsMinusButton = addNewButton("-", BS_M_X, BUYSELL_Y, G_H, G_H);
bsPlusButton = addNewButton("+", BS_P_X, BUYSELL_Y, G_H, G_H);
feedAcresButton = addNewButton("A", PF_A_X, FEED_Y, G_H, G_H);
plantAvgButton = addNewButton("A", PF_A_X, PLANT_Y, G_H, G_H);
// create a place to output text
out = new OutputBox(0,OUT_Y,W,OUT_H);
add(out);
// add static labels
for(int i=0;i<LABEL_TXTS.length;i++) {
//System.err.println("Label "+LABEL_TXTS[i]);
Label l = new Label(LABEL_TXTS[i]);
l.setRect(LABEL_LOCS[i][0],LABEL_LOCS[i][1],LABEL_LOCS[i][2],LABEL_LOCS[i][3]);
add(l);
}
// add status label
statusLabel = new Label("");
statusLabel.setRect(0, STATUS_Y, W, lineHeight);
add(statusLabel);
// add edit controls
buysellEdit = new NumericEdit();
buysellEdit.setRect(E_X, BUYSELL_Y, E_W, G_H);
buysellEdit.setInt(5);
add(buysellEdit);
feedEdit = new NumericEdit();
feedEdit.setRect(E_X,FEED_Y,E_W,G_H);
feedEdit.setInt(2000);
add(feedEdit);
plantEdit = new NumericEdit();
plantEdit.setRect(E_X,PLANT_Y,E_W,G_H);
plantEdit.setInt(1000);
add(plantEdit);
}
public void clearRect(Graphics g, int x, int y, int w, int h) {
g.setColor(255,255,255);
g.fillRect(x,y,w,h);
g.setColor(0,0,0);
}
public void onPaint(Graphics g) {
//System.err.println("onPaint");
// Year display is next to Title, not in out box
clearRect(g,YEAR_X,YEAR_Y,YEAR_W,lineAscent);
g.drawText("Year "+year,YEAR_X,YEAR_Y);
// Draw lines as per LINES_A
for(int i=0;i<LINES_A.length;i++)
g.drawLine(T,LINES_A[i],R,LINES_A[i]);
}
/**
* Update info. in status line.
*/
private void updateStatus() {
int surplus = calcSurplus();
statusLabel.setText("B: "+bushels+" P: "+pop+" A: "+acres+" Surplus: "+surplus);
statusLabel.repaint();
}
/**
* Refresh screen with this turn's info.
*/
private void showReport() {
// draw the border between the top text and the input area
//g.drawLine(0,14,159,14);
out.clear();
// Tell user how this turn went
if (plague) {
plagueCount = pop;
pop /= 2;
plagueCount -= pop;
out.println("Plague! "+plagueCount+ ((plagueCount == 1) ?
" person" : " people") +" died, "+starved+" starved,");
} else
out.println("Last year "+starved+((starved == 1) ?
" person" : " people") + " starved");
out.println("and "+immigrants+((immigrants == 1) ?
" person" : " people") + " entered the city.");
out.println("The population is now "+pop+".");
out.println("We harvested "+harvest+" bushels at "+
acreCost+" BPA.");
out.println("Rats ate "+rats+" bushels, leaving "+
bushels+".");
out.println("The city owns "+acres+" acres of land.");
acreCost = r.random(6) + 22;
out.println("Land is worth "+acreCost+" an acre.");
updateStatus();
this.repaint();
}
/**
* Events only checked while playing.
* (Presumably none of these events will get hit when not
* playing because the objects won't exist, but this also
* makes onEvent look a bit neater.)
*
*/
private void playingEvent(Event e) {
if (e.type == ControlEvent.PRESSED) {
if (e.target instanceof Button) {
// pressed buttons
if (e.target == exitButton)
endGame();
else if (e.target == doneButton)
processTurn();
else if (e.target == buyButton)
buyAcres();
else if (e.target == sellButton)
sellAcres();
else if (e.target == plantMaxButton)
plantMax();
else if (e.target == feedNeededButton)
feedNeeded();
else if (e.target == plantRbButton)
plantRb();
else if (e.target == feedRbButton)
feedRb();
else if (e.target == bsMinusButton)
modifyBs(-1);
else if (e.target == bsPlusButton)
modifyBs(1);
else if (e.target == feedAcresButton)
feedAcres();
else if (e.target == plantAvgButton)
plantAvg();
}
}
}
/**
* Checks for events. Responsible for updating state of the
* game, exiting, acknowledging errors, etc.
*/
public void onEvent(Event e) {
if (playing)
playingEvent(e); // check playing events
if (e.type == ControlEvent.PRESSED) {
// check menu items being selected
if (e.target instanceof Menu) {
String sel=((Menu)e.target).getSelected();
if (sel.equals("Quit")) {
endGame();
} else if (sel.equals("About")) {
Dialog id = new Dialog("About",0,80,160,80);
id.out.printlnCentered(aboutText);
add(id);
return;
} else if (sel.equals("History")) {
Dialog h = new Dialog("History",0,16,160,height-16,historyText);
add(h);
return;
} else if (sel.equals("Help1")) {
Dialog h = new Dialog("Help1",0,16,160,height-16,helpText1);
add(h);
return;
} else if (sel.equals("Help2")) {
Dialog h = new Dialog("Help2",0,16,160,height-16,helpText2);
add(h);
return;
} else if (sel.equals("Key1"))
add(new Dialog("Key1",0,16,160,height-16,keyText1));
else if (sel.equals("Key2"))
add(new Dialog("Key2",0,16,160,height-16,keyText2));
}
}
}
/**
* modify buy/sell acres by i
*
*/
private void modifyBs(int i) {
int v = buysellEdit.getInt();
v += i;
if (v < 0)
v = 0;
buysellEdit.setInt(v);
}
/**
* buy some acres
*
*/
private void buyAcres() {
int value = buysellEdit.getInt();
if ((value*acreCost) > bushels)
showError();
else {
bushels -= value*acreCost;
acres += value;
}
updateStatus();
}
/**
* sell some acres
*
*/
private void sellAcres() {
int value = buysellEdit.getInt();
if (value > acres)
showError();
else {
bushels += value*acreCost;
acres -= value;
}
// be nice and reduce acres being planted if needed
if (acres < plantEdit.getInt())
plantEdit.setInt(acres);
updateStatus();
}
/**
* plant maximum possible acres
*
*/
private void plantMax() {
int m;
m=pop * PLANT_MAX_PER_PERSON;
if (m>acres)
m=acres;
plantEdit.setInt(m);
plantEdit.repaint();
updateStatus();
}
/**
* try to feed everybody just enough
*
*/
private void feedNeeded() {
int m;
m = pop * BUSHELS_NEEDED_PER_PERSON;
if (m > bushels)
m = bushels;
feedEdit.setInt(m);
feedEdit.repaint();
updateStatus();
}
/**
* plant remaining bushels (after bushels used feeding people)
*
*/
private void plantRb() {
int m = ( bushels-feedEdit.getInt() ) * PLANT_ACRES_PER_BUSHEL;
if (m < 0 )
m = 0;
plantEdit.setInt(m);
plantEdit.repaint();
updateStatus();
}
/**
* feed remaining bushels (after bushels used for planting)
*
*/
private void feedRb() {
int m = bushels-(plantEdit.getInt()/PLANT_ACRES_PER_BUSHEL);
if (m < 0 )
m = 0;
feedEdit.setInt(m);
feedEdit.repaint();
updateStatus();
}
/**
* feed just enough people to tend all fields
*
*/
private void feedAcres() {
feedEdit.setInt(acres/PLANT_MAX_PER_PERSON*BUSHELS_NEEDED_PER_PERSON);
feedEdit.repaint();
updateStatus();
}
/**
* plant just enough to feed everyone with an avg. yield
*
*/
private void plantAvg() {
plantEdit.setInt((pop*BUSHELS_NEEDED_PER_PERSON)/AVG_YIELD);
plantEdit.repaint();
updateStatus();
}
private int calcSurplus() {
int feed = feedEdit.getInt();
int plant = plantEdit.getInt();
return bushels-feed-(plant/PLANT_ACRES_PER_BUSHEL);
}
private void processTurn() {
int feed = feedEdit.getInt();
int plant = plantEdit.getInt();
if (feed > bushels) {
// trying to feed more bushels than we have
showError();
return;
}
if (plant > acres ||
plant / PLANT_ACRES_PER_BUSHEL > (bushels-feed) ||
plant > pop * PLANT_MAX_PER_PERSON) {
// trying to plant more acres than we have, or
// trying to plant more bushels than we have, or
// trying to plant more than the population can
showError();
return;
}
bushels -= feed;
starved = pop - feed / BUSHELS_NEEDED_PER_PERSON;
immigrants = 0;
if (starved < 0) {
immigrants = -1 * (starved / 2);
starved = 0;
}
// Essentially, the turn's over; update state &
// figure out random events (plague):
bushels -= plant / PLANT_ACRES_PER_BUSHEL;
acreCost = r.random(5) + 1;
harvest = acreCost * plant;
int p = r.random(MAX_RAT_PCT*10);
//ratPop = r.random(600);
//rats = (ratPop * (bushels + harvest)) / 1000;
if (hard)
rats = p * (bushels + harvest) / 1000;
else
rats = p * bushels / 1000;
bushels = bushels - rats + harvest;
//plague = (r.random(10) == 0);
plague = (r.random(100) < PLAGUE_PCT);
immigrants += (5 - acreCost) * bushels / 600 + 1;
immigrants = (immigrants > MAX_IMMIGRANTS) ? MAX_IMMIGRANTS : immigrants;
immigrants = (immigrants < 0) ? 0 : immigrants;
pop += immigrants - starved;
year ++;
showReport();
this.repaint();
}
/**
* Game has ended either by user request or naturally.
*
* This is a good place to add final score, saving stats,
* that sort of thing. (But not a saved game.)
*/
public void endGame () {
playing = false;
exit(0);
}
/**
* Exit caught by VM. This is called after exit(0) in endGame,
* so when we get here, we should check the value of playing to
* see if we need to save the game.
*
*/
public void onExit() {
if (playing)
; // save game
else
; // remove old saved game
}
/**
* Let the player know that something isn't right.
*/
private void showError() {
add(new Dialog("Wabburami, Think Again",0,80,160,80,
"You do not have enough bushels, acres, or people to do "+
"as you request."));
}
}