/*******************************************************************************
* UNIT.C *
* - Declarations and functions for handling game part of units *
* *
* FREE SPACE COLONISATION *
* Copyright (C) 2002 - 2007 Paul Mueller <pmtech@swissonline.ch> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
*******************************************************************************/
/*******************************************************************************
* INCLUDES *
*******************************************************************************/
#include <memory.h> /* memset() */
#include <stdio.h> /* sprintf() */
#include "code/fscmap.h" /* Get destination position */
#include "code/fsctool.h"
#include "code/unitinfo.h" /* ORDER_* */
#include "code/unittype.h"
#include "unit.h"
/*******************************************************************************
* DEFINES *
*******************************************************************************/
#define UNIT_FREESLOT_TYPE (char)(-1)
#define UNIT_MAX 600
/*******************************************************************************
* DATA *
*******************************************************************************/
static char *UnitNames[] = { /* Names for shuttles and other transport units */
"",
"Columbus","Copernicus", "Cousteau",
"Einstein", "El-Baz", "Fermi", "Feynman",
"Galileo", "Goddard", "Hawking", "Justman",
"Magellan", "Onizuka", "Pickover", "Pike",
"Rees", "Sakharov", "Tichy", "Voltaire"
};
static UNIT Units[UNIT_MAX + 2]; /* 0 is invalid, shared with frontend */
/*******************************************************************************
* CODE *
*******************************************************************************/
/*
* Name:
* unitSetName
* Description:
* Creates a name for given unit, based on given unittype
* Input:
* punit *: Pointer on unit to create name for
* ut *: Pointer on unit type
*/
static void unitSetName(UNIT *punit, UNITTYPE *ut)
{
sprintf(punit -> name, "%s %d", ut -> name, fsctoolRand(600));
}
/* ========================================================================== */
/* ======================= PUBLIC FUNCTIONS ================================= */
/* ========================================================================== */
/*
* Name:
* unitInit
* Description:
* Initializes the buffer for the units
* Input:
* None
*/
void unitInit(void)
{
memset(&Units[0], 0, sizeof(UNIT) * (UNIT_MAX + 2));
}
/*
* Name:
* unitName
* Description:
* Returns the name of the unit with the given id
* Input:
* Unitid
*/
char *unitName(int unitno)
{
static int nameno = 0;
nameno += (3 + unitno);
nameno %= 19;
return(UnitNames[nameno]);
}
/*
* Name:
* unitGet
* Description:
* Returns a pointer on the unit with given id. If the id is invalid
* then a pointer on unit 0 is returned.
* Input:
* Unitid
*/
UNIT *unitGet(int unitno)
{
if ((unitno < 1) || (unitno >= UNIT_MAX)) {
Units[0].type = -1; /* Unit is invalid */
return &Units[0];
}
return &Units[unitno];
}
/*
* Name:
* unitGetList
* Description:
* Fills in the id' of the players units into given list
* Counts all units for given owner.
* Input:
* owner: Number of owner to counts unit for (-1: all players)
* plist *: Where to return the numbers of units
* withorder: Only units with this order (-1: all units)
* Output:
* Number of units in list.
*/
int unitGetList(char owner, int *plist, char withorder)
{
int i;
int count;
count = 0;
for(i = 1; i < UNIT_MAX; i++) {
/* First check if we have to bail out */
if (Units[i].type == 0) {
break;
}
if (owner < 0 || Units[i].owner == owner) {
if ((withorder < 0) || (Units[i].order.what == withorder)){
*plist = i; /* Save number of unit */
plist++;
count++;
}
}
}
*plist = 0; /* Sign end of list */
return count;
}
/* --------- Unit list functions ---------- */
/*
* Name:
* unitListRemove
* Description:
* Removes unit with given if from iven liked list
* Input:
* base *:
* unitno:
*/
void unitListRemove(int *base, int unitno)
{
UNIT *pactual;
int actualunit;
if ((*base) == 0) {
return; /* Error, should never happen */
}
actualunit = *base;
do {
pactual = &Units[actualunit];
if (actualunit == unitno) {
/* found it, remove it */
(*base) = pactual -> nextid; /* Attach next to prevoius unit */
pactual -> nextid = 0; /* Set next to zero */
return;
}
base = &pactual -> nextid; /* Where to attach next, if */
/* actual unit is removed */
actualunit = pactual -> nextid;
}
while (actualunit);
}
/*
* Name:
* unitListInsert
* Description:
* Adds a unit to the given list. Add it at the front of possible units
* already in existing list on tile
* Input:
* base *: Pointer on base of linked list
* unitno: Id of unit to add to list
* Replaces:
*
*/
void unitListInsert(int *base, int unitno)
{
int oldbase;
oldbase = (*base); /* Save posible actual unit for attachment */
/* If none available, is anyway 0! */
(*base) = unitno; /* Insert new unit at base */
Units[unitno].nextid = oldbase; /* Attach previous unit(s) to base */
}
/*
* Name:
* unitListFind
* Description:
* Looks for a unit in given list.
* Input:
* base *: Pointer on base of linked list
* unitno: Id of unit to look in list for
* Output:
* Number of given unit, if succeeded, else 0
*/
int unitListFind(int *base, int unitno)
{
UNIT *punit;
int next;
next = (*base);
while (next)
{
punit = &Units[next];
if (next == unitno)
{
return next;
}
next = punit -> nextid;
}
return 0;
}
/*
* Name:
* unitListCount
* Description:
* Counts the units in the given list.
* Input:
* base *: Pointer on base of linked list
* Output:
* Number of units in list.
*/
int unitListCount(int *base)
{
UNIT *punit;
int next;
int cnt;
cnt = 0;
next = (*base);
while (next) {
punit = &Units[next];
cnt++;
next = punit -> nextid;
}
return cnt;
}
/*
* Name:
* unitDelete
* Description:
* Removes a unit from thr games internal table
* Input:
* punit *: Pointer on unit to delete.
* Replaces:
* wipe_unit
*/
void unitDelete(UNIT *punit)
{
memset(punit, 0, sizeof(UNIT));
punit -> type = UNIT_FREESLOT_TYPE; /* Is a free slot */
}
/*
* Name:
* unitCreate
* Description:
* On success, returns the id of a new created unit, else 0.
* Input:
* unittype: Type of unit to create
* owner: Owner of unit
* pos: Position of unit
* cargo_load: Cargo to load on unit, if any
* Output:
* Pointer on unit slot, or pointer on Slot 0, if failed
*/
int unitCreate(char unittype, char owner, int pos, char cargo_load)
{
int i;
UNIT *punit;
UNITTYPE *ut;
for (i = 1; i < UNIT_MAX; i++) {
if (Units[i].type <= 0) {
punit = &Units[i];
/* We found a free slot - initialize it */
memset(punit, 0, sizeof(UNIT));
/* -------- Add the info part --------- */
punit -> type = unittype;
punit -> nation = owner;
punit -> owner = owner;
punit -> pos = pos;
punit -> cargo_load = cargo_load;
punit -> order.what = ORDER_NONE;
punit -> level = 0;
/* Add the additional info from unittype */
ut = unittypeGet(unittype);
punit -> hp[UI_VALUE_FULL] = ut -> hit;
punit -> hp[UI_VALUE_ACT] = ut -> hit;
punit -> moves[UI_VALUE_FULL] = ut -> speed;
punit -> moves[UI_VALUE_ACT] = ut -> speed;
punit -> attack = ut -> att;
punit -> defense = ut -> def;
punit -> sensorrange = ut -> sensorrange;
/* ---- Data usable while game is running --------- */
punit -> ability = ut -> ability; /* UNIT_ABILITY_* saves some func calls */
punit -> range_no = ut -> range; /* To save some call while playing */
/* The range of a ship: 0 / 1 / 2 */
/* RULES_RANGE_* */
unitSetName(punit, ut);
return i;
}
}
return 0; /* Invalid unit */
}
/*
* Name:
* unitCreateFromUnit
* Description:
* On success, returns the id of a new created unit, else 0.
* The unit is created using the given unit as template.
* Input:
* unitno: Unit to use as template
* Output:
* Id of new created unit
*/
int unitCreateFromUnit(int unitno)
{
int i;
for (i = 1; i < UNIT_MAX; i++) {
if (Units[i].pos < 0 || Units[i].type < 0) {
memcpy(&Units[i], &Units[unitno], sizeof(UNIT));
return i;
}
}
return 0;
}
/*
* Name:
* unitRestoreMoves
* Description:
* Restore the move points of all units in game
* Input:
* owner: Number of units owner
*/
void unitRestoreMoves(char owner)
{
UNIT *punit;
punit = &Units[1];
while(punit -> type != 0) {
if (punit -> owner == owner) {
punit -> moves[UI_VALUE_ACT] = punit -> moves[UI_VALUE_FULL];
}
punit++;
}
}
/*
* Name:
* unitGetMilitaryMightSum
* Description:
* Returns the sum of all attack and defense values of active units
* for every player in '*vallist'
* Input:
* attackval *: Sum of attack points
* defenseval *: Sum of defense values
* numvalues: Number of values in arrays
*/
void unitGetMilitaryMightSum(int *attackval, int *defenseval, int numvalues)
{
UNIT *punit;
memset(attackval, 0, numvalues * sizeof(int));
memset(defenseval, 0, numvalues * sizeof(int));
punit = &Units[1];
while(punit -> type != 0) {
if (punit -> owner > 0) {
attackval[punit -> owner] += punit -> attack;
defenseval[punit -> owner] += punit -> defense;
}
punit++;
}
}
/*
* Name:
* unitChangeToAbility
* Description:
* Change the given unit to the type given in argument
* Input:
* punit *: Pointer on unit to change given unit to
* ability: Target ability
*/
void unitChangeToAbility(UNIT *punit, int ability)
{
UNITTYPE *ut, *utold;
char type;
int hitpoints, attack, defense;
type = unittypeBestRoleUnit(0, ability);
ut = unittypeGet(type);
utold = unittypeGet(punit -> type); /* For calculation of bonus */
/* taken from unit changed from */
/* Add the additional info from unittype */
if (utold -> hit > 0) {
hitpoints = ut -> hit * punit -> hp[UI_VALUE_FULL] / utold -> hit;
}
if (utold -> att > 0) {
attack = ut -> att * punit -> attack / utold -> att;
}
if (utold -> def > 0) {
defense = ut -> def * punit -> defense / utold -> def;
}
punit -> type = (char)type; /* New type */
punit -> hp[UI_VALUE_FULL] = (char)hitpoints;
punit -> hp[UI_VALUE_ACT] = (char)hitpoints;
punit -> moves[UI_VALUE_FULL] = 0;
punit -> moves[UI_VALUE_ACT] = 0;
punit -> attack = (char)attack;
punit -> defense = (char)defense;
punit -> sensorrange = ut -> sensorrange;
unitSetName(punit, ut);
punit -> ability = (char)ability; /* UNIT_ABILITY_* saves some func calls */
punit -> range_no = ut -> range; /* To save some call while playing */
/* The range of th ship: 0 / 1 / 2 */
/* RULES_RANGE_* */
}
/* ========= Load and save data of units ========= */
/*
* Name:
* unitGetLoadSaveInfo
* Description:
* If 'save' is true then fill in struct 'info' with data needed for
* saving data given in 'data *'. 'numrec' must hold the maximum number
* of records that can be filled, 'recsize' the maximum size of record to
* be saved.
* Input:
* recsize *: Where to fill in the size of the record
* numrec *: Where to put the number of records to be saved
* save: Return info for save / load given info into game
* Output:
* Pointer on data to get data from / fill in with data
*/
char *unitGetLoadSaveInfo(int *recsize, int *numrec, int save)
{
UNIT *punit;
int numunit;
*recsize = sizeof(UNIT);
if (save) {
punit = &Units[1]; /* Start with first unit */
numunit = 0; /* Count units to be saved */
while(punit -> type != 0) {
numunit++;
punit++;
}
*numrec = numunit;
}
else {
*numrec = UNIT_MAX; /* Maximum number of units available */
}
return (char *)&Units[1];
}