COSMOS Game (XENIX Specific), Part 02/03
Karl Denninger
karl at ddsw1.MCS.COM
Fri Nov 18 15:56:54 AEST 1988
Part 2 of 3, see part 1 for details.
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 2 (of 3)."
# Contents: Help cosmos.h drone.c torpedoes.c
# Wrapped by karl at ddsw1 on Thu Nov 17 23:53:07 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Help' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Help'\"
else
echo shar: Extracting \"'Help'\" \(13308 characters\)
sed "s/^X//" >'Help' <<'END_OF_FILE'
X************************ COSMOS On-Line Assistance **************************
X
Note: If your screen is "screwed up" your terminal type is set incorrectly.
X
X Numeric Celestial Objects on Grid
X -Pad-
X @ - Planet A-Z - Spaceship
X 7 8 9 * - A Star (Computer or Man)
X 4 5 6 <<< Move in ` - A Asteroid + - StarBase
X 1 2 3 direction , - A Mine . - Empty Space
X A Void is a "space"
b - Broadcast message
l - Fire Lasers
m - Lay a Mine
t - Fire a Torpedo + - Add another enemy ship to game
s - Raise/lower (toggle) shields
X
A - Set your alliance (unimpl.) M - Move on autopilot to coordinates
B - Build a base on a planet N - Change ship's name (if docked)
C - Capture an object (unimplemented) P - Players in game (docked) or status
D - Dock with a starbase Q - Quit (save if GREEN status)
R - Disable/Enable Ramming protection S - Scan an object in view
X
X
Movement:
X
X Basic Movement is done with the numeric keypad. Some ships can "home"
X in on a given coordinate using the "M" command. This command will
X only function in ships which include it as part of their navigation
X subsystem (first available on the Frigate).
X
X The coordinate grid is layed out in x, y, with the 'x' axis being
X the horizontal. Your current position is always displayed in the
X lower left corner of the playscreen.
X
X The "M" (capital 'm') command will take you to a destination at
X best-rate-of-travel speed if your ship is equipped with an autopilot
X (small ships lack the machinery). The autopilot is intelligent
X enough to stop the ship if there is an obstruction you would
X otherwise impact with, but not intelligent to steer around it
X automatically. Enter the destination coordinates when you use the
X "M" command with a single space or tab between them, "X" first.
X
X A "M" command entered without coordinates will use the last stored
X destination position.
X
X
Shields:
X
X These consume energy when in use. When your shields are up,
X the shields will take the damage (in percent operability) before
X your main energy stores and the remainder of the ship are affected.
X If your shield level drops to zero or below, your shields will
X be "blown down" and you will suffer damage from this as well as the
X hit which causes the shields to drop (as they are no longer functional).
X
X Shields provide some protection against collisions.
X
X You may not be able raise your shields if they are below 30% efficiency.
X
X
XEnergy:
X
X If you run out you're dead. Don't allow this to happen. The best
X way to get more energy is to dock with a starbase. See "building
X bases" for information on this.
X
X Some energy is used to maintain the ships' functions. An additional
X amount if required whenever you move, when you use shields or weapons,
X or when you build upon a planet.
X
X
Building Bases:
X
X To build a base, a player moves next to a planet and uses the "B"
X command. You will be asked for a direction, enter the key on the
X keypad (numeric) corresponding to the direction of the planet you
X wish to build upon.
X
X 10 Builds are required to create a base, and each one requires 500
X Energy units from your ship.
X
X
Lasers:
X
X Lasers are fired with the 'l' key. You must aim these weapons at
X the position you wish to hit _relative_ to your current location, or
X in ships which have targeting (anything larger than a courier) you
X may aim by ship name. Thus, to hit an object at 102, 100 if you
X are at 100, 100 would require a "laser" coordinate entry of "2 0".
X
X Larger ships have more powerful lasers.
X
X Note that either an object's letter (case is irrelavent) or the
X relative coordinates must be entered at the prompt, followed by
X <return>. A null (ie: return only) entry will use the last entered
X coordinates or ship to target on.
X
X
Projectiles:
X
X Torpedoes move at a reasonable rate -- you may be able to outrun
X them. Torpedoes also have a definite range dependant on the
X launcher's guidance capabilities, at which point they automatically
X detonate regardless of whether they are in range of a target.
X
X Torpedoes explode on impact with any other object in the game.
X
X All torpedoes are guided by the "parent" ship which fires it. As a
X result, if the parent ship should die, the torpedo will cease
X activity (effectively be "dead). The torpedo does carry limited
X detection facilities in it's nose, as will "track" or home in on a
X target if it is not specified in absolute terms. Small ships have
X an "in flight" torpedo limit due to their limited computer resources
X for guidance.
X
X To fire a torpedo, enter either the ship's letter or the relative
X coordinates to fire upon, as with lasers. As with lasers, a
X <return> signifies to repetitively fire at the same target.
X
X Scout ships do not possess torpedoes.
X
X
Mines:
X
X Intersteller mines are extremely dangerous. They are difficult to
X spot and impossible to trace, and they will explode if they take any
X damage at all (ie: if you shoot it). Clusters of mines will
X chain-detonate; this will produce a very spectacular explosion (not
X to mention killing nearly any ship nearby). Mines are not detected
X by one's "collision avoidance" system, and as a result you can
X easily run into one or more without warning.
X
X Note that once in a while a mine will be in your "kit" that has much
X more explosive power than normal. These are termed "nuclear" mines;
X you cannot detect a difference until they are detonated.
X
X Mines are first available to Frigates.
X
X
Ramming objects:
X
X Your computer will not allow you to run into solid objects unless
X you specifically override this safety feature. To turn on the
X override, and permit ramming, press <R>. You may press this key
X again to disable the override when you are done with it.
X
X This is intended to permit intentional ramming operations, but
X prevent accidental death due to collisions with solid objects.
X
X Note that the override on your movement expends some energy stopping
X your ship before it impacts with the object you would otherwise ram.
X
X
Special weaponry:
X
X There may be special functions only available to the largest class
X ships. The use of these functions is not documented, but there are
X rumors that one of them is a planet-destroying weapon.
X
X Hints will be given to you if you are fortunate when completing a base.
X
X
XExplosions:
X
X Expect to take *HEAVY* damage from things that explode near you. If
X you are unfortunate enough to be next to an object that is destroyed,
X you will suffer the equivalent damage of several large laser (or
X multiple) torpedo hits. Many ships will be destroyed by these
X occurances. Bases, planets, stars, and large ships will do damage
X beyond the immediate neighbor sectors when they detonate.
X
X Be especially careful if you are near multiple sources of explosion
X -- it is possible to have a chain-reaction established and suffer
X multiple hits in this case. Such occurrances are nearly always fatal.
X
X Your shields are effective against explosion forces up to a point.
X
X
Combat:
X
X You will be informed via a "beep" and a message on the bottom line
X of your screen, as well as your token "flashing", whenever you
X suffer an attack. The source of the attack is not necessarially
X known to you, although you can probably take a good guess from the
X magnitude of the hit.
X
X The first time you fire on a base it will send a distress message.
X Bases will also use their very last dying gasps to tell the universe
X you have blown them to smithereens, so you can expect a message when
X this occurs as well.
X
X Weapons fire is "sticky"; that is, once you enter a coordinate to
X shoot at you may just press <return> at the coordinate prompt to
X fire at the same relative location. This "sticky" power is retained
X even if you move the vessel. NOTE THAT COORDINATES ENTERED FOR
X WEAPONS MUST - MUST - MUST BE RELATIVE TO YOUR CURRENT LOCATION.
X
X Any item which explodes will be detected by your ships' sensor, and
X the coordinates of the explosion will be displayed on the message
X screen. Novas and planetary destruction are so spectacular as to be
X unmistakable for other explosions, and are so noted.
X
X
Black Holes:
X
X Occasionally you may see an "empty" space on the game grid. These
X are "black holes". There are a few found at random locations
X throughout the galaxy, and exploding stars will also create these
X anomolies.
X
X Moving into a sector containing a black hole will cause your ship to
X be instantly transported to another location on the game grid. The
X "white hole" on the other side is always consistantly placed once
X the black hole has been created.
X
X
General Weaponry & Player Notes:
X
X When you shoot something, or it explodes, you will see the area
X affected by the act light up in reverse video (providing your
X terminal supports this option).
X
X Note that the computer may be playing and number of ships while you
X are in the game. These are indistinguishable from human players,
X and they play be the same rules you do. Pay particular attention
X to a ships' size, as these ships come in all sizes and dispositions.
X The admininistrator can set the maximum number of computer players
X which can be in the game as well as their rate of replenishment.
X It is completely possible for the computer ships to gang up on the
X human player(s). (Hint: Computer ships operate on energy just as you
X do, and must dock as well).
X
X The message area (the 4 lines on the bottom right side of the screen)
X is a "windowed radio" of sorts. Operating on sub-light frequencies,
X it is a limited-bandwidth device, that is to say, rapid events may
X overload it's reception and display capacity. If this occurs the
X message(s) which overload the capacity of the internal buffering are
X lost without a trace.
X
X All other things being equal, a small ship is faster than a large
X one due to inertia. The game enforces this by parceling out movement
X windows differently for the different classes of ships.
X
X
X
Combat Hints:
X
To Survive Combat (victoriously, of course):
X
X1) Use the power of items near you, yet be wary of it. Be aware that a ship
X or other object which detonates near you will likely damage you heavily.
X Large ships', planets, and stars' detonations will be _fatal_ if you are
X too close to the object when it explodes.
X2) Put up your shields when hostilities are imminent. They only help you if
X they are raised. However, do not leave them up unnecessarially, as
X shields are a heavy drain on your energy resources. Computer ships will
X _always_ raise their shields when in your company if they are operational.
X Note that if your shields get to below 30% efficiency, your control
X circuits may malfunction, making it impossible to lower _or_ raise shields.
X To avoid this drop your shields before you go below 30% shield efficiency.
X3) Make use of the explosive potential in starbases if you surprise a enemy
X ship and it is docked with one. Undock and move away IMMEDIATELY if you
X are attacked while docked, or if the base you are docked with is attacked
X by hostile fire.
X4) Be aware that different class ships have different scanner sensitivities,
X and that you may be seen before you can see your opponent and vice-versa.
X As a correlary of this, if you can't see what's firing on you, it's
X almost certainly larger than you are.
X5) Keep an eye on your secondary resources (percentage damage display), as
X well as energy. Abort your combat if any of your critical parameters is
X near the failing level. Shields are especially important, as they absorb
X hits that would otherwise damage your ship's other components.
X6) Learn to fire bursts of weapons. This is done by moving to position,
X keying the initial fire command with appropriate parameters, then
X re-keying only the command portion to fire again at the same location.
X Use EXTREME caution when doing this with lasers to prevent running out
X of energy!
X7) Use the scanners to determine whether a ship you are attacking is weaker
X than you are, comparable, or much stronger. Don't be afraid to run from
X attacks from ships of unknown strength!
X8) Be wary of allowing your "operability percentages" to drop below 30
X percent. Your controls may malfunction in this circumstance; you may be
X unable to raise (or lower!) your shields, fire weapons, or even move!
X
Note that you only get points for what you actively damage. Forcing someone
into a planet will not gain you any Captains' points, while causing their
ship to explode from laser or torpedo fire certainly will.
X
Most damage which does not disable a resource (percent < 0) will be repaired
with time, even if you do not dock at a starbase. Damage which results in an
item going below "0" will not be repaired until you dock, and the item
affected cannot be used. Nearly all items which sustain damage leaving less
than 30 percent operability will have serious problems. The following
X"secondary" items are *ESSENTIAL* to operation of the ship; loss of any of
these (below 0) will cost you your vessel.
X
X Life support - This one should be obvious (oxygen anyone?)
X Crew - Also obvious. You're one of them :-)
X Hull - If it's zero, there isn't one. In other words,
X your vessel is blown into a few thousand pieces.
X
X<Return> to continue
END_OF_FILE
if test 13308 -ne `wc -c <'Help'`; then
echo shar: \"'Help'\" unpacked with wrong size!
fi
# end of 'Help'
fi
if test -f 'cosmos.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cosmos.h'\"
else
echo shar: Extracting \"'cosmos.h'\" \(7901 characters\)
sed "s/^X//" >'cosmos.h' <<'END_OF_FILE'
X/* Cosmos - The final frontier
X
X This package is Copyright 1988 Karl Denninger. All rights reserved.
X
X All unauthorized mutants shall be destroyed, fed to vermin, and the
X remains from this process will be prosecuted.
X
X*/
X
X/* Definitions go below - Make sure you have these in front of include
X files as these definitions should override the include files */
X
X#include <values.h> /* Gots to have this */
X
X#undef NO_RDCHK /* Define if not Xenix or if
X you have problems with input
X disappearing when typed ahead */
X
X#define MAXSHIPS 20 /* Max players */
X#define HOMEDIR home /* Home directory */
X#define HOME "/etc/cosmos/" /* Home pointer file */
X#define SIZE 200 /* Grid size (each) */
X#define MAXNAME 20 /* Ship name max length */
X#define MAXFTORPS 10 /* Max free torps per ship */
X#define TIME_PER_EUNIT 20 /* Time per energy in turns at rest */
X#define TIME_PER_MSG 100 /* Time for message expiration */
X#define MINE_ENERGY 5L /* Energy for a mine */
X#define EPERSHIELD 100 /* Energy per shield point */
X#undef ACCOUNTING /* Accounting features enabled? */
X
X#undef RETIRE_MSGS /* Don't kill msgs */
X#undef FASTMATH /* We have a fast sqrt routine */
X
X/* All of these constants are per ship type, which means they get multiplied
X when used. This is especially important with energy adjustments; be fair! */
X
X#define E_PER_MOVE 30 /* Energy per move square */
X#define E_RAND_PER_MOVE 5 /* Random influence per move */
X#define EADD 75 /* Number always added w/docked */
X#define RANDADD 80 /* Random number added w/docked */
X#define NUKECHANCE 200 /* One in 200 mines is a nuke */
X
X/* Having a thing explode counts as EXPLOSION * HIT TYPE points of
X explosive energy which must be dissipated. Some, of course, by
X the person impacted.... :-)
X*/
X
X#define EXPLOSION 10000 /* Base explosion energy dissipated */
X#define TORP_EREL 800 /* Base torpedo energy released */
X
X#define SHIP_DEATH 1 /* Ship explosion ( X type) */
X#define MINE_BOOM 2 /* Mine explosion */
X#define BASE_DEATH 4 /* This is not good :-) */
X#define NUKE_MINE 12 /* Nuclear mine blast */
X#define BIG_BOOM 18 /* A planet blowing up! */
X#define NOVA 40 /* Uh, don't ask */
X
X#define NAP /* System has short sleep if defined */
X#define NAPTIME 250 /* Time in ms for sleep ifdef NAP */
X#define SLEEPTIME 1 /* Time in sec for sleep ifndef NAP */
X
X/* Some constants below, tune these for personal preference */
X
X#define SHIELD_COST 4 /* Cost per turn per ship/shield type */
X#define BUILDCOST 500 /* Cost of a BUILD command */
X#define BUILDTIME 2 /* Time in Seconds to execute a build */
X
X/* For inter-ship messages */
X
X#define MAXMSG 6 /* Maximum messages in queue at once */
X#define MSGLEN 40 /* Maximum length of each msg */
X
X/* The following are the definitions for the inanimate objects */
X
X#define EMPTY '.' /* Empty place */
X#define PLANET '@' /* Planetary body */
X#define STAR '*' /* A star */
X#define BASE '+' /* A Starbase planet */
X#define NEGBASE '-' /* A negbase planet */
X#define MINE ',' /* A Mine */
X#define TORPEDO '^' /* A Torpedo */
X
X#define VOID ' ' /* A void */
X#define ASTEROID '`' /* Asteroid :-) */
X
X/* END OF CONFIGURABLE SECTION -- DO NOT CHANGE BELOW HERE */
X
X
static char *shiptypes[20] = { /* Names of ships */
X "", "Scout", "Courier", "Frigate", "Miner", "Destroyer",
X "Cruiser", "Battlestar", "Death Star", "Dreadnought",
X "Marauder", "Flagship"
X };
X
static int e_require[20] = { /* Energy requirements/capacity */
X 0, 20000, 30000, 40000, 55000, 70000, 85000, 100000,
X 120000, 135000, 150000, 200000
X };
X
static int pts[20] = { /* Pts for Advancement */
X 0, 20000, 40000, 80000, 160000, 320000, 640000, 1280000,
X 2560000, 5120000, 10240000, MAXINT
X };
X
static int num_torps[20] = { /* Number of torpedoes */
X 0, 0, 2, 5, 2, 5, 10, 15, 17, 20, 30, 35
X };
X
static int num_ftorps[20] = { /* Guidance control capacity */
X 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5
X };
X
static int num_mines[20] = { /* Number of mines */
X 0, 0, 0, 2, 15, 5, 5, 15, 20, 25, 30, 40
X };
X
static int window_size[20] = { /* Screen window sizes */
X 10, 10, 12, 12, 14, 14, 16, 16, 18, 18, 20, 20
X };
X
X /* Bit mask values for weapons */
X /* THESE SHOULD NOT BE CHANGED */
X#define SHIELD_UP 1
X#define SHIELD_DEAD 2 /* NOTE: Requires, due to entries, */
X#define LASERS_LOCK 4 /* 32-bit integers to run */
X#define LASERS_DEAD 8
X#define TORPEDO_LOCK 16
X#define TORPEDO_DEAD 32
X#define MINE_LOCK 64
X#define MINE_DEAD 128
X#define PLANET_KILLER 256 /* You have a planet killer */
X#define CREATE_WORLDS 512 /* You can create planets */
X
static int weapons[20] = { /* Weapons mask; must be here */
X 0,
X MINE_DEAD,
X MINE_DEAD,
X 0,
X 0,
X MINE_DEAD,
X MINE_DEAD,
X 0, /* All normal weapons here */
X 0,
X 0,
X PLANET_KILLER,
X PLANET_KILLER|CREATE_WORLDS
X };
X
X
X/* Standard include files */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/ipc.h>
X#include <sys/shm.h>
X#include <curses.h>
X#include <signal.h>
X#include <string.h>
X#include <math.h>
X#include <ctype.h>
X#include <pwd.h>
X
extern struct passwd *getpwuid();
extern char *memcpy();
X
X#define MAXGRID SIZE * SIZE /* DO NOT CHANGE */
X
struct torps {
X char inuse; /* Torpedo in "use" */
X int level; /* Torpedo 'level' for explosion */
X int x; /* Torpedo 'x' coordinate */
X int y; /* Torpedo 'y' coordinate */
X int destx; /* Destination 'x' */
X int desty; /* Destination 'y' */
X int homeship; /* Home in on ship indicated if NZ */
X int travelled; /* Sectors travelled */
X int life; /* Life (in sectors) of torpedo w/o impact */
X int lastkey; /* Last homing beacon direction */
X};
X
struct grid { /* The play grid */
X char type; /* Thing 'living' there */
X short shield; /* Shield percentage at location */
X int energy; /* Energy at location */
X char align; /* Alignment */
X char hit; /* Hit by fire flag */
X};
X
X/* Additional attributes
X Ship type (1 char)
X Weapon status (each weapon - bit mask inoperable/locked/standby)
X Shields
X Lasers
X Torpedoes
X Mines
X Life support status (percentage)
X Crew status (percentage)
X Engines (percentage)
X Hull (percentage)
X Shields
X*/
struct nameblock {
X char name[MAXNAME]; /* Ships' christened name */
X char token; /* Game token */
X int type; /* Ship type */
X int wstatus; /* Bit mask -- be careful! */
X int lasers; /* Laser status */
X int torps; /* Torpedo launchers */
X int mines; /* Mine launchers */
X int life; /* Life support */
X int crew; /* Crew status */
X int engines; /* Engine status */
X int hull; /* Hull status */
X int shield; /* Shield status */
X long energy; /* Energy amount */
X long points; /* Points awarded to date */
X char align; /* Current alignment */
X int locked; /* What you have locked on */
X int lockx; /* 'X' coordinate of lock */
X int locky; /* "Y" coordinate of lock */
X int numtorps; /* Number of torpedoes */
X int nummines; /* Number of mines */
X int scanned; /* Have we been scanned? */
X int human; /* Non-zero if a human player */
X int gods; /* The gods have intervened */
X int uid; /* The users' UID */
X};
X
struct msgblock {
X int curmsg; /* Current message number */
X char msgtext[MSGLEN*MAXMSG]; /* Message texts */
X};
X
X
struct gameseg {
X int ccount; /* # of computers */
X struct nameblock names[MAXSHIPS]; /* Name/ship blocks */
X struct grid play[MAXGRID]; /* Play grid */
X struct msgblock messages[MAXMSG]; /* Messages */
X};
X
X
struct shiprecord {
X char shipname[20];
X int type;
X long points; /* Points */
X int uid; /* User's UID entry */
X int x; /* X & Y Coordinates Last time */
X int y;
X long energy; /* Energy last saved */
X int notused1; /* We will save 2 ints for later */
X int notused2;
X int notused3;
X int notused4;
X};
X
struct nameblock onename;
struct grid onegrid;
struct msgblock onemsg;
X
int ccount;
X
END_OF_FILE
if test 7901 -ne `wc -c <'cosmos.h'`; then
echo shar: \"'cosmos.h'\" unpacked with wrong size!
fi
# end of 'cosmos.h'
fi
if test -f 'drone.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'drone.c'\"
else
echo shar: Extracting \"'drone.c'\" \(13370 characters\)
sed "s/^X//" >'drone.c' <<'END_OF_FILE'
X/* Spacewar - The final frontier
X
X This package is Copyright 1988 Karl Denninger. All rights reserved.
X
X All unauthorized mutants shall be destroyed, fed to vermin, and the
X remains from this process will be prosecuted.
X
X*/
X
X/* Definitions go below - Make sure you have these in front of include
X files as these definitions should override the include files */
X
X
X
X/* This is the drone module -- it's a computer "player" */
X
X
X
X#include "cosmos.h"
X
X
int extx, exty;
char *buffer; /* Buffer pointer */
int *intbfr;
int numcomp;
char home[128]; /* Home directory */
int superuser, su2; /* Uid of the superuser */
int window; /* Window size, must be < 20 */
int foundchar = 0; /* Found character? */
int oldchar; /* Old character if one */
struct nameblock *ship; /* Pointer to ship's data */
struct nameblock name[MAXSHIPS];
struct grid onegrid;
struct grid oldgrid;
int quit; /* Halt variable */
X
int squares[SIZE];
X
int drone = -1; /* This is a drone ship */
X
main(argc, argv)
int argc;
char *argv[];
X{
X
X static long points; /* Points accumulated */
X static int type; /* Class of ship */
X char shipname[40];
X
X int shipcount = 0;
X int bypass;
X int slept = 0; /* Was I sleeping a minute ago? */
X int humans = 0; /* Number of human players */
X int humancount = 0; /* Human count (turns) */
X int ntfree = 0; /* Number of torpedoes free */
X int docked = 0;
X int tmpint; /* Temp integer */
X
X int seg; /* Shared segment number */
X
X int status; /* Status (ok/not ok) */
X int qcount = 0; /* Quit counter */
X int energy_count = 0; /* Temporary iterative counter */
X int stale_msg = TIME_PER_MSG;/* Stale message count */
X int tempenergy;
X long size;
X int x, y; /* X & Y coordinates of ship */
X int oldx, oldy;
X int key;
X int tempint = 0;
X double dist; /* Distance between two points */
X
X static int delta_x = 0; /* Initial delta 'x' */
X static int delta_y = 0; /* Initial delta 'y' */
X
X int semid;
X int flags;
X char tempstr[80]; /* 80 Character string */
X char tempstr2[80]; /* 80 Character string */
X char tmp[80];
X FILE *fid;
X int lastkey = 0;
X
X struct nameblock namebuf;
X struct torps torparray[MAXFTORPS];
X /* Array of torpedo coords */
X
X long game = sizeof(ccount) + (sizeof(onename) * MAXSHIPS) +
X (sizeof(onegrid) * MAXGRID) + (sizeof(onemsg) * MAXMSG);
X
X size = (game); /* Get size of game module */
X
X printf("Cosmos DRONE V%s\n", VERSION);
X printf("Copyright 1988 MCS Inc. & Karl Denninger\n");
X fflush(stdout);
X for (x = 0; x < SIZE; x++)
X squares[x] = (x * x);
X sprintf(tmp, "%s", HOME);
X if ((fid = fopen(tmp, "r")) != NULL) {
X fscanf(fid, "%s %d %d %d", home, &superuser, &su2, &numcomp);
X fclose(fid);
X }
X if ((seg = shmget(122L, size, 0660)) == -1) {
X perror("create");
X puts("Cannot execute due to shared-segment create fault");
X exit(1);
X }
X if ((buffer = shmat(seg, (char *) NULL, 0)) == (char *) -1) {
X perror("attach");
X puts("Cannot execute due to shared-segment attach fault");
X exit(1);
X }
X if ((semid = semget(122L, 1, 0660)) == -1) {
X if ((semid = semget(122L, 1, 0660)) == -1) {
X perror("semaphone create");
X exit(1);
X }
X } else {
X acquire(semid);
X }
X signal(SIGINT, SIG_IGN); /* Ignore ^C */
X readgrid(0, 0, &onegrid);
X if (onegrid.type == 0) {
X puts("No grid, exiting....\n");
X release(semid);
X exit(1);
X }
X intbfr = (int *) buffer;
X srand((unsigned) time ((long *) 0L));
X if (((int) *intbfr ) >= numcomp) {
X puts("All computer players in, exiting");
X release(semid);
X exit(1);
X }
X *intbfr += 1; /* Increment one */
X ship = (struct nameblock *) getcship(semid, &x, &y);/* Get token */
X if ((x == 0) && (y == 0)) {
X x = roll(SIZE);
X y = roll(SIZE);
X }
X window = window_size[ship->type];
X sprintf(tmp, "Welcome %s (%c)", ship->name, ship->token);
X putmsg(tmp);
X
X/* Now place the computer's ship in the game. */
X
X quit = 0;
X tempint = 0;
X while (quit == 0) {
X readgrid(x, y, &onegrid);
X if (onegrid.type == EMPTY)
X quit++;
X else {
X x = roll(SIZE); y = roll(SIZE);
X tempint++;
X if (tempint >= 200) {
X release(semid);
X puts("Cannot place ship!");
X }
X }
X }
X onegrid.type = ship->token;
X onegrid.shield = ship->shield;
X onegrid.energy = ship->energy;
X onegrid.align = 0; /* Neutral alignment */
X ship->human = 0; /* Android player */
X storegrid(x, y, onegrid);
X quit = 0;
X while (quit == 0) {
X
X/* Move torpedoes */
X movetorps(torparray, &ntfree);
X readgrid(x, y, &onegrid);
X if (onegrid.type == EMPTY) /* If we got killed */
X quit++; /* Exit at end of pass */
X
X/* Insert here any routines which should be performed after each turn --
X specifically, those things which take energy when engaged such as shields */
X
X energy_count--;
X if (energy_count < 0) {
X energy_count = TIME_PER_EUNIT;
X onegrid.energy += 500;
X ship->energy += 500;
X }
X#ifdef RETIRE_MSGS
X if (stale_msg-- <= 0) {
X putmsg("");
X stale_msg = TIME_PER_MSG;
X }
X#endif
X if (ship->wstatus & SHIELD_UP) {
X onegrid.energy -= (ship->type * SHIELD_COST);
X docked = 0; /* Undock the craft */
X }
X if (ship->energy > onegrid.energy)
X ship->energy = onegrid.energy;
X if (ship->shield > onegrid.shield)
X ship->shield = onegrid.shield;
X if (ship->shield <= 30) {
X ship->wstatus &= ~(SHIELD_UP);
X ship->wstatus |= SHIELD_DEAD;
X } else
X ship->wstatus &= ~(SHIELD_DEAD);
X if (ship->torps <= 30) {
X ship->wstatus &= ~(TORPEDO_LOCK);
X ship->wstatus |= TORPEDO_DEAD;
X if (ship->torps < 0)
X ship->numtorps = 0; /* Blown off */
X } else
X if (num_torps[ship->type] > 0)
X ship->wstatus &= ~(TORPEDO_DEAD);
X if (ship->mines <= 30) {
X ship->wstatus &= ~(MINE_LOCK);
X ship->wstatus |= MINE_DEAD;
X if (ship->mines < 0)
X ship->nummines = 0; /* Blown off */
X } else
X if (num_mines[ship->type] > 0)
X ship->wstatus &= ~(MINE_DEAD);
X ship->align = onegrid.align; /* Alignment */
X if (onegrid.hit) {
X printf("Computer hit %d times\n", onegrid.hit);
X onegrid.hit = 0;
X }
X storegrid(x, y, onegrid);
X if ((ship->energy < 0) || (ship->life < 0) || (ship->hull < 0) || (ship->crew < 0)) {
X sprintf(tmp, "The %s (%c) explodes!", ship->name, ship->token);
X putmsg(tmp);
X explode(x, y, (ship->type * EXPLOSION), ship->type);
X ship->token = 0; /* Delete from grid */
X ship->name[0] = 0;
X onegrid.type = EMPTY;
X onegrid.shield = 0;
X onegrid.energy = 0;
X onegrid.align = 0;
X storegrid(x, y, onegrid);
X release(semid); /* Release locks */
X puts("Computer ship disintegrated!");
X *intbfr -= 1;
X exit(0);
X }
X status = calcstatus(x, y, window, docked);
X release(semid); /* Release lock */
X oldx = x;
X oldy = y;
X/*
X The purpose of this section of code is to insure that there is
X something to do before going off and reading input. If there is
X nothing to do, wait a second, then go update the display and try
X again. In addition, if a drone, we only move with any real speed if
X there are humans in the game (to reduce CPU load).
X*/
X humans = 0; /* No humans */
X for (key = 0; key < MAXSHIPS; key++) {
X readname(key, &onename);
X if (onename.type) {
X if (onename.human) /* A human! */
X humans++;
X }
X }
X if (!humans) { /* If there are no humans */
X if (humancount < 100) /* Do we sleep? */
X humancount++; /* Increase human check */
X else {
X slept++;
X sleep(60); /* sleep 60 seconds */
X }
X } else {
X humancount = 0; /* Clear count iff humans */
X if (slept) {
X slept = 0; /* Clear it */
X sprintf(tmp, "%s awakens", ship->name);
X putmsg(tmp);
X }
X }
X key = 0;
X nap(NAPTIME + 350);
X#ifdef SLOWDOWN
X if ((ship->type >= 10) && (shipcount < 5))/* Marauder... */
X shipcount = 5; /* Nearly always can move... */
X if (shipcount++ <= (ship->type / 3)) {/* If delay not expired */
X key = 0; /* No input allowed */
X bypass++; /* Bypass check */
X } else { /* Otherwise... */
X#endif
X shipcount = 0; /* Reset counter to zero */
X key = makechoice(x, y, window, &lastkey);
X bypass = 0; /* Evaluate keypress */
X#ifdef SLOWDOWN
X }
X#endif
X acquire(semid); /* Regain lock on segment */
X if (status == 0) /* If green */
X qcount = 0; /* Then reset exit marker */
X if (!bypass) {
X if ((key == 0) || ((key >= '0') && (key <= '9')))
X key = checkchoice(x, y, key, &lastkey);
X }
X switch (key) {
X case 0:
X break;
X case '8':
X y = y + 1;
X break;
X case '7':
X y = y + 1;
X x = x - 1;
X break;
X case '1':
X y = y - 1;
X x = x - 1;
X break;
X case '9':
X x = x + 1;
X y = y + 1;
X break;
X case '3':
X y = y - 1;
X x = x + 1;
X break;
X case '2':
X y = y - 1;
X break;
X case '4':
X x = x - 1;
X break;
X case '6':
X x = x + 1;
X break;
X case 'D':
X docked = cdock(x, y, &window);
X break;
X case 'B':
X cbuildbase(semid, x, y, window);
X break;
X case 'l':
X if (cphasers(x, y, 'A', 'Z') == 0)
X lastkey = 0;
X break;
X case 'L':
X if (cphasers(x, y, BASE, BASE) == 0)
X lastkey = 0;
X break;
X/*
X case 'm':
X cmines(semid, x, y);
X break;
X*/
X case 't':
X if (!cftorps(x, y, torparray, &ntfree, window))
X lastkey = 0;
X break;
X case 's':
X case 'S':
X if ((ship->wstatus & SHIELD_DEAD) == 0)
X ship->wstatus = ship->wstatus ^ SHIELD_UP;
X break;
X }
X if (x < 0)
X x = 0;
X if (y < 0)
X y = 0;
X if (x >= SIZE)
X x = SIZE - 1;
X if (y >= SIZE)
X y = SIZE - 1;
X
X/* Now check to see if the engines are working... */
X
X if (ship->engines < 30) {
X if (roll(200) > ship->engines) {
X x = oldx; /* If not, no movement! */
X y = oldy;
X }
X }
X
X/* End Engine check */
X
X if ((x != oldx) || (y != oldy)) {
X printf("Position %d %d\n", x, y);
X docked = 0; /* Undock craft */
X readgrid(x, y, &oldgrid);
X if (oldgrid.type == VOID) {
X x = oldgrid.energy;
X y = oldgrid.shield;
X readgrid(x, y, &oldgrid);
X }
X if (oldgrid.type != EMPTY) { /* Collision! */
X tempenergy = oldgrid.energy;
X readgrid(oldx, oldy, &onegrid);
X oldgrid.energy -= ((onegrid.energy / 2) + 1000);
X if (oldgrid.energy < 0) {
X if ((oldgrid.type >= 'A') && (oldgrid.type <= 'Z')) {
X namebuf.token = oldgrid.type;
X tempint = locship(&namebuf, 1);
X namebuf.token = 0;
X namebuf.name[0] = 0;
X storename(tempint, namebuf);
X }
X if (oldgrid.type == MINE) {
X explode(x, y, (MINE_BOOM * EXPLOSION), MINE_BOOM);
X }
X oldgrid.type = EMPTY;
X }
X storegrid(x, y, oldgrid);
X x = oldx; /* Go backwards */
X y = oldy;
X if (tempenergy < 0)
X tempenergy = 0 - tempenergy;
X onegrid.energy -= ((tempenergy / 2) + 1000);
X storegrid(x, y, onegrid);
X } else {
X readgrid(oldx, oldy, &onegrid);
X
X onegrid.energy -= sqr(((x - oldx) * (x - oldx)) + ((y - oldy) * (y - oldy))) * (roll(E_RAND_PER_MOVE) + E_PER_MOVE);
X storegrid(x, y, onegrid);
X onegrid.type = EMPTY;
X onegrid.energy = 0L;
X onegrid.shield = 0L;
X onegrid.align = (char) 0;
X storegrid(oldx, oldy, onegrid);
X }
X }
X readgrid(x, y, &onegrid);
X if (onegrid.hit) /* If we have been hit */
X docked = 0; /* Undock craft for sure */
X if (docked) { /* If docked with the base */
X tmpint = (roll(RANDADD)+EADD) * ship->type;
X onegrid.energy += tmpint;
X ship->energy += tmpint;
X if (onegrid.energy > e_require[ship->type]) {
X onegrid.energy = e_require[ship->type];
X ship->energy = e_require[ship->type];
X }
X if (ship->shield < 100) {
X ship->shield++;
X onegrid.shield++;
X }
X if (ship->engines < 100)
X ship->engines += 1;
X if (ship->life < 100)
X ship->life += 1;
X if (ship->crew < 100)
X ship->crew += 1;
X if (ship->hull < 100)
X ship->hull += 1;
X if (ship->lasers < 100)
X ship->lasers += 1;
X if (ship->mines < 100)
X ship->mines += 1;
X if (ship->torps < 100)
X ship->torps += 1;
X ship->numtorps++;
X ship->nummines++;
X }
X if (energy_count == 0) { /* If it's time */
X if ((ship->shield < 100) && (ship->shield > 0)) {
X ship->shield++;
X onegrid.shield++;
X }
X if ((ship->engines < 100) && (ship->engines > 0))
X ship->engines += 1;
X if ((ship->life < 100) && (ship->life > 0))
X ship->life += 1;
X if ((ship->crew < 100) && (ship->crew > 0))
X ship->crew += 1;
X if ((ship->hull < 100) && (ship->hull > 0))
X ship->hull += 1;
X if ((ship->lasers < 100) && (ship->lasers > 0))
X ship->lasers += 1;
X if ((ship->torps< 100) && (ship->torps> 0))
X ship->torps += 1;
X if ((ship->mines < 100) && (ship->mines> 0))
X ship->mines += 1;
X }
X if (ship->shield > 100) {
X ship->shield = 100;
X onegrid.shield = 100;
X }
X if (ship->engines > 100)
X ship->engines = 100;
X if (ship->life > 100)
X ship->life = 100;
X if (ship->crew > 100)
X ship->crew = 100;
X if (ship->hull > 100)
X ship->hull = 100;
X if (ship->torps > 100)
X ship->torps = 100;
X if (ship->lasers > 100)
X ship->lasers = 100;
X if (ship->mines > 100)
X ship->mines = 100;
X if (ship->numtorps > num_torps[ship->type])
X ship->numtorps = num_torps[ship->type];
X if (ship->nummines > num_mines[ship->type])
X ship->nummines = num_mines[ship->type];
X storegrid(x, y, onegrid);
X }
X readgrid(x, y, &onegrid); /* Delete ship */
X onegrid.type = EMPTY;
X storegrid(x, y, onegrid);
X namebuf.token = ship->token;
X tempint = locship(&namebuf, 1);
X namebuf.token = 0;
X namebuf.name[0] = 0;
X storename(tempint, namebuf);
X release(semid);
X puts("Good bye!");
X *intbfr -= 1;
X shmdt(buffer); /* Detach shared segment */
X exit(0);
X}
END_OF_FILE
if test 13370 -ne `wc -c <'drone.c'`; then
echo shar: \"'drone.c'\" unpacked with wrong size!
fi
# end of 'drone.c'
fi
if test -f 'torpedoes.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'torpedoes.c'\"
else
echo shar: Extracting \"'torpedoes.c'\" \(7558 characters\)
sed "s/^X//" >'torpedoes.c' <<'END_OF_FILE'
X/* Part of the COSMOS package
X Copyright 1988 Karl Denninger & MCS, Inc.
X All Rights Reserved
X*/
X
X
X#include "cosmos.h"
X
extern struct nameblock *ship;
X
movetorps(ta, ntfree)
struct torps ta[];
int *ntfree;
X{
X int tcount;
X struct grid ourgrid;
X int key;
X int xx, yy;
X int dist;
X int x1, y1, xv, yv, count;
X
X if (! *ntfree)
X return(0); /* Exit -- no torpedoes to move */
X for (tcount = 0; tcount < MAXFTORPS; tcount++) {
X if (ta[tcount].inuse) { /* Process this entry */
X readgrid(ta[tcount].x, ta[tcount].y, &ourgrid);
X if (ourgrid.type != TORPEDO) {
X ta[tcount].inuse = 0; /* Free slot */
X (*ntfree)--; /* Free torpedo in flight */
X } else {
X ourgrid.type = EMPTY;
X ourgrid.energy = 0;
X ourgrid.shield = 0;
X storegrid(ta[tcount].x, ta[tcount].y, ourgrid);
X if ((ta[tcount].destx == -1) && (ta[tcount].desty == -1)) {
X if (ta[tcount].homeship) {
X xx = ta[tcount].x;
X yy = ta[tcount].y;
X key = findobj(&xx, &yy, &dist,
X ta[tcount].homeship,
X ta[tcount].homeship,
X window_size[ship->type]);
X if (!key)
X key = ta[tcount].lastkey;
X else
X ta[tcount].lastkey = key;
X }
X } else
X key = give_dir(ta[tcount].x,
X ta[tcount].y,
X ta[tcount].destx,
X ta[tcount].desty);
X xx = ta[tcount].x;
X yy = ta[tcount].y;
X switch(key) {
X case 0:
X break;
X case '8':
X yy = yy + 1;
X break;
X case '7':
X yy= yy + 1;
X xx = xx - 1;
X break;
X case '1':
X yy = yy - 1;
X xx = xx - 1;
X break;
X case '9':
X xx = xx + 1;
X yy = yy + 1;
X break;
X case '3':
X yy = yy - 1;
X xx = xx + 1;
X break;
X case '2':
X yy = yy - 1;
X break;
X case '4':
X xx = xx - 1;
X break;
X case '6':
X xx = xx + 1;
X break;
X }
X if ((xx < 0) || (yy < 0) || (xx >= SIZE) || (yy >= SIZE)) {
X (*ntfree)--;
X ta[tcount].inuse = 0; /* Delete */
X } else {
X readgrid(xx, yy, &ourgrid);
X if (ourgrid.type == VOID) { /* Warp */
X xx = ourgrid.energy; /* Get x */
X yy = ourgrid.shield; /* And Y */
X readgrid(xx, yy, &ourgrid);
X }
X if (ourgrid.type != EMPTY) {
X ta[tcount].inuse = 0; /* Boom! */
X if ((ourgrid.type >= 'A') && (ourgrid.type <= 'Z'))
X ship->points += 100;
X givedamage(xx, yy, ta[tcount].level * TORP_EREL, ship, 0);
X (*ntfree)--;
X } else {
X ourgrid.type = TORPEDO;
X ourgrid.energy = 5;
X ourgrid.shield = 0;
X storegrid(xx, yy, ourgrid);
X ta[tcount].x = xx;
X ta[tcount].y = yy;
X if (ta[tcount].life-- <= 0) {
X givedamage(xx, yy,
X (ta[tcount].level * TORP_EREL), ship, 0);
X (*ntfree)--;
X ta[tcount].inuse = 0;
X }
X }
X }
X }
X }
X }
X}
X
X
firetorps(x, y, torparray, semid, ntfree, window)
int x, y;
struct torps torparray[];
int semid;
int *ntfree;
int window;
X{
X static int key;
X static int destx;
X static int desty;
X static int zz;
X int xx, yy;
X int x1, y1;
X int z = 0;
X int dist;
X struct grid ourgrid;
X char tmp[80];
X
X release(semid);
X mvaddstr(22,20,"Torpedo -> ");
X refresh();
X get_str(tmp);
X acquire(semid);
X if (ship->wstatus & SHIELD_UP) {
X mvaddstr(23,20,"Captain! The shields are UP!");
X clrtoeol();
X return(0);
X }
X xx = x;
X yy = y;
X if (tmp[0]) {
X if ((!isdigit(tmp[0])) && (tmp[0] != '-')) {
X destx = x;
X desty = y;
X key = findobj(&destx, &desty, &dist, toupper(tmp[0]), toupper(tmp[0]), window);
X if (!key) {
X mvaddstr(23,20,"Captain, I can't locate that target!");
X clrtoeol();
X return(0);
X }
X destx = -1;
X desty = -1;
X zz = toupper(tmp[0]);
X } else {
X sscanf(tmp, "%d %d", &x1, &y1);
X destx = (x1 + x);
X desty = (y1 + y);
X key = give_dir(xx, yy, destx, desty);
X }
X }
X xx = x; yy = y;
X switch(key) {
X case '9':
X xx++;
X yy++;
X break;
X case '6':
X xx++;
X break;
X case '3':
X xx++;
X yy--;
X break;
X case '2':
X yy--;
X break;
X case '1':
X xx--;
X yy--;
X break;
X case '4':
X xx--;
X break;
X case '7':
X xx--;
X yy++;
X break;
X case '8':
X yy++;
X break;
X }
X if ((xx < 0) || (xx >= SIZE) || (yy < 0) || (yy >= SIZE))
X return(0); /* Don't launch, off grid */
X readgrid(xx, yy, &ourgrid);
X if (ourgrid.type != EMPTY) { /* Something is there */
X mvaddstr(23,20,"ABORT! Something is in the way of our launch!");
X clrtoeol();
X return(0);
X }
X if (*ntfree >= num_ftorps[ship->type]) {
X mvaddstr(23,20,"Information system overload; unable to launch");
X clrtoeol();
X return(0);
X }
X if (ship->numtorps <= 0) {
X mvaddstr(23,20,"No torpedoes on board Captain!");
X clrtoeol();
X return(0);
X }
X ship->numtorps--; /* Subtract one torpedo */
X for (z = 0; z < num_ftorps[ship->type]; z++) {
X if (!torparray[z].inuse) { /* Found one free! */
X (*ntfree)++;
X torparray[z].x = xx;
X torparray[z].y = yy;
X torparray[z].destx = 0;
X torparray[z].desty = 0;
X if ((destx == -1) && (desty == -1)) {
X torparray[z].homeship = zz;
X torparray[z].destx = -1;
X torparray[z].desty = -1;
X } else {
X torparray[z].homeship = 0;
X torparray[z].destx = destx;
X torparray[z].desty = desty;
X }
X torparray[z].travelled = 0;
X torparray[z].life = (ship->type * 2); /* Max dist */
X torparray[z].level = (ship->type); /* Blast size */
X if (!torparray[z].level)
X torparray[z].level++;
X torparray[z].inuse++; /* Entry used */
X mvaddstr(23,20,"Torpedo fired!");
X clrtoeol();
X ourgrid.type = TORPEDO;
X storegrid(xx, yy, ourgrid);
X return(1);
X }
X }
X /* If you get here, you're in trouble -- something went wrong */
X mvaddstr(23,20,"Captain! The torpedo tubes are jammed!");
X clrtoeol();
X refresh();
X return(0);
X}
X
X
cftorps(x, y, torparray, ntfree, window)
int x, y;
struct torps torparray[];
int *ntfree;
int window;
X{
X static int key;
X static int destx;
X static int desty;
X static int zz;
X int xx, yy;
X int x1, y1;
X int z = 0;
X int dist;
X struct grid ourgrid;
X char tmp[80];
X
X if (ship->torps < 30) {
X if (roll(200) > ship->torps)
X return(0);
X }
X destx = x;
X desty = y;
X key = findobj(&destx, &desty, &dist, 'A', 'Z', window);
X if (!key) {
X return(0);
X }
X readgrid(destx, desty, &ourgrid);
X zz = ourgrid.type; /* Save character */
X xx = x; yy = y;
X switch(key) {
X case '9':
X xx++;
X yy++;
X break;
X case '6':
X xx++;
X break;
X case '3':
X xx++;
X yy--;
X break;
X case '2':
X yy--;
X break;
X case '1':
X xx--;
X yy--;
X break;
X case '4':
X xx--;
X break;
X case '7':
X xx--;
X yy++;
X break;
X case '8':
X yy++;
X break;
X }
X if ((xx < 0) || (xx >= SIZE) || (yy < 0) || (yy >= SIZE))
X return(0); /* Don't launch, off grid */
X readgrid(xx, yy, &ourgrid);
X if (ourgrid.type != EMPTY) { /* Something is there */
X return(0);
X }
X if (*ntfree >= num_ftorps[ship->type]) {
X return(0);
X }
X if (ship->numtorps <= 0) {
X return(0);
X }
X ship->numtorps--; /* Subtract one torpedo */
X for (z = 0; z < num_ftorps[ship->type]; z++) {
X if (!torparray[z].inuse) { /* Found one free! */
X (*ntfree)++;
X torparray[z].x = xx;
X torparray[z].y = yy;
X torparray[z].destx = 0;
X torparray[z].desty = 0;
X torparray[z].homeship = zz;
X torparray[z].destx = -1;
X torparray[z].desty = -1;
X torparray[z].travelled = 0;
X torparray[z].life = (ship->type * 2); /* Max dist */
X torparray[z].level = (ship->type); /* Blast size */
X if (!torparray[z].level)
X torparray[z].level++;
X torparray[z].inuse++; /* Entry used */
X ourgrid.type = TORPEDO;
X storegrid(xx, yy, ourgrid);
X return(1);
X }
X }
X /* If you get here, you're in trouble -- something went wrong */
X return(0);
X}
END_OF_FILE
if test 7558 -ne `wc -c <'torpedoes.c'`; then
echo shar: \"'torpedoes.c'\" unpacked with wrong size!
fi
# end of 'torpedoes.c'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 3 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Karl Denninger (karl at ddsw1.MCS.COM, ddsw1!karl)
Data: [+1 312 566-8912], Voice: [+1 312 566-8910]
Macro Computer Solutions, Inc. "Quality solutions at a fair price"
More information about the Alt.sources
mailing list