A lot of work on resource gathering, some still bugs may still remain.

Removed hardcoded unit types forever.
Applied a path from jim4 for win32 compilation.
This commit is contained in:
n0body 2003-09-05 17:10:56 +00:00
parent a3ca771643
commit 9fe8fc9ff2
34 changed files with 1099 additions and 1494 deletions

View file

@ -36,6 +36,7 @@
<li>Future 1.19 Release<p>
<ul>
<li>++
<li>New resource harvesting, no hardcoded unit types (from Crestez Leonard).
<li>NEW_UI: Fixed save/load (from Martin Renold).
<li>Pathfinder fixes for when the goal moves (EXPERIMENTAL) (from Russell Smith).
<li>Added repair-costs and repair-hp for units that can be repaired (from Russell Smith).

View file

@ -27,11 +27,11 @@
MODULE = src/action
MSRC = action_attack.c action_board.c action_build.c action_demolish.c \
action_die.c action_follow.c action_harvest.c \
action_move.c action_patrol.c action_repair.c action_research.c \
action_resource.c action_returngoods.c action_spellcast.c \
action_stand.c action_still.c action_train.c action_unload.c \
action_upgradeto.c actions.c command.c
action_die.c action_follow.c action_move.c action_patrol.c \
action_repair.c action_research.c action_resource.c \
action_returngoods.c action_spellcast.c action_stand.c \
action_still.c action_train.c action_unload.c action_upgradeto.c \
actions.c command.c
SRC+= $(addprefix $(MODULE)/,$(MSRC))
HDRS+=

View file

@ -392,7 +392,7 @@ global void HandleActionBuilded(Unit* unit)
//
// If we can harvest from the new building, do it.
//
if (worker->Type->Harvester&&worker->Type->ResourceHarvested==type->GivesResource) {
if (worker->Type->ResInfo[type->GivesResource]) {
CommandResource(worker,unit,0);
}
}

View file

@ -1,484 +0,0 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name action_harvest.c - The harvest action. */
//
// (c) Copyright 1998-2001,2003 by Lutz Sammer
//
// 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; version 2 dated June, 1991.
//
// 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 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.
//
// $Id$
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "stratagus.h"
#include "unittype.h"
#include "player.h"
#include "unit.h"
#include "actions.h"
#include "sound.h"
#include "tileset.h"
#include "map.h"
#include "interface.h"
#include "pathfinder.h"
#include "upgrade_structs.h"
// FIXME: Should combine all the resource functions
// FIXME: Should update buttons if the action changes?
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/**
** Move to forest.
**
** @param unit Pointer to worker unit.
**
** @return TRUE if reached, otherwise FALSE.
*/
local int MoveToWood(Unit* unit)
{
int i;
int x;
int y;
if( (i=DoActionMove(unit))>=0 ) { // reached end-point?
return 0;
}
if( i==PF_UNREACHABLE ) {
newtry:
if( FindWoodInSight(unit,&unit->Orders[0].X,&unit->Orders[0].Y) ) {
// Move to new wood position
unit->Orders[0].Goal=NoUnitP;
unit->Orders[0].RangeX=unit->Orders[0].RangeY=1;
NewResetPath(unit);
return 0;
}
// FIXME: Should do more tries
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
return 0;
}
x=unit->Orders[0].X;
y=unit->Orders[0].Y;
if( !CheckedForestOnMap(x,y) ) {
//
// Fast check surrounding for forest
//
x=unit->X;
y=unit->Y;
if( CheckedForestOnMap(x-1,y-1) ) {
--x;
--y;
} else if( CheckedForestOnMap(x-1,y+0) ) {
--x;
} else if( CheckedForestOnMap(x-1,y+1) ) {
--x;
++y;
} else if( CheckedForestOnMap(x+0,y-1) ) {
--y;
} else if( CheckedForestOnMap(x+0,y+1) ) {
++y;
} else if( CheckedForestOnMap(x+1,y-1) ) {
++x;
--y;
} else if( CheckedForestOnMap(x+1,y+0) ) {
++x;
} else if( CheckedForestOnMap(x+1,y+1) ) {
++x;
++y;
} else {
DebugLevel3Fn("No Wood, Trying a better spot\n");
goto newtry;
}
}
// FIXME: don't chop the same wood!
unit->Orders[0].X=x;
unit->Orders[0].Y=y;
unit->Orders[0].RangeX=unit->Orders[0].RangeY=0;
DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
// turn to wood
UnitHeadingFromDeltaXY(unit,x-unit->X,y-unit->Y);
//unit->Value=unit->Data.Harvest.WoodToHarvest;
DebugCheck( unit->Wait!=1 );
return 1;
}
/**
** Chop the wood.
**
** @param unit Pointer to worker unit.
**
** @return TRUE if ready, otherwise FALSE.
*/
local int ChopWood(Unit* unit)
{
Unit* destu;
int flags;
flags=UnitShowAnimation(unit,unit->Type->Animations->Attack);
if( (flags&AnimationSound) && (UnitVisibleOnMap(unit) || ReplayRevealMap) ) {
PlayUnitSound(unit,VoiceTreeChopping);
}
if( unit->Reset ) {
DebugCheck( unit->Wait!=1 );
//
// This a work around the bug: "lumber bug"
// We give a worker a new command and in the next cycle
// the worker is ready chopping.
//
#if 1
if( unit->Orders[1].Action==UnitActionHarvest
|| unit->Orders[1].Action==UnitActionResource ) {
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
return 0;
}
#endif
//
// Wood gone while chopping?
//
if( !ForestOnMap(unit->Orders[0].X,unit->Orders[0].Y) ) {
if( FindWoodInSight(unit,&unit->Orders[0].X,&unit->Orders[0].Y) ) {
unit->Orders[0].Goal=NoUnitP;
unit->Orders[0].RangeX=unit->Orders[0].RangeY=0;
DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
unit->Orders[0].X--;
unit->Orders[0].Y--;
NewResetPath(unit);
unit->SubAction=1;
} else {
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
DebugLevel3Fn("NO-WOOD in sight range\n");
}
return 0;
}
//
// Ready chopping wood?
//
if( !--unit->Value ) {
// Have wood
unit->Player->UnitTypesCount[unit->Type->Type]--;
if( unit->Type==UnitTypeOrcWorker ) {
unit->Type=UnitTypeOrcWorkerWithWood;
} else if( unit->Type==UnitTypeHumanWorker ) {
unit->Type=UnitTypeHumanWorkerWithWood;
} else {
// FIXME: support more races!
DebugLevel0Fn("Wrong unit for chopping wood %d\n"
_C_ unit->Type->Type);
}
unit->Player->UnitTypesCount[unit->Type->Type]++;
//
// Update the display.
//
CheckUnitToBeDrawn(unit);
if( IsOnlySelected(unit) ) { // update display
#ifndef NEW_UI
UpdateButtonPanel();
#else
SelectedUnitChanged();
#endif
}
//
// Update the map.
//
MapRemoveWood(unit->Orders[0].X,unit->Orders[0].Y);
#if 0
/*
* This call turned out not to be sufficient because MapRemoveWood()
* may actually remove more that one wood tile (x,y) due to
* "wood fixing" code, see action_harvest.c . So the pathfinder
* callback had to moved directly into MapRemoveWood().
*/
#ifdef HIERARCHIC_PATHFINDER
PfHierMapChangedCallback (unit->Orders[0].X, unit->Orders[0].Y,
unit->Orders[0].X, unit->Orders[0].Y);
#endif
#endif
//
// Find place to return wood.
//
// NOTE: unit->Orders[0].X && unit->Orders[0].Y holds return place.
unit->Orders[0].X=unit->X;
unit->Orders[0].Y=unit->Y;
if( !(destu=FindDeposit(unit->Player,unit->X,unit->Y,WoodCost)) ) {
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
} else {
unit->Orders[0].RangeX=unit->Orders[0].RangeY=0;
unit->Orders[0].Goal=destu;
RefsDebugCheck( !destu->Refs );
destu->Refs++;
DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
NewResetPath(unit);
return 1;
}
}
}
return 0;
}
/**
** Return with the wood.
**
** @param unit unit pointer.
**
** @return TRUE if reached, otherwise FALSE.
*/
local int ReturnWithWood(Unit* unit)
{
Unit* destu;
int i;
destu=unit->Orders[0].Goal;
unit->Orders[0].RangeX=unit->Orders[0].RangeY=1;
DebugCheck( !destu );
i=DoActionMove(unit);
if( i>=0 && (!unit->Reset || !(destu->Destroyed || destu->Removed
|| !destu->HP || destu->Orders[0].Action==UnitActionDie)) ) {
return 0;
}
if( !destu ) {
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
return 0;
}
//
// Target is dead, stop harvest
//
if( destu->Destroyed ) {
DebugLevel0Fn("Destroyed unit\n");
RefsDebugCheck( !destu->Refs );
if( !--destu->Refs ) {
ReleaseUnit(destu);
}
unit->Orders[0].Goal=NoUnitP;
// FIXME: perhaps we should choose an alternative
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
return 0;
} else if( destu->Removed || !destu->HP
|| destu->Orders[0].Action==UnitActionDie ) {
RefsDebugCheck( !destu->Refs );
--destu->Refs;
RefsDebugCheck( !destu->Refs );
unit->Orders[0].Goal=NoUnitP;
// FIXME: perhaps we should choose an alternative
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
return 0;
}
DebugCheck( unit->Wait!=1 );
DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
//
// If depot is still under construction, wait!
//
if( destu->Orders[0].Action==UnitActionBuilded ) {
DebugLevel2Fn("Invalid depot\n");
return 0;
}
unit->Orders[0].Goal=NoUnitP;
RefsDebugCheck( !destu->Refs );
--destu->Refs;
RefsDebugCheck( !destu->Refs );
if( i==PF_UNREACHABLE ) {
// FIXME: could try another depot, or retry later.
DebugLevel2Fn("WOOD-DEPOSIT NOT REACHED %d=%d,%d ? %d\n"
_C_ UnitNumber(destu) _C_ destu->X _C_ destu->Y
_C_ MapDistanceToUnit(unit->X,unit->Y,destu));
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
return 0;
}
RemoveUnit(unit,destu);
#if 0
// FIXME: this breaks the drop out code.
// FIXME: this is a hack, but solves the problem, a better solution is
// FIXME: still wanted.
// Place unit where pathfinder is more likely to work
if (unit->X < destu->X) {
PlaceUnit(unit,destu->X,unit->Y);
RemoveUnit(unit,NULL); // Unit removal necessary to free map tiles
}
if (unit->X > destu->X+destu->Type->TileWidth-1) {
PlaceUnit(unit,destu->X+destu->Type->TileWidth-1,unit->Y);
RemoveUnit(unit,NULL);
}
if (unit->Y < destu->Y) {
PlaceUnit(unit,unit->X,destu->Y);
RemoveUnit(unit,NULL);
}
if (unit->Y > destu->Y+destu->Type->TileHeight-1) {
PlaceUnit(unit,unit->X,destu->Y+destu->Type->TileHeight-1);
RemoveUnit(unit,NULL);
}
#else
unit->X=destu->X;
unit->Y=destu->Y;
#endif
//
// Update wood.
//
unit->Player->Resources[WoodCost]+=unit->Player->Incomes[WoodCost];
unit->Player->TotalResources[WoodCost]+=unit->Player->Incomes[WoodCost];
if( unit->Player==ThisPlayer ) {
MustRedraw|=RedrawResources;
}
unit->Player->UnitTypesCount[unit->Type->Type]--;
if( unit->Type==UnitTypeOrcWorkerWithWood ) {
unit->Type=UnitTypeOrcWorker;
} else if( unit->Type==UnitTypeHumanWorkerWithWood ) {
unit->Type=UnitTypeHumanWorker;
} else {
// FIXME: must support more races.
DebugLevel0Fn("Wrong unit for returning wood %d\n" _C_ unit->Type->Type);
}
unit->Player->UnitTypesCount[unit->Type->Type]++;
unit->Wait=WAIT_FOR_WOOD;
return 1;
}
/**
** Wait in wood deposit.
**
** @param unit Pointer to worker unit.
*/
local int WaitInWoodDeposit(Unit* unit)
{
Unit* destu;
DebugLevel3Fn("Waiting\n");
//
// Drop out unit at nearest point to target.
//
destu=ResourceDepositOnMap(unit->X,unit->Y,WoodCost);
DebugCheck( !destu ); // there must be a depot!
DropOutNearest(unit
,unit->Orders[0].X,unit->Orders[0].Y
,destu->Type->TileWidth,destu->Type->TileHeight);
//
// Return to chop point.
//
DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
unit->Orders[0].Goal=NoUnitP;
unit->Orders[0].RangeX=unit->Orders[0].RangeY=0;
// NOTE: unit->Orders[0].X && unit->Orders[0].Y holds return place.
NewResetPath(unit);
CheckUnitToBeDrawn(unit);
unit->Wait=1;
//unit->Data.Harvest.WoodToHarvest=CHOP_FOR_WOOD;
unit->Value=CHOP_FOR_WOOD;
return 1;
}
/**
** Unit Harvest:
** Move into forest.
** Chop the tree.
** Return to wood store.
** Deliver wood.
** Restart from beginning.
**
** FIXME: we should write a generic resource function
**
** @param unit Pointer to worker unit.
*/
global void HandleActionHarvest(Unit* unit)
{
switch( unit->SubAction ) {
case 0:
NewResetPath(unit);
unit->Value=CHOP_FOR_WOOD;
unit->SubAction=1;
case 1:
if( MoveToWood(unit) ) {
unit->SubAction=64;
}
break;
case 64:
if( ChopWood(unit) ) {
unit->SubAction=128;
}
break;
case 128:
if( ReturnWithWood(unit) ) {
unit->SubAction=192;
}
break;
case 192:
if( WaitInWoodDeposit(unit) ) {
unit->SubAction=0;
}
break;
}
}
//@}

View file

@ -78,6 +78,8 @@ local int ActionMoveGeneric(Unit* unit,const Animation* anim)
// FIXME: state 0?, should be wrong, should be Reset.
// FIXME: Reset flag is cleared by HandleUnitAction.
if( !(state=unit->State) ) {
// FIXME: So units flying up and down are not affected.
unit->IX=unit->IY=0;
#ifdef HIERARCHIC_PATHFINDER
d = PfHierComputePath (unit, &xd, &yd);

View file

@ -50,7 +50,7 @@
----------------------------------------------------------------------------*/
#define SUB_START_RESOURCE 0
#define SUB_MOVE_TO_RESOURCE 1
#define SUB_MOVE_TO_RESOURCE 5
#define SUB_UNREACHABLE_RESOURCE 31
#define SUB_START_GATHERING 55
#define SUB_GATHER_RESOURCE 60
@ -73,24 +73,62 @@
local int MoveToResource(Unit* unit)
{
Unit* goal;
ResourceInfo* resinfo;
int x;
int y;
goal=unit->Orders[0].Goal;
DebugCheck( !goal );
switch( DoActionMove(unit) ) { // reached end-point?
case PF_UNREACHABLE:
return -1;
case PF_REACHED:
break;
default:
if( !unit->Reset || !(goal->Destroyed || goal->Removed
|| !goal->HP || goal->Orders[0].Action==UnitActionDie) ) {
return 0;
resinfo=unit->Type->ResInfo[unit->CurrentResource];
if (resinfo->TerrainHarvester) {
x=unit->Orders->X;
y=unit->Orders->Y;
// Wood gone, look somewhere else.
if ( (!ForestOnMap(x,y)) && (!unit->IX) && (!unit->IY)) {
if (!FindTerrainType(UnitMovementMask(unit),MapFieldForest,0,10,
unit->Player,unit->X,unit->Y,&x,&y)) {
DebugLevel3Fn("No wood in range\n");
return -1;
} else {
DebugLevel3Fn("%d,%d -> %d,%d\n" _C_ unit->X _C_ unit->Y _C_ x _C_ y);
unit->Orders->X=x;
unit->Orders->Y=y;
NewResetPath(unit);
}
break;
}
switch( DoActionMove(unit)) {
case PF_UNREACHABLE:
if (FindTerrainType(UnitMovementMask(unit),MapFieldForest,0,9999,unit->Player,unit->X,unit->Y,&x,&y)) {
unit->Orders->X=x;
unit->Orders->Y=y;
NewResetPath(unit);
DebugLevel3Fn("Found a better place to harvest %d,%d\n" _C_ x _C_ y);
// FIXME: can't this overflow? It really shouldn't, since
// x and y are really supossed to be reachable, checked thorugh a flood fill.
return MoveToResource(unit);
}
return -1;
case PF_REACHED:
return 1;
default:
return 0;
}
} else {
goal=unit->Orders[0].Goal;
DebugCheck( !goal );
switch( DoActionMove(unit) ) { // reached end-point?
case PF_UNREACHABLE:
return -1;
case PF_REACHED:
break;
default:
// Goal gone or something.
if( !unit->Reset || !(goal->Destroyed || goal->Removed
|| !goal->HP || goal->Orders[0].Action==UnitActionDie) ) {
return 0;
}
break;
}
return 1;
}
return 1;
}
/*
@ -103,13 +141,30 @@ local int MoveToResource(Unit* unit)
local int StartGathering(Unit* unit)
{
Unit * goal;
ResourceInfo* resinfo;
resinfo=unit->Type->ResInfo[unit->CurrentResource];
DebugCheck(unit->IX);
DebugCheck(unit->IY);
if (resinfo->TerrainHarvester) {
DebugCheck(!ForestOnMap(unit->Orders->X,unit->Orders->Y));
UnitHeadingFromDeltaXY(unit,unit->Orders->X-unit->X,unit->Orders->Y-unit->Y);
if (resinfo->WaitAtResource) {
unit->Data.ResWorker.TimeToHarvest=resinfo->WaitAtResource;
} else {
unit->Data.ResWorker.TimeToHarvest=1;
}
unit->Data.ResWorker.DoneHarvesting=0;
return 1;
}
goal=unit->Orders[0].Goal;
//
// Target is dead, stop getting resources.
//
if( goal->Destroyed || goal->Removed || !goal->HP ||
goal->Orders[0].Action==UnitActionDie) {
DebugLevel0Fn("Destroyed resource goal, stop gathering.\n");
DebugLevel3Fn("Destroyed resource goal, stop gathering.\n");
RefsDebugCheck( !goal->Refs );
--goal->Refs;
if( goal->Destroyed ) {
@ -119,15 +174,23 @@ local int StartGathering(Unit* unit)
} else {
RefsDebugCheck( !goal->Refs );
}
unit->Orders[0].Goal=NoUnitP;
// Find an alternative, but don't look too far.
unit->Orders[0].X=unit->Orders[0].Y=-1;
// FIXME: Choose an alternative
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
if ((goal=FindResource(unit,unit->X,unit->Y,10))) {
unit->SubAction=SUB_START_RESOURCE;
unit->Orders[0].Goal=goal;
RefsDebugCheck( !goal->Refs );
++goal->Refs;
} else {
unit->Orders[0].Action=UnitActionStill;
unit->Orders[0].Goal=0;
unit->SubAction=0;
}
return 0;
}
// FIXME: 0 can happen, if to near placed by map designer.
DebugLevel3Fn("%d\n" _C_ MapDistanceToUnit(unit->X,unit->Y,goal) );
DebugCheck( MapDistanceToUnit(unit->X,unit->Y,goal)>1 );
//
@ -163,7 +226,7 @@ local int StartGathering(Unit* unit)
//
// Place unit inside the resource
//
if (!unit->Type->HarvestFromOutside) {
if (!resinfo->HarvestFromOutside) {
RefsDebugCheck( !goal->Refs );
--goal->Refs;
@ -175,13 +238,9 @@ local int StartGathering(Unit* unit)
unit->Y=goal->Y;
}
if (unit->Type->WaitAtResource) {
unit->Data.ResWorker.TimeToHarvest=unit->Type->WaitAtResource;
} else {
unit->Data.ResWorker.TimeToHarvest=1;
}
unit->Data.ResWorker.TimeToHarvest=resinfo->WaitAtResource;
unit->Reset=1;
unit->Data.ResWorker.DoneHarvesting=0;
return 1;
}
@ -196,11 +255,7 @@ local void AnimateActionHarvest(Unit* unit)
flags=UnitShowAnimation(unit,unit->Type->Animations->Attack);
#ifdef WITH_SOUND
if( (flags&AnimationSound) ) {
if( GameSounds.Repair.Sound==(void*)-1 ) {
PlayUnitSound(unit,VoiceAttacking);
} else {
PlayUnitSound(unit,VoiceRepair);
}
PlayUnitSound(unit,VoiceTreeChopping);
}
#endif
}
@ -218,133 +273,171 @@ local int GatherResource(Unit* unit)
Unit* source;
Unit* depot;
Unit* uins;
ResourceInfo* resinfo;
int i;
int addload;
if (unit->Type->HarvestFromOutside) {
resinfo=unit->Type->ResInfo[unit->CurrentResource];
source=0;
if (resinfo->HarvestFromOutside||resinfo->TerrainHarvester) {
AnimateActionHarvest(unit);
unit->Data.ResWorker.TimeToHarvest-=unit->Wait;
} else {
unit->Data.ResWorker.TimeToHarvest--;
unit->Wait=1;
}
// This means we have to return.
if (unit->Data.ResWorker.TimeToHarvest==-1) {
DebugCheck(!unit->Type->HarvestFromOutside);
if (unit->Data.ResWorker.DoneHarvesting) {
DebugCheck(!(resinfo->HarvestFromOutside||resinfo->TerrainHarvester));
return unit->Reset;
}
if (--unit->Data.ResWorker.TimeToHarvest) {
DebugLevel3Fn("need to wait %d more cycles.\n" _C_ unit->Data.ResWorker.TimeToHarvest);
// Target gone?
if (resinfo->TerrainHarvester&&!ForestOnMap(unit->Orders->X,unit->Orders->Y)) {
DebugLevel3Fn("Wood gone for unit %d.\n" _C_ unit->Slot);
if (unit->Reset) {
// Action now breakable, move to resource again.
unit->SubAction=SUB_MOVE_TO_RESOURCE;
// Give it some reasonable look while serching.
unit->Frame=unit->Type->Animations->Still->Frame;
}
return 0;
}
unit->Data.ResWorker.TimeToHarvest=unit->Type->WaitAtResource;
if ( unit->Type->HarvestFromOutside ) {
source=unit->Orders[0].Goal;
} else {
source=unit->Container;
// No wood? Freeze!!!
}
DebugCheck( !source );
DebugCheck( source->Value>655350 );
//
// Target is dead, stop getting resources.
//
if( !(source->Destroyed || source->Removed || !source->HP ||
source->Orders[0].Action==UnitActionDie)) {
if (!unit->Data.ResWorker.DoneHarvesting&&unit->Data.ResWorker.TimeToHarvest<0) {
unit->Data.ResWorker.TimeToHarvest+=resinfo->WaitAtResource;
//
// Calculate how much we can load.
//
if (unit->Type->ResourceStep) {
addload = unit->Type->ResourceStep;
//
if (resinfo->ResourceStep) {
addload = resinfo->ResourceStep;
} else {
addload = unit->Type->ResourceCapacity;
}
// Don't load more that there is.
if (addload > source->Value) {
addload = source->Value;
addload = resinfo->ResourceCapacity;
}
// Make sure we don't bite more than we can chew.
if (unit->Value + addload > unit->Type->ResourceCapacity) {
addload = unit->Type->ResourceCapacity - unit->Value;
if (unit->Value + addload > resinfo->ResourceCapacity) {
addload = resinfo->ResourceCapacity - unit->Value;
}
DebugLevel3Fn("Harvested another %d resources.\n" _C_ addload);
unit->Value += addload;
source->Value -= addload;
UnitMarkSeen(source);
if( IsOnlySelected(source) ) {
MustRedraw|=RedrawInfoPanel;
}
// Change unit to full state.
if( unit->Type->TransformWhenLoaded&&unit->Value ) {
unit->Player->UnitTypesCount[unit->Type->Type]--;
unit->Type=unit->Type->TransformWhenLoaded;
unit->Player->UnitTypesCount[unit->Type->Type]++;
}
}
//
// End of resource: destroy the resource.
// FIXME: implement depleted resources.
//
if( source->Destroyed || source->Removed || !source->HP ||
source->Orders[0].Action==UnitActionDie || source->Value==0) {
DebugLevel0Fn("Resource is destroyed\n");
uins=source->UnitInside;
//
// Improved version of DropOutAll that makes workers go to the depot.
// FIXME: empty harvesters whould find another resource.
//
for( i=source->InsideCount; i; --i,uins=uins->NextContained ) {
if (uins->Value && (depot=FindDeposit(uins->Player,uins->X,uins->Y,source->Type->GivesResource))) {
DropOutNearest(uins,depot->X+depot->Type->TileWidth/2
,depot->Y+depot->Type->TileHeight/2
,source->Type->TileWidth,source->Type->TileHeight);
uins->Orders[0].Action=UnitActionReturnGoods;
uins->SubAction=0;
uins->Wait=unit->Reset=1;
uins->Orders[0].Goal=depot;
RefsDebugCheck( !depot->Refs );
++depot->Refs;
DebugLevel0Fn("Sent unit %d to depot\n" _C_ uins->Slot);
continue;
if (resinfo->TerrainHarvester) {
DebugLevel3Fn("Harvested another %d resources.\n" _C_ addload);
unit->Value += addload;
if (addload&&unit->Value==resinfo->ResourceCapacity) {
DebugLevel3("Removed wood.\n");
MapRemoveWood(unit->Orders->X,unit->Orders->Y);
}
DebugLevel0Fn("Unit %d just sits around confused.\n" _C_ uins->Slot);
DropOutOnSide(uins,LookingW
,source->Type->TileWidth,source->Type->TileHeight);
uins->Orders[0].Goal=0;
uins->Orders[0].X=uins->Orders[0].Y=-1;
uins->Orders[0].Action=UnitActionStill;
uins->Wait=unit->Reset=1;
uins->SubAction=0;
}
// Don't destroy the resource twice.
if( !(source->Destroyed || source->Removed || !source->HP ||
source->Orders[0].Action==UnitActionDie)){
LetUnitDie(source);
}
// FIXME: make the workers inside look for a new resource.
source=NULL;
}
// Only return home if we are full.
if (unit->Value < unit->Type->ResourceCapacity || !source) {
return 0;
} else {
if (unit->Type->HarvestFromOutside) {
unit->Data.ResWorker.TimeToHarvest=-1;
return 0;
} else {
return 1;
if ( resinfo->HarvestFromOutside ) {
source=unit->Orders[0].Goal;
} else {
source=unit->Container;
}
DebugCheck( !source );
DebugCheck( source->Value>655350 );
//
// Target is dead, stop getting resources.
//
if( !(source->Destroyed || source->Removed || !source->HP ||
source->Orders[0].Action==UnitActionDie)) {
// Don't load more that there is.
if (addload > source->Value) {
addload = source->Value;
}
DebugLevel3Fn("Harvested another %d resources.\n" _C_ addload);
unit->Value += addload;
source->Value -= addload;
UnitMarkSeen(source);
if( IsOnlySelected(source) ) {
MustRedraw|=RedrawInfoPanel;
}
}
//
// End of resource: destroy the resource.
// FIXME: implement depleted resources.
//
if( source->Destroyed || source->Removed || !source->HP ||
source->Orders[0].Action==UnitActionDie || source->Value==0) {
DebugLevel0Fn("Resource is destroyed\n");
uins=source->UnitInside;
//
// Improved version of DropOutAll that makes workers go to the depot.
// FIXME: empty harvesters should find another resource.
//
for( i=source->InsideCount; i; --i,uins=uins->NextContained ) {
if (uins->Value && (depot=FindDeposit(uins,uins->X,uins->Y,1000))) {
DropOutNearest(uins,depot->X+depot->Type->TileWidth/2
,depot->Y+depot->Type->TileHeight/2
,source->Type->TileWidth,source->Type->TileHeight);
// Remember were it mined, so it can look around for another resource.
uins->Orders[0].Arg1=(void*)((unit->X<<16)|unit->Y);
uins->Orders[0].Goal=depot;
RefsDebugCheck( !depot->Refs );
++depot->Refs;
NewResetPath(uins);
uins->SubAction=SUB_MOVE_TO_DEPOT;
uins->Wait=1;
DebugLevel0Fn("Sent unit %d to depot\n" _C_ uins->Slot);
continue;
}
DropOutOnSide(uins,LookingW
,source->Type->TileWidth,source->Type->TileHeight);
uins->Orders[0].X=uins->Orders[0].Y=-1;
if ((uins->Orders[0].Goal=FindResource(uins,uins->X,uins->Y,10))) {
DebugLevel0Fn("Unit %d found another resource.\n" _C_ uins->Slot);
uins->SubAction=SUB_START_RESOURCE;
uins->Wait=1;
RefsDebugCheck( !uins->Orders[0].Goal->Refs );
++uins->Orders[0].Goal->Refs;
} else {
DebugLevel0Fn("Unit %d just sits around confused.\n" _C_ uins->Slot);
uins->Orders[0].Action=UnitActionStill;
uins->SubAction=0;
uins->Wait=unit->Reset=1;
}
}
// Don't destroy the resource twice.
if( !(source->Destroyed || source->Removed || !source->HP ||
source->Orders[0].Action==UnitActionDie)){
LetUnitDie(source);
// FIXME: make the workers inside look for a new resource.
}
source=NULL;
}
}
if (resinfo->TerrainHarvester) {
if (unit->Value == resinfo->ResourceCapacity) {
// Mark as complete.
DebugLevel3Fn("Done Harvesting, waiting for reset.\n");
unit->Data.ResWorker.DoneHarvesting=1;
}
return 0;
}
if (resinfo->HarvestFromOutside && !resinfo->TerrainHarvester) {
if ((unit->Value == resinfo->ResourceCapacity)||(source==NULL)) {
// Mark as complete.
DebugLevel3Fn("Done Harvesting, waiting for reset %X.\n" _C_ (unsigned)source);
unit->Data.ResWorker.DoneHarvesting=1;
}
return 0;
}
if ((!resinfo->HarvestFromOutside)&& (!resinfo->TerrainHarvester)) {
return unit->Value==resinfo->ResourceCapacity&&source;
}
}
return 0;
}
/**
@ -358,25 +451,31 @@ local int StopGathering(Unit* unit)
{
Unit* depot;
Unit* source;
ResourceInfo* resinfo;
if ( unit->Type->HarvestFromOutside ) {
source=unit->Orders[0].Goal;
} else {
source=unit->Container;
resinfo=unit->Type->ResInfo[unit->CurrentResource];
source=0;
if (!resinfo->TerrainHarvester) {
if ( resinfo->HarvestFromOutside ) {
source=unit->Orders[0].Goal;
} else {
source=unit->Container;
}
source->Data.Resource.Active--;
DebugCheck(source->Data.Resource.Active<0);
}
source->Data.Resource.Active--;
DebugCheck(source->Data.Resource.Active<0);
// Store resource position.
// FIXME: is this the best way?
unit->Orders[0].Arg1=(void*)((unit->X<<16)|unit->Y);
// Find and send to resource deposit.
if( (!(depot=FindDeposit(unit->Player,unit->X,unit->Y,unit->Type->ResourceHarvested)))
if( (!(depot=FindDeposit(unit,unit->X,unit->Y,1000)))
|| (!unit->Value)) {
if (!unit->Type->HarvestFromOutside) {
if (!(resinfo->HarvestFromOutside||resinfo->TerrainHarvester)) {
DebugCheck(!unit->Container);
DropOutOnSide(unit,LookingW,source->Type->TileWidth,source->Type->TileHeight);
}
@ -385,7 +484,7 @@ local int StopGathering(Unit* unit)
unit->SubAction=0;
// should return 0, done below!
} else {
if (!unit->Type->HarvestFromOutside) {
if (!(resinfo->HarvestFromOutside||resinfo->TerrainHarvester)) {
DebugCheck(!unit->Container);
DropOutNearest(unit,depot->X+depot->Type->TileWidth/2
,depot->Y+depot->Type->TileHeight/2
@ -421,6 +520,9 @@ local int StopGathering(Unit* unit)
local int MoveToDepot(Unit* unit)
{
Unit* goal;
ResourceInfo* resinfo;
resinfo=unit->Type->ResInfo[unit->CurrentResource];
goal=unit->Orders[0].Goal;
DebugCheck( !goal );
@ -489,29 +591,17 @@ local int MoveToDepot(Unit* unit)
//
// Update resource.
//
unit->Player->Resources[unit->Type->ResourceHarvested]+=
(unit->Value*unit->Player->Incomes[unit->Type->ResourceHarvested])/100;
unit->Player->TotalResources[unit->Type->ResourceHarvested]+=
(unit->Value*unit->Player->Incomes[unit->Type->ResourceHarvested])/100;
unit->Player->Resources[resinfo->FinalResource]+=
(unit->Value*unit->Player->Incomes[resinfo->FinalResource])/100;
unit->Player->TotalResources[resinfo->FinalResource]+=
(unit->Value*unit->Player->Incomes[resinfo->FinalResource])/100;
unit->Value=0;
if( unit->Player==ThisPlayer ) {
MustRedraw|=RedrawResources;
}
//
// Change unit to empty state.
//
if( unit->Type->TransformWhenEmpty ) {
unit->Player->UnitTypesCount[unit->Type->Type]--;
unit->Type=unit->Type->TransformWhenEmpty;
unit->Player->UnitTypesCount[unit->Type->Type]++;
}
unit->Wait=resinfo->WaitAtDepot;
if (unit->Type->WaitAtDepot) {
unit->Wait=unit->Type->WaitAtDepot;
} else {
unit->Wait=1;
}
return 1;
}
@ -526,10 +616,13 @@ local int WaitInDepot(Unit* unit)
{
const Unit* depot;
Unit* goal;
ResourceInfo* resinfo;
int x;
int y;
depot=ResourceDepositOnMap(unit->X,unit->Y,unit->Type->ResourceHarvested);
resinfo=unit->Type->ResInfo[unit->CurrentResource];
depot=ResourceDepositOnMap(unit->X,unit->Y,resinfo->ResourceId);
DebugCheck( !depot );
// Could be destroyed, but then we couldn't be in?
@ -540,20 +633,33 @@ local int WaitInDepot(Unit* unit)
x=(int)unit->Orders[0].Arg1>>16;
y=(int)unit->Orders[0].Arg1&0xFFFF;
}
if( !(goal=FindResource(unit->Player,x,y,unit->Type->ResourceHarvested)) ) {
DropOutOnSide(unit,LookingW,
depot->Type->TileWidth,depot->Type->TileHeight);
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
// Range hardcoded. don't stray too far though
if( resinfo->TerrainHarvester ) {
if (FindTerrainType(UnitMovementMask(unit),MapFieldForest,0,10,
unit->Player,x,y,&x,&y)) {
DropOutNearest(unit,x,y,depot->Type->TileWidth,depot->Type->TileHeight);
unit->Orders->X=x;
unit->Orders->Y=y;
} else {
DropOutOnSide(unit,LookingW,depot->Type->TileWidth,depot->Type->TileHeight);
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
}
} else {
DropOutNearest(unit,goal->X+goal->Type->TileWidth/2
,goal->Y+goal->Type->TileHeight/2
,depot->Type->TileWidth,depot->Type->TileHeight);
unit->Orders[0].Goal=goal;
RefsDebugCheck( !goal->Refs );
++goal->Refs;
unit->Orders[0].RangeX=unit->Orders[0].RangeY=1;
unit->Orders[0].X=unit->Orders[0].Y=-1;
if ((goal=FindResource(unit,x,y,10))) {
DropOutNearest(unit,goal->X+goal->Type->TileWidth/2
,goal->Y+goal->Type->TileHeight/2
,depot->Type->TileWidth,depot->Type->TileHeight);
unit->Orders[0].Goal=goal;
RefsDebugCheck( !goal->Refs );
++goal->Refs;
unit->Orders[0].RangeX=unit->Orders[0].RangeY=1;
unit->Orders[0].X=unit->Orders[0].Y=-1;
} else {
DropOutOnSide(unit,LookingW,depot->Type->TileWidth,depot->Type->TileHeight);
unit->Orders[0].Action=UnitActionStill;
unit->SubAction=0;
}
}
CheckUnitToBeDrawn(unit);
@ -574,6 +680,10 @@ void ResourceGiveUp(Unit* unit)
unit->Reset=1;
unit->Orders[0].X=unit->Orders[0].Y=-1;
unit->SubAction=0;
if( unit->Type->ResInfo[unit->CurrentResource]->LoseResources ) {
unit->Value=0;
unit->CurrentResource=0;
}
if( unit->Orders[0].Goal ) {
RefsDebugCheck( !unit->Orders[0].Goal->Refs );
--unit->Orders[0].Goal->Refs;
@ -591,13 +701,23 @@ void ResourceGiveUp(Unit* unit)
*/
global void HandleActionResource(Unit* unit)
{
int ret;
int ret,newres;
DebugLevel3Fn("%s(%d) SubAction %d\n"
_C_ unit->Type->Ident _C_ UnitNumber(unit) _C_ unit->SubAction);
// Let's start mining.
if ( unit->SubAction==SUB_START_RESOURCE ) {
if (unit->Orders->Goal) {
newres=unit->Orders->Goal->Type->GivesResource;
} else {
newres=WoodCost;
}
if (newres!=unit->CurrentResource) {
// Drop other resources.
unit->Value=0;
}
unit->CurrentResource=newres;
NewResetPath(unit);
DebugLevel3Fn("Started mining. reset path.\n");
unit->SubAction=SUB_MOVE_TO_RESOURCE;
@ -632,8 +752,9 @@ global void HandleActionResource(Unit* unit)
if (unit->SubAction==SUB_START_GATHERING) {
if (StartGathering(unit)) {
unit->SubAction=SUB_GATHER_RESOURCE;
}
} else {
return;
}
}
// Gather the resource.

View file

@ -54,9 +54,9 @@
/**
** Return goods to gold/wood deposit.
**
** FIXME: must support to move to a specified deposit.
**
** @param unit pointer to unit.
**
** FIXME: move this into action_resource?
*/
global void HandleActionReturnGoods(Unit* unit)
{
@ -65,56 +65,30 @@ global void HandleActionReturnGoods(Unit* unit)
type=unit->Type;
//
// Select target to return goods. FIXME: more races support
// Select target to return goods.
//
if( type->Harvester ) {
if( !unit->Orders[0].Goal ) {
if( !(destu=FindDeposit(unit->Player,unit->X,unit->Y,type->ResourceHarvested)) ) {
DebugLevel3Fn("No deposit -> can't return\n");
unit->Orders[0].Action=UnitActionStill;
return;
}
unit->Orders[0].Goal=destu;
RefsDebugCheck( !destu->Refs );
++destu->Refs;
DebugCheck(!type->Harvester );
if( !unit->Orders[0].Goal ) {
if( !(destu=FindDeposit(unit,unit->X,unit->Y,1000)) ) {
DebugLevel3Fn("No deposit -> can't return\n");
unit->Orders[0].Action=UnitActionStill;
return;
}
DebugLevel3("Return to %d=%d,%d\n"
_C_ UnitNumber(unit->Orders[0].Goal)
_C_ unit->Orders[0].X _C_ unit->Orders[0].Y);
unit->Orders[0].Action=UnitActionResource;
// Somewhere on the way the loaded worker changed Arg1.
// Bummer, go get the closest resource to the depot
unit->Orders[0].Arg1=(void*)-1;
NewResetPath(unit);
unit->SubAction=70;
unit->Wait=1;
return;
}
if( type==UnitTypeHumanWorkerWithWood || type==UnitTypeOrcWorkerWithWood ) {
if( !unit->Orders[0].Goal ) {
if( !(destu=FindDeposit(unit->Player,unit->X,unit->Y,WoodCost)) ) {
// No deposit -> can't return
unit->Orders[0].Action=UnitActionStill;
return;
}
unit->Orders[0].Goal=destu;
RefsDebugCheck( !destu->Refs );
++destu->Refs;
}
unit->Orders[0].X=unit->X;
unit->Orders[0].Y=unit->Y; // Return point to continue.
DebugLevel3("Return to %d=%d,%d\n"
_C_ UnitNumber(unit->Orders[0].Goal)
_C_ unit->Orders[0].X _C_ unit->Orders[0].Y);
unit->Orders[0].Action=UnitActionHarvest;
unit->Orders[0].Arg1=(void*)-1;
NewResetPath(unit);
unit->SubAction=128; // FIXME: Hardcoded
DebugLevel3("Wait: %d\n" _C_ unit->Wait);
unit->Wait=1;
return;
unit->Orders[0].Goal=destu;
RefsDebugCheck( !destu->Refs );
++destu->Refs;
}
DebugLevel3("Return to %d=%d,%d\n"
_C_ UnitNumber(unit->Orders[0].Goal)
_C_ unit->Orders[0].X _C_ unit->Orders[0].Y);
unit->Orders[0].Action=UnitActionResource;
// Somewhere on the way the loaded worker could have change Arg1
// Bummer, go get the closest resource to the depot
unit->Orders[0].Arg1=(void*)-1;
NewResetPath(unit);
unit->SubAction=70;
unit->Wait=1;
return;
}
//@}

View file

@ -155,9 +155,6 @@ global void HandleActionTrain(Unit* unit)
&& !nunit->Type->Harvester)
|| (unit->NewOrder.Action==UnitActionAttack
&& !nunit->Type->CanAttack)
|| ((unit->NewOrder.Action==UnitActionHarvest)
&& nunit->Type!=UnitTypeOrcWorker
&& nunit->Type!=UnitTypeHumanWorker )
|| (unit->NewOrder.Action==UnitActionBoard
&& nunit->Type->UnitType!=UnitTypeLand) ) {
DebugLevel0Fn("Wrong order for unit\n");

View file

@ -174,10 +174,10 @@ local void (*HandleActionTable[256])(Unit*) = {
HandleActionPatrol,
HandleActionBuild,
HandleActionRepair,
HandleActionHarvest,
HandleActionResource,
HandleActionReturnGoods,
HandleActionDemolish,
HandleActionNotWritten,
// Enough for the future ?
HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten,
@ -268,7 +268,7 @@ local void (*HandleActionTable[256])(Unit*) = {
local void HandleUnitAction(Unit* unit)
{
int z;
//
// If current action is breakable proceed with next one.
//
@ -306,6 +306,11 @@ local void HandleUnitAction(Unit* unit)
ReleaseUnit(unit->Orders[0].Goal);
}
}
if (unit->CurrentResource) {
if (unit->Type->ResInfo[unit->CurrentResource]->LoseResources) {
unit->Value=0;
}
}
//
// Shift queue with structure assignment.

View file

@ -702,29 +702,23 @@ global void CommandCancelBuilding(Unit* unit,
}
/**
** Send unit harvest
** Send unit harvest a location
**
** @param unit pointer to unit.
** @param x X map position for harvest.
** @param y Y map position for harvest.
** @param flush if true, flush command queue.
*/
global void CommandHarvest(Unit* unit,int x,int y,int flush)
global void CommandResourceLoc(Unit* unit,int x,int y,int flush)
{
Order* order;
int nx;
int ny;
//
// Check if unit is still valid? (NETWORK!)
//
if( !unit->Removed && unit->Orders[0].Action!=UnitActionDie ) {
// FIXME: more races, could happen with many orders in queue.
if( !unit->Type->Building
&& unit->Type!=UnitTypeHumanWorker
&& unit->Type!=UnitTypeOrcWorker ) {
DebugLevel0Fn("None worker gets order\n");
ClearSavedAction(unit);
return;
}
if( unit->Type->Building ) {
// FIXME: should find a better way for pending orders.
order=&unit->NewOrder;
@ -733,9 +727,27 @@ global void CommandHarvest(Unit* unit,int x,int y,int flush)
return;
}
order->Action=UnitActionHarvest;
order->X=x;
order->Y=y;
order->Action=UnitActionResource;
// Find the closest piece of wood next to a tile where the unit can move
DebugLevel3("Want to harvest from %d,%d.\n" _C_ x _C_ y);
if (!FindTerrainType(0,(unit->Type->MovementMask),1,20,unit->Player,x,y,&nx,&ny)) {
DebugLevel0Fn("FIXME: Give up???\n");
}
if (max(abs(nx-x),abs(ny-y))>1) {
DebugLevel3("Closest tile reachable is at %d,%d.\n" _C_ x _C_ y);
if (!FindTerrainType(0,MapFieldForest,0,20,unit->Player,nx,ny,&nx,&ny)) {
DebugLevel0Fn("FIXME: Give up???\n");
}
} else {
// The destination is next to a reacahble tile.
nx=x;
ny=y;
}
DebugLevel3("So the final destination is %d,%d.\n" _C_ nx _C_ ny);
order->X=nx;
order->Y=ny;
order->RangeX=order->RangeY=1;
order->Goal=NoUnitP;
order->Type=NULL;
@ -806,8 +818,7 @@ global void CommandReturnGoods(Unit* unit,Unit* goal,int flush)
// FIXME: more races, could happen with many orders in queue.
if( !unit->Type->Building
&& !unit->Type->Harvester
&& unit->Type!=UnitTypeHumanWorkerWithWood
&& unit->Type!=UnitTypeOrcWorkerWithWood) {
&& !unit->Value ) {
ClearSavedAction(unit);
return;
}

View file

@ -744,180 +744,12 @@ local void AiCheckingWork(void)
**
** @return Pointer to the nearest reachable gold mine.
**
** @see FindGoldMine but this version doesn't check for explored tiles.
** @see FindGoldMine
*/
local Unit* AiFindGoldMine(const Unit* unit)
{
static const int xoffset[]={ 0,-1,+1, 0, -1,+1,-1,+1 };
static const int yoffset[]={ -1, 0, 0,+1, -1,-1,+1,+1 };
struct {
unsigned short X;
unsigned short Y;
} * points;
int size;
int x;
int y;
int rx;
int ry;
int mask;
int wp;
int rp;
int ep;
int i;
int w;
int n;
unsigned char* m;
unsigned char* matrix;
const Unit* destu;
Unit* mine;
Unit* bestmine;
int destx;
int desty;
int bestx;
int besty;
int bestd;
destx=x=unit->X;
desty=y=unit->Y;
size=TheMap.Width*TheMap.Height/4;
points=malloc(size*sizeof(*points));
//
// Find the nearest gold depot
//
if( (destu=FindDeposit(unit->Player,x,y,GoldCost)) ) {
NearestOfUnit(destu,x,y,&destx,&desty);
}
bestd=99999;
IfDebug( bestx=besty=0; ); // keep the compiler happy
//
// Make movement matrix. FIXME: can create smaller matrix.
//
matrix=CreateMatrix();
w=TheMap.Width+2;
matrix+=w+w+2;
//
// Mark sight range as border. FIXME: matrix didn't need to be bigger.
//
n=unit->Stats->SightRange;
rx=x-n;
if( rx<0 ) {
rx=0;
}
ep=x+n;
if( ep>TheMap.Width ) {
ep=TheMap.Width;
}
ry=y-n;
if( ry<0 ) {
ry=0;
}
wp=y+n;
if( wp>TheMap.Height ) {
wp=TheMap.Height;
}
for( i=rx; i<ep; ++i ) { // top bottom line
matrix[i+ry*w]=matrix[i+wp*w]=66;
}
for( i=ry+1; i<wp-1; ++i ) {
matrix[rx+i*w]=matrix[ep+i*w]=66;
}
#if 0
matrix[x+n+(y+n)*w]=matrix[x-n+(y+n)*w]=
matrix[x+n+(y-n)*w]=matrix[x-n+(y-n)*w]=66;
for( i=n; i--; ) {
// FIXME: marks out of map area
DebugCheck( x-i+(y-n)*w<0 || x+i+(y+n)*w>w*TheMap.Hight );
matrix[x+n+(y+i)*w]=matrix[x-n+(y+i)*w]=
matrix[x+n+(y-i)*w]=matrix[x-n+(y-i)*w]=
matrix[x-i+(y+n)*w]=matrix[x+i+(y+n)*w]=
matrix[x-i+(y-n)*w]=matrix[x+i+(y-n)*w]=66;
}
#endif
mask=UnitMovementMask(unit);
points[0].X=x;
points[0].Y=y;
rp=0;
matrix[x+y*w]=1; // mark start point
ep=wp=1; // start with one point
bestmine=NoUnitP;
//
// Pop a point from stack, push all neighbors which could be entered.
//
for( ;; ) {
while( rp!=ep ) {
rx=points[rp].X;
ry=points[rp].Y;
for( i=0; i<8; ++i ) { // mark all neighbors
x=rx+xoffset[i];
y=ry+yoffset[i];
m=matrix+x+y*w;
if( *m ) { // already checked
continue;
}
//
// Look if there is a mine
//
if ( (mine=ResourceOnMap(x,y,GoldCost)) ) {
if( destu ) {
n=max(abs(destx-x),abs(desty-y));
if( n<bestd ) {
bestd=n;
bestx=x;
besty=y;
bestmine=mine;
}
*m=22;
} else { // no goal take the first
free(points);
return mine;
}
}
if( CanMoveToMask(x,y,mask) ) { // reachable
*m=1;
points[wp].X=x; // push the point
points[wp].Y=y;
if( ++wp>=size ) { // round about
wp=0;
}
} else { // unreachable
*m=99;
}
}
if( ++rp>=size ) { // round about
rp=0;
}
}
//
// Take best of this frame, if any.
//
if( bestd!=99999 ) {
free(points);
return bestmine;
}
//
// Continue with next frame.
//
if( rp==wp ) { // unreachable, no more points available
break;
}
ep=wp;
}
DebugLevel3Fn("no mine in sight-range\n");
free(points);
return NoUnitP;
// FIXME: explored tiles?
return FindResource(unit,unit->X,unit->Y,100);
}
/**
@ -939,113 +771,12 @@ local int AiMineGold(Unit* unit)
_C_ unit->Type->Ident _C_ unit->X _C_ unit->Y);
return 0;
}
DebugCheck(unit->Type != UnitTypeHumanWorker
&& unit->Type != UnitTypeOrcWorker);
CommandResource(unit, dest, FlushCommands);
return 1;
}
#if 0
/**
** Assign worker to harvest.
**
** @param unit Find wood for this worker.
*/
local int AiHarvest(Unit * unit)
{
int x, y, addx, addy, i, n, r, wx, wy, bestx, besty, cost;
Unit *dest;
DebugLevel3Fn("%d\n" _C_ UnitNumber(unit));
x = unit->X;
y = unit->Y;
addx = unit->Type->TileWidth;
addy = unit->Type->TileHeight;
r = TheMap.Width;
if (r < TheMap.Height) {
r = TheMap.Height;
}
// This is correct, but can this be written faster???
if ((dest = FindWoodDeposit(unit->Player, x, y))) {
NearestOfUnit(dest, x, y, &wx, &wy);
DebugLevel3("To %d,%d\n" _C_ wx _C_ wy);
} else {
wx = unit->X;
wy = unit->Y;
}
cost = 99999;
IfDebug(bestx = besty = 0; ); // keep the compiler happy
// FIXME: if we reach the map borders we can go fast up, left, ...
--x;
while (addx <= r && addy <= r) {
for (i = addy; i--; y++) { // go down
if (CheckedForestOnMap(x, y)) {
n = max(abs(wx - x), abs(wy - y));
DebugLevel3("Distance %d,%d %d\n" _C_ x _C_ y _C_ n);
if (n < cost && PlaceReachable(unit, x-1, y-1, 3)) {
cost = n;
bestx = x;
besty = y;
}
}
}
++addx;
for (i = addx; i--; x++) { // go right
if (CheckedForestOnMap(x, y)) {
n = max(abs(wx - x), abs(wy - y));
DebugLevel3("Distance %d,%d %d\n" _C_ x _C_ y _C_ n);
if (n < cost && PlaceReachable(unit, x-1, y-1, 3)) {
cost = n;
bestx = x;
besty = y;
}
}
}
++addy;
for (i = addy; i--; y--) { // go up
if (CheckedForestOnMap(x, y)) {
n = max(abs(wx - x), abs(wy - y));
DebugLevel3("Distance %d,%d %d\n" _C_ x _C_ y _C_ n);
if (n < cost && PlaceReachable(unit, x-1, y-1, 3)) {
cost = n;
bestx = x;
besty = y;
}
}
}
++addx;
for (i = addx; i--; x--) { // go left
if (CheckedForestOnMap(x, y)) {
n = max(abs(wx - x), abs(wy - y));
DebugLevel3("Distance %d,%d %d\n" _C_ x _C_ y _C_ n);
if (n < cost && PlaceReachable(unit, x-1, y-1, 3)) {
cost = n;
bestx = x;
besty = y;
}
}
}
if (cost != 99999) {
DebugLevel3Fn("wood on %d,%d\n" _C_ x _C_ y);
DebugCheck(unit->Type!=UnitTypeHumanWorker && unit->Type!=UnitTypeOrcWorker);
CommandHarvest(unit, bestx, besty,FlushCommands);
return 1;
}
++addy;
}
DebugLevel0Fn("no wood reachable by %s(%d,%d)\n");
_C_ unit->Type->Ident _C_ unit->X _C_ unit->Y);
return 0;
}
#else
/**
** Assign worker to harvest.
**
@ -1090,7 +821,7 @@ local int AiHarvest(Unit * unit)
//
// Find the nearest wood depot
//
if( (destu=FindDeposit(unit->Player,x,y,WoodCost)) ) {
if( (destu=FindDeposit(unit,x,y,100)) ) {
NearestOfUnit(destu,x,y,&destx,&desty);
}
bestd=99999;
@ -1139,9 +870,7 @@ local int AiHarvest(Unit * unit)
}
*m=22;
} else { // no goal take the first
DebugCheck(unit->Type!=UnitTypeHumanWorker
&& unit->Type!=UnitTypeOrcWorker);
CommandHarvest(unit,x,y,FlushCommands);
CommandResourceLoc(unit,x,y,FlushCommands);
free(points);
return 1;
}
@ -1167,9 +896,7 @@ local int AiHarvest(Unit * unit)
// Take best of this frame, if any.
//
if( bestd!=99999 ) {
DebugCheck(unit->Type!=UnitTypeHumanWorker
&& unit->Type!=UnitTypeOrcWorker);
CommandHarvest(unit, bestx, besty,FlushCommands);
CommandResourceLoc(unit, bestx, besty,FlushCommands);
free(points);
return 1;
}
@ -1190,8 +917,6 @@ local int AiHarvest(Unit * unit)
return 0;
}
#endif
/**
** Assign worker to haul oil.
*/
@ -1200,7 +925,8 @@ local int AiHaulOil(Unit * unit)
Unit *dest;
DebugLevel3Fn("%d\n" _C_ UnitNumber(unit));
dest = FindResource(unit->Player, unit->X, unit->Y ,unit->Type->ResourceHarvested);
// Range hardcoded. search the whole map!!!
dest = FindResource(unit, unit->X, unit->Y,1000);
if (!dest) {
DebugLevel3Fn("oil platform not reachable by %s(%d,%d)\n"
_C_ unit->Type->Ident _C_ unit->X _C_ unit->Y);
@ -1261,27 +987,19 @@ local void AiCollectResources(void)
if( !unit->Type->Harvester ) {
continue;
}
c=unit->Type->ResourceHarvested;
//
// See if it's assigned already
//
switch( unit->Orders[0].Action ) {
case UnitActionHarvest:
units_assigned[num_units_assigned[WoodCost]++][WoodCost]=unit;
continue;
case UnitActionResource:
units_assigned[num_units_assigned[c]++][c]=unit;
continue;
default:
break;
if (unit->Orders[0].Action==UnitActionResource) {
c=unit->CurrentResource;
units_assigned[num_units_assigned[c]++][c]=unit;
}
//
// Send workers with resources back home.
//
if (unit->Value||unit->Type==UnitTypeHumanWorkerWithWood
||unit->Type==UnitTypeOrcWorkerWithWood) {
if (unit->Value) {
units_with_resource[num_units_with_resource[c]++][c]=unit;
if (unit->Orders[0].Action == UnitActionStill
&& unit->OrderCount==1 ) {
@ -1293,7 +1011,10 @@ local void AiCollectResources(void)
// Look what the unit can do
//
for( c=0; c<MaxCosts; ++c ) {
int tn;
if (unit->Type->ResInfo[c]) {
units_unassigned[num_units_unassigned[c]++][c]=unit;
}
#if 0
UnitType** types;
//
@ -1329,6 +1050,7 @@ local void AiCollectResources(void)
if( j<tn ) {
break;
}
#endif
}
}
@ -1418,7 +1140,7 @@ local void AiCollectResources(void)
int n1;
int n2;
case GoldCost:
if( (unit->Orders[0].Action==UnitActionResource&&unit->Type->ResourceHarvested==GoldCost) || AiMineGold(unit) ) {
if( (unit->Orders[0].Action==UnitActionResource&&unit->CurrentResource==GoldCost) || AiMineGold(unit) ) {
DebugLevel3Fn("Assigned to gold\n");
units_assigned[num_units_assigned[c]++][c]=unit;
units_unassigned[i][c] = units_unassigned[--num_units_unassigned[c]][c];
@ -1434,7 +1156,7 @@ local void AiCollectResources(void)
}
break;
case WoodCost:
if( unit->Orders[0].Action==UnitActionHarvest || AiHarvest(unit) ) {
if( (unit->Orders[0].Action==UnitActionResource&&unit->CurrentResource==WoodCost) || AiHarvest(unit) ) {
DebugLevel3Fn("Assigned to harvest\n");
units_assigned[num_units_assigned[c]++][c]=unit;
units_unassigned[i][c] = units_unassigned[--num_units_unassigned[c]][c];
@ -1450,7 +1172,7 @@ local void AiCollectResources(void)
}
break;
case OilCost:
if( (unit->Orders[0].Action==UnitActionResource&&unit->Type->ResourceHarvested==OilCost) || AiHaulOil(unit) ) {
if( (unit->Orders[0].Action==UnitActionResource&&unit->CurrentResource==OilCost) || AiHaulOil(unit) ) {
DebugLevel3Fn("Assigned to oil\n");
units_assigned[num_units_assigned[c]++][c]=unit;
units_unassigned[i][c] = units_unassigned[--num_units_unassigned[c]][c];

View file

@ -100,8 +100,8 @@ extern void CommandUnload(Unit* unit,int x,int y,Unit* what,int flush);
extern void CommandBuildBuilding(Unit*,int,int,UnitType*,int);
/// Prepare command cancel build
extern void CommandCancelBuilding(Unit* unit,Unit* worker);
/// Prepare command harvest
extern void CommandHarvest(Unit* unit,int x,int y,int flush);
/// Prepare command resource location
extern void CommandResourceLoc(Unit* unit,int x,int y,int flush);
/// Prepare command resource
extern void CommandResource(Unit* unit,Unit* dest,int flush);
/// Prepare command return
@ -160,9 +160,7 @@ extern void HandleActionAttack(Unit* unit);
extern void HandleActionBoard(Unit* unit);
/// Handle command unload
extern void HandleActionUnload(Unit* unit);
/// Handle command harvest
extern void HandleActionHarvest(Unit* unit);
/// Handle command haul
/// Handle command resource
extern void HandleActionResource(Unit* unit);
/// Handle command return
extern void HandleActionReturnGoods(Unit* unit);

View file

@ -98,9 +98,9 @@ extern void SendCommandUnload(Unit* unit,int x,int y,Unit* what,int flush);
extern void SendCommandBuildBuilding(Unit*,int,int,UnitType*,int);
/// Send cancel building command
extern void SendCommandCancelBuilding(Unit* unit,Unit* peon);
/// Send harvest location command
extern void SendCommandResourceLoc(Unit* unit,int x,int y,int flush);
/// Send harvest command
extern void SendCommandHarvest(Unit* unit,int x,int y,int flush);
/// Send haul oil command
extern void SendCommandResource(Unit* unit,Unit* dest,int flush);
/// Send return goods command
extern void SendCommandReturnGoods(Unit* unit,Unit* dest,int flush);

View file

@ -47,6 +47,7 @@
#include <bzlib.h>
#undef DrawIcon
#undef EndMenu
#undef FindResource
#endif
#ifdef USE_ZZIPLIB

View file

@ -83,9 +83,8 @@ enum _message_type_ {
MessageCommandUnload, /// Unit command unload
MessageCommandBuild, /// Unit command build building
MessageCommandCancelBuild, /// Unit command cancel building
MessageCommandHarvest, /// Unit command harvest
MessageCommandMine, /// Unit command mine gold
MessageCommandResource, /// Unit command haul oil
MessageCommandResourceLoc, /// Unit command resource location
MessageCommandResource, /// Unit command resource
MessageCommandReturn, /// Unit command return goods
MessageCommandTrain, /// Unit command train
MessageCommandCancelTrain, /// Unit command cancel training

View file

@ -139,6 +139,7 @@
#pragma warning(disable:4244) // Conversion from double to uchar
#pragma warning(disable:4761) // Integral size mismatch
#define snprintf _snprintf /// Unix -> dumm
#define vsnprintf _vsnprintf
#include <string.h>
#define strdup _strdup
#define strncasecmp strnicmp
@ -531,21 +532,8 @@ extern long isqrt(long num);
/// bits macro
#define BitsOf(n) (sizeof(n)*8)
// FIXME: more config stuff which needs a better place
/// How long stay in a gold-mine
#define MINE_FOR_GOLD (150/SpeedResourcesHarvest[GoldCost])
/// How long stay in a gold-deposit
#define WAIT_FOR_GOLD (150/SpeedResourcesReturn[GoldCost])
/// How much I must chop for 1 wood
#define CHOP_FOR_WOOD (52/SpeedResourcesHarvest[WoodCost])
/// How long stay in a wood-deposit
#define WAIT_FOR_WOOD (100/SpeedResourcesReturn[WoodCost])
/// How long stay in a oil-well
#define HAUL_FOR_OIL (100/SpeedResourcesHarvest[OilCost])
/// How long stay in a oil-deposit
#define WAIT_FOR_OIL (100/SpeedResourcesReturn[OilCost])
// FIXME: configurable. maybe we could move it into one big global
// FIXME: settings struct?
/// How many resource get the player back if canceling building
#define CancelBuildingCostsFactor 75
/// How many resource get the player back if canceling training

View file

@ -420,7 +420,6 @@ enum _unit_action_ {
UnitActionBuild, /// unit builds building
UnitActionRepair, /// unit repairing
UnitActionHarvest, /// unit harvest lumber
UnitActionResource, /// unit harvesting resources
UnitActionReturnGoods, /// unit returning any resource
@ -568,6 +567,7 @@ struct _unit_ {
** ,used for fancy buildings
*/
unsigned Rs : 8;
unsigned CurrentResource;
#define MAX_ORDERS 16 /// How many outstanding orders?
char OrderCount; /// how many orders in queue
@ -595,6 +595,7 @@ struct _unit_ {
} Resource; /// Resource still
struct _order_resource_worker_ {
int TimeToHarvest; /// how much time until we harvest some more.
unsigned DoneHarvesting:1; /// Harvesting done, wait for action to break.
} ResWorker; /// Worker harvesting
struct _order_research_ {
Upgrade* Upgrade; /// Upgrade researched
@ -819,12 +820,15 @@ extern int CanBuildOn(int x,int y,int mask);
extern int CanBuildUnitType(const Unit* unit,const UnitType* type,int x,int y);
/// Find resource
extern Unit* FindResource(const Player* player,int x,int y,int resource);
extern Unit* FindResource(const Unit* unit,int x,int y,int range);
/// Find nearest deposit
extern Unit* FindDeposit(const Player*,int x,int y,int resource);
extern Unit* FindDeposit(const Unit* unit,int x,int y,int range);
/// Find the next idle worker
extern Unit* FindIdleWorker(const Player* player,const Unit* last);
/// Find the neareast piece of terrain with specific flags.
extern int FindTerrainType(int movemask,int resmask,int rvresult,int range,
const Player *player,int x,int y,int* px,int* py);
/// Find the nearest piece of wood in sight range
extern int FindWoodInSight(const Unit* unit,int* x,int* y);

View file

@ -38,7 +38,7 @@
----------------------------------------------------------------------------*/
/**
** @struct _unit_type_ unittype.h
** @struct _unit_type_ unittype.h
**
** \#include "unittype.h"
**
@ -328,54 +328,17 @@
**
** Resource can be harvested. It's false for things like
** oil patches.
** FIXME: crappy name.
**
** UnitType::Harvester
**
** Unit is a resource worker.
** Unit is a resource worker. Faster than examining ResInfo
**
** UnitType::HarvestFromOutside
**
** Unit will harvest from the outside. The unit will use it's
** Attack animation (seems it turned into a generic Action anim.)
** UnitType::ResInfo[::MaxCosts]
**
** UnitType::ResourceHarvested
**
** The resource it can harvest. Needs Harvester flag. An unit
** can't harvest more than one type of resource.
** FIXME: implement something like TransformForOtherResource.
**
** UnitType::WaitAtResource
**
** Cycles the unit waits while inside a resource.
**
** UnitType::ResourceStep
**
** The unit makes so-caled mining cycles. Each mining cycle
** it does some sort of animation and gains ResourceStep
** resources. You can stop after any number of steps.
** when the quantity in the harvester reaches the maximum
** (ResourceCapacity) it will return home. I this is 0 then
** it's considered infinity, and ResourceCapacity will now
** be the limit.
**
** UnitType::ResourceCapacity
**
** Maximum amount of resources a harvester can carry. The
** actual amount can be modified while unloading.
**
** UnitType::WaitAtDepot
**
** Cycles the unit waits while inside the depot to unload.
**
** UnitType::TransformWhenEmpty;
**
** The harvester will transform into another unit when it is
** empty. FIXME: just change the animation.
**
** UnitType::TransformWhenLoaded
**
** The harvester will transform into another unit when it is
** loaded. FIXME: just change the animation.
** Information about resource harvesting. If NULL, it can't
** harvest it.
**
** UnitType::MustBuildOnTop
**
@ -520,6 +483,73 @@
**
** Sprite images of the player colors. This image is drawn
** over UnitType::Sprite. Used with OpenGL only.
**
**
**
** @struct _resource_info_ unittype.h
**
** \#include "unittype.h"
**
** typedef struct _unit_type_ UnitType;
**
** This struct contains information about how a unit will harvest a
** resource.
**
** ResourceInfo::FileWhenLoaded
**
** The harvester's animation file will change when it's loaded.
**
** ResourceInfo::FileWhenEmpty;
**
** The harvester's animation file will change when it's empty.
** The standard animation is used only when building/repairing.
**
**
** ResourceInfo::HarvestFromOutside
**
** Unit will harvest from the outside. The unit will use it's
** Attack animation (seems it turned into a generic Action anim.)
**
** ResourceInfo::ResourceId
**
** The resource this is for. Mostly redundant.
**
** ResourceInfo::FinalResource
**
** The resource is converted to this at the depot. Usefull for
** a fisherman who harvests fish, but it all turns to food at the
** depot.
**
** ResourceInfo::WaitAtResource
**
** Cycles the unit waits while inside a resource.
**
** ResourceInfo::ResourceStep
**
** The unit makes so-caled mining cycles. Each mining cycle
** it does some sort of animation and gains ResourceStep
** resources. You can stop after any number of steps.
** when the quantity in the harvester reaches the maximum
** (ResourceCapacity) it will return home. I this is 0 then
** it's considered infinity, and ResourceCapacity will now
** be the limit.
**
** ResourceInfo::ResourceCapacity
**
** Maximum amount of resources a harvester can carry. The
** actual amount can be modified while unloading.
**
** ResourceInfo::WaitAtDepot
**
** Cycles the unit waits while inside the depot to unload.
**
** ResourceInfo::TerrainHarvester
**
** The unit will harvest terrain. For now this only works
** for wood. maybe it could be made to work for rocks, but
** more than that requires a tileset rewrite.
** FIXME: more configurable.
**
*/
/*----------------------------------------------------------------------------
@ -584,6 +614,23 @@ typedef struct _missile_config_ {
MissileType*Missile; /// Identifier to use to run time
} MissileConfig;
typedef struct _resource_info_ {
char * FileWhenLoaded; /// Change the graphic when the unit is loaded.
char * FileWhenEmpty; /// Change the graphic when the unit is empty.
unsigned HarvestFromOutside; /// Unit harvests without entering the building.
unsigned WaitAtResource; /// Cycles the unit waits while mining.
unsigned ResourceStep; /// Resources the unit gains per mining cycle.
unsigned ResourceCapacity; /// Max amount of resources to carry.
unsigned WaitAtDepot; /// Cycles the unit waits while returning.
unsigned ResourceId; /// Id of the resource harvested. Redundant.
unsigned FinalResource; /// Convert resource when delivered.
unsigned TerrainHarvester; /// Unit will harvest terrain(wood only for now).
unsigned LoseResources; /// The unit will lose it's resource when distracted.
// Runtime info:
Graphic * SpriteWhenLoaded; /// The graphic corresponding to FileWhenLoaded.
Graphic * SpriteWhenEmpty; /// The graphic corresponding to FileWhenEmpty
} ResourceInfo;
/**
** Typedef of base structure of unit-type
*/
@ -664,6 +711,7 @@ struct _unit_type_ {
#define CanTargetSea 2 /// Can attack sea units
#define CanTargetAir 4 /// Can attack air units
unsigned EquivType : 1; ///
unsigned Revealer : 1; /// reveal the fog of war
unsigned LandUnit : 1; /// Land animated
unsigned AirUnit : 1; /// Air animated
@ -692,20 +740,13 @@ struct _unit_type_ {
unsigned Hero : 1; /// Is hero only used for triggers .
unsigned Volatile : 1; /// Invisiblity/unholy armor kills unit.
unsigned Organic : 1; /// Organic can be healed.
unsigned CanStore[MaxCosts]; /// Resources that we can store here.
unsigned GivesResource; /// The resource this unit gives.
unsigned MaxWorkers; /// Maximum number of workers.
unsigned CanHarvest : 1; /// Resource can be harvested.
unsigned Harvester : 1; /// Unit is a resource worker.
unsigned HarvestFromOutside; /// Unit harvests without entering the building.
unsigned ResourceHarvested; /// The resource it can harvest.
unsigned WaitAtResource; /// Cycles the unit waits while mining.
unsigned ResourceStep; /// Resources the unit gains per mining cycle.
unsigned ResourceCapacity; /// Max amount of resources to carry.
unsigned WaitAtDepot; /// Cycles the unit waits while returning.
UnitType* TransformWhenEmpty; /// UnitType to transform to when empty.
UnitType* TransformWhenLoaded; /// UnitType to transform to when loaded.
unsigned Harvester : 1; /// unit is a resource harvester.
ResourceInfo* ResInfo[MaxCosts]; /// Resource information.
UnitType* MustBuildOnTop; /// Must be built on top of something.
unsigned SelectableByRectangle : 1; /// Selectable with mouse rectangle.
@ -756,10 +797,6 @@ extern UnitType* UnitTypes[UnitTypeMax]; /// All unit-types
extern int NumUnitTypes; /// Number of unit-types made
// FIXME: this hardcoded unit-types must be removed!!
extern UnitType*UnitTypeHumanWorker; /// Human worker
extern UnitType*UnitTypeOrcWorker; /// Orc worker
extern UnitType*UnitTypeHumanWorkerWithWood; /// Human worker with wood
extern UnitType*UnitTypeOrcWorkerWithWood; /// Orc worker with wood
extern UnitType*UnitTypeHumanWall; /// Human wall
extern UnitType*UnitTypeOrcWall; /// Orc wall
extern UnitType*UnitTypeCritter; /// Critter unit-type pointer

View file

@ -307,14 +307,14 @@ global int CheckedForestOnMap(int tx,int ty)
*/
global int ForestOnMap(int tx,int ty)
{
IfDebug(
if( tx<0 || ty<0 || tx>=TheMap.Width || ty>=TheMap.Height ) {
// FIXME: must cleanup calling function !
fprintf(stderr,"Used x %d, y %d\n",tx,ty);
abort();
return 0;
}
);
#ifdef DEBUG
if( tx<0 || ty<0 || tx>=TheMap.Width || ty>=TheMap.Height ) {
// FIXME: must cleanup calling function !
fprintf(stderr,"Used x %d, y %d\n",tx,ty);
abort();
return 0;
}
#endif
return TheMap.Fields[tx+ty*TheMap.Width].Flags&MapFieldForest;
}

View file

@ -301,7 +301,7 @@ global void UpdateMinimap(void)
if( (*table)->Player->Player==PlayerNumNeutral ) {
if( type->Critter ) {
color=ColorNPC;
} else if( type->OilPatch ) {
} else if( type->GivesResource==OilCost ) {
color=ColorBlack;
} else {
color=ColorYellow;

View file

@ -561,8 +561,8 @@ local void DoNextReplay(void)
SendCommandBuildBuilding(UnitSlots[unit],posx,posy,UnitTypeByIdent(val),flags);
} else if( !strcmp(name,"cancel-build") ) {
SendCommandCancelBuilding(UnitSlots[unit],dunit);
} else if( !strcmp(name,"harvest") ) {
SendCommandHarvest(UnitSlots[unit],posx,posy,flags);
} else if( !strcmp(name,"resource-loc") ) {
SendCommandResourceLoc(UnitSlots[unit],posx,posy,flags);
} else if( !strcmp(name,"resource") ) {
SendCommandResource(UnitSlots[unit],dunit,flags);
} else if( !strcmp(name,"return") ) {
@ -902,20 +902,20 @@ global void SendCommandCancelBuilding(Unit* unit,Unit* worker)
}
/**
** Send command: Unit harvest wood.
** Send command: Unit harvests a location (wood for now).
**
** @param unit pointer to unit.
** @param x X map tile position where to harvest.
** @param y Y map tile position where to harvest.
** @param flush Flag flush all pending commands.
*/
global void SendCommandHarvest(Unit* unit,int x,int y,int flush)
global void SendCommandResourceLoc(Unit* unit,int x,int y,int flush)
{
if( NetworkFildes==-1 ) {
CommandLog("harvest",unit,flush,x,y,NoUnitP,NULL,-1);
CommandHarvest(unit,x,y,flush);
CommandLog("resource-loc",unit,flush,x,y,NoUnitP,NULL,-1);
CommandResourceLoc(unit,x,y,flush);
} else {
NetworkSendCommand(MessageCommandHarvest,unit,x,y,NoUnitP,0,flush);
NetworkSendCommand(MessageCommandResourceLoc,unit,x,y,NoUnitP,0,flush);
}
}
@ -923,7 +923,7 @@ global void SendCommandHarvest(Unit* unit,int x,int y,int flush)
** Send command: Unit harvest resources
**
** @param unit pointer to unit.
** @param dest pointer to destination (oil-platform).
** @param dest pointer to destination (oil-platform,gold mine).
** @param flush Flag flush all pending commands.
*/
global void SendCommandResource(Unit* unit,Unit* dest,int flush)
@ -1308,9 +1308,9 @@ global void ParseCommand(unsigned char msgnr,UnitRef unum,
CommandLog("cancel-build",unit,FlushCommands,-1,-1,dest,NULL,-1);
CommandCancelBuilding(unit,dest);
break;
case MessageCommandHarvest:
CommandLog("harvest",unit,status,x,y,NoUnitP,NULL,-1);
CommandHarvest(unit,x,y,status);
case MessageCommandResourceLoc:
CommandLog("resource-loc",unit,status,x,y,NoUnitP,NULL,-1);
CommandResourceLoc(unit,x,y,status);
break;
case MessageCommandResource:
dest=NoUnitP;

View file

@ -181,9 +181,7 @@ local SoundId ChooseUnitVoiceSoundId(const Unit *unit,UnitVoiceGroup voice)
return GameSounds.TreeChopping.Sound;
case VoiceWorkCompleted:
// FIXME: make this more configurable
if (unit->Type==UnitTypeHumanWorker) {
return GameSounds.PeasantWorkComplete.Sound;
} else if( ThisPlayer->Race==PlayerRaceHuman ) {
if( ThisPlayer->Race==PlayerRaceHuman ) {
return GameSounds.HumanWorkComplete.Sound;
} else {
return GameSounds.OrcWorkComplete.Sound;

View file

@ -989,11 +989,7 @@ global void ShowLoadProgress(const char* fmt,...)
char* s;
va_start(va,fmt);
#ifdef USE_WIN32
vsprintf(temp,fmt,va);
#else
vsnprintf(temp,sizeof(temp),fmt,va);
#endif
va_end(va);
if( VideoDepth && IsFontLoaded(GameFont) ) {

View file

@ -594,9 +594,7 @@ global void DrawButtonPanel(void)
case ButtonHarvest:
case ButtonReturn:
for( j=0; j<NumSelected; ++j ) {
if( Selected[j]->Orders[0].Action!=UnitActionResource
&& Selected[j]->Orders[0].Action
!=UnitActionHarvest ) {
if( Selected[j]->Orders[0].Action!=UnitActionResource ) {
break;
}
}

View file

@ -1082,7 +1082,7 @@ global int HandleCheats(const char* Input)
if( !ThisPlayer->Ai ) {
AiInit( ThisPlayer );
}
SetMessage("I'm an AI Now :)");
SetMessage("I'm the BORG, resistance is futile!");
}
#endif
} else {

View file

@ -521,17 +521,22 @@ global void DrawUnitInfo(const Unit* unit)
VideoDrawText(x+63,y+8+125,GameFont,"Speed:");
DrawStats(x+108,y+8+125,stats->Speed,type->_Speed);
// Show how much wood is harvested already in percents! :) //vladi
// FIXME: Make this optional
if( unit->Orders[0].Action==UnitActionHarvest && unit->SubAction==64 ) {
sprintf(buf,"Wood: %d%%"
,(100*(CHOP_FOR_WOOD-unit->Value))/CHOP_FOR_WOOD);
VideoDrawText(x+63,y+8+141,GameFont,buf);
}
// FIXME: Ugly hack.
if( unit->Type->Harvester&&unit->Value&&unit->Orders[0].Action!=UnitActionHarvest ) {
if( unit->Type->Harvester&&unit->Value) {
sprintf(buf,"Carry: %d %s",unit->Value,
DefaultResourceNames[unit->Type->ResourceHarvested]);
DefaultResourceNames[unit->CurrentResource]);
VideoDrawText(x+61,y+8+141,GameFont,buf);
}
if ((unit->Type->Harvester)&&
(unit->Orders->Action==UnitActionResource)&&
(unit->CurrentResource)&&
(unit->Type->ResInfo[unit->CurrentResource]) &&
(unit->SubAction==60) &&
(!unit->Type->ResInfo[unit->CurrentResource]->ResourceStep)) {
sprintf(buf,"%s: %d%%",DefaultResourceNames[unit->CurrentResource],
100*(unit->Type->ResInfo[unit->CurrentResource]->WaitAtResource-
unit->Data.ResWorker.TimeToHarvest)/
unit->Type->ResInfo[unit->CurrentResource]->WaitAtResource);
VideoDrawText(x+61,y+8+141,GameFont,buf);
}

View file

@ -40,12 +40,10 @@
#include "stratagus.h"
#if defined(USE_OPENGL) && defined(_MSC_VER)
#if defined(_MSC_VER)
#undef NOUSER
#include "video.h"
#else
#include "video.h"
#endif
#include "video.h"
#include "font.h"
#include "interface.h"
#include "menus.h"

View file

@ -111,6 +111,7 @@ global void DoRightButton(int sx,int sy)
int action;
int acknowledged;
int flush;
int res;
//
// No unit selected
@ -196,41 +197,45 @@ global void DoRightButton(int sx,int sy)
// Handle resource workers.
//
if( action==MouseActionHarvest ) {
// Return wood cutter home
if( (type==UnitTypeOrcWorkerWithWood ||
type==UnitTypeHumanWorkerWithWood) &&
dest && dest->Type->CanStore[WoodCost] &&
dest->Player==unit->Player) {
DebugLevel3("send to wood deposit.\n");
dest->Blink=4;
SendCommandReturnGoods(unit,dest,flush);
continue;
}
// Send wood cutter to work
if((type==UnitTypeOrcWorker||type==UnitTypeHumanWorker) &&
IsMapFieldExplored(unit->Player,x,y) &&
ForestOnMap(x,y) ) {
SendCommandHarvest(unit,x,y,flush);
continue;
}
if (unit->Type->Harvester && dest) {
// Return a loaded harvester to deposit
if( unit->Value>0 &&
dest->Type->CanStore[unit->Type->ResourceHarvested] &&
dest->Player==unit->Player) {
dest->Blink=4;
DebugLevel3Fn("Return to deposit.\n");
SendCommandReturnGoods(unit,dest,flush);
continue;
}
// Go and harvest
if( (unit->Value<unit->Type->ResourceCapacity) &&
dest->Type->GivesResource==unit->Type->ResourceHarvested &&
(dest->Player==unit->Player ||
dest->Player->Player==PlayerMax-1)) {
dest->Blink=4;
SendCommandResource(unit,dest,flush);
continue;
if (unit->Type->Harvester) {
if ( dest ) {
// Return a loaded harvester to deposit
if( (unit->Value>0) &&
(dest->Type->CanStore[unit->CurrentResource])&&
(dest->Player==unit->Player) ) {
dest->Blink=4;
DebugLevel3Fn("Return to deposit.\n");
SendCommandReturnGoods(unit,dest,flush);
continue;
}
// Go and harvest from an building
if( (res=dest->Type->GivesResource) &&
(unit->Type->ResInfo[res]) &&
(unit->Value<unit->Type->ResInfo[res]->ResourceCapacity) &&
(dest->Type->CanHarvest) &&
(dest->Player==unit->Player ||
(dest->Player->Player==PlayerMax-1)) ) {
dest->Blink=4;
SendCommandResource(unit,dest,flush);
continue;
}
} else {
// FIXME: support harvesting more types of terrain.
for (res=0;res<MaxCosts;res++) {
if ( (unit->Type->ResInfo[res]) &&
(unit->Type->ResInfo[res]->TerrainHarvester) &&
(IsMapFieldExplored(unit->Player,x,y)) &&
(ForestOnMap(x,y)) &&
((unit->CurrentResource!=res)||
(unit->Value<unit->Type->ResInfo[res]->ResourceCapacity))) {
DebugLevel3("Sent worker to cut wood.\n");
SendCommandResourceLoc(unit,x,y,flush);
break;
}
}
if (res!=MaxCosts) {
continue;
}
}
}
// Go and repair
@ -358,7 +363,7 @@ global void DoRightButton(int sx,int sy)
}
if( IsMapFieldExplored(unit->Player,x,y) && ForestOnMap(x,y) ) {
DebugLevel3("RALY POINT TO FOREST\n");
SendCommandHarvest(Selected[i],x,y,!(KeyModifiers&ModifierShift));
SendCommandResourceLoc(Selected[i],x,y,!(KeyModifiers&ModifierShift));
continue;
}
SendCommandMove(unit,x,y,flush);
@ -945,23 +950,31 @@ local void SendDemolish(int sx,int sy)
**
** @see Selected
*/
local void SendHarvest(int sx,int sy)
local void SendResource(int sx,int sy)
{
int i;
int res;
Unit* dest;
for( i=0; i<NumSelected; ++i ) {
DebugCheck(!Selected[i]->Type->Harvester);
if ((dest=UnitUnderCursor) &&
(Selected[i]->Type->ResourceHarvested==dest->Type->GivesResource)) {
(Selected[i]->Type->Harvester) &&
(res=dest->Type->GivesResource) &&
(Selected[i]->Type->ResInfo[res])) {
dest->Blink=4;
DebugLevel3("RESOURCE\n");
SendCommandResource(Selected[i],dest,!(KeyModifiers&ModifierShift));
continue;
}
if( IsMapFieldExplored(Selected[i]->Player,sx/TileSizeX,sy/TileSizeY) &&
ForestOnMap(sx/TileSizeX,sy/TileSizeY) ) {
SendCommandHarvest(Selected[i],sx/TileSizeY,sy/TileSizeY,!(KeyModifiers&ModifierShift));
for (res=0;res<MaxCosts;res++) {
if( Selected[i]->Type->Harvester &&
Selected[i]->Type->ResInfo[res] &&
Selected[i]->Type->ResInfo[res]->TerrainHarvester &&
IsMapFieldExplored(Selected[i]->Player,sx/TileSizeX,sy/TileSizeY) &&
ForestOnMap(sx/TileSizeX,sy/TileSizeY) ) {
DebugLevel3("RESOURCE\n");
SendCommandResourceLoc(Selected[i],sx/TileSizeY,sy/TileSizeY,!(KeyModifiers&ModifierShift));
}
}
}
}
@ -1070,7 +1083,7 @@ local void SendCommand(int sx, int sy)
SendPatrol(sx,sy);
break;
case ButtonHarvest:
SendHarvest(sx,sy);
SendResource(sx,sy);
break;
case ButtonUnload:
SendUnload(sx,sy);

View file

@ -58,6 +58,8 @@
/// Get unit-type.
extern UnitType* CclGetUnitType(SCM ptr);
/// Get resource by name
extern unsigned CclGetResourceByName(SCM ptr);
/**
** Set hit-point regeneration
@ -209,8 +211,6 @@ local void CclParseOrder(SCM list,Order* order)
order->Action=UnitActionBuild;
} else if( gh_eq_p(value,gh_symbol2scm("action-repair")) ) {
order->Action=UnitActionRepair;
} else if( gh_eq_p(value,gh_symbol2scm("action-harvest")) ) {
order->Action=UnitActionHarvest;
} else if( gh_eq_p(value,gh_symbol2scm("action-resource")) ) {
order->Action=UnitActionResource;
} else if( gh_eq_p(value,gh_symbol2scm("action-return-goods")) ) {
@ -366,6 +366,29 @@ local void CclParseBuilded(Unit* unit, SCM list)
}
}
/**
** Parse res worker data
**
** @param unit Unit pointer which should be filled with the data.
** @param list All options of the resource worker data.
*/
local void CclParseResWorker(Unit* unit, SCM list)
{
SCM value;
while (!gh_null_p(list)) {
value = gh_car(list);
list = gh_cdr(list);
if (gh_eq_p(value, gh_symbol2scm("time-to-harvest"))) {
unit->Data.ResWorker.TimeToHarvest = gh_scm2int(gh_car(list));
list = gh_cdr(list);
} else if (gh_eq_p(value, gh_symbol2scm("done-harvesting"))) {
unit->Data.ResWorker.DoneHarvesting = 1;
list = gh_cdr(list);
}
}
}
/**
** Parse research
**
@ -681,6 +704,9 @@ local SCM CclUnit(SCM list)
} else if( gh_eq_p(value,gh_symbol2scm("value")) ) {
unit->Value=gh_scm2int(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("current-resource")) ) {
unit->CurrentResource=CclGetResourceByName(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("sub-action")) ) {
unit->SubAction=gh_scm2int(gh_car(list));
list=gh_cdr(list);
@ -761,6 +787,10 @@ local SCM CclUnit(SCM list)
sublist=gh_car(list);
list=gh_cdr(list);
CclParseBuilded(unit,sublist);
} else if( gh_eq_p(value,gh_symbol2scm("data-res-worker")) ) {
sublist=gh_car(list);
list=gh_cdr(list);
CclParseResWorker(unit,sublist);
} else if( gh_eq_p(value,gh_symbol2scm("data-research")) ) {
sublist=gh_car(list);
list=gh_cdr(list);

View file

@ -71,7 +71,7 @@ local ccl_smob_type_t SiodUnitTypeTag; /// siod unit-type object
** @param value SCM thingie
** @return the resource id
*/
local unsigned CclGetResourceByName(SCM value)
global unsigned CclGetResourceByName(SCM value)
{
int i;
for( i=0; i<MaxCosts; ++i ) {
@ -96,6 +96,7 @@ local SCM CclDefineUnitType(SCM list)
SCM sublist;
UnitType* type;
UnitType* auxtype;
ResourceInfo* res;
char* str;
int i;
int redefine;
@ -271,7 +272,7 @@ local SCM CclDefineUnitType(SCM list)
auxtype=UnitTypeByIdent(str);
if (!auxtype) {
DebugLevel0("Build on top of undefined unit \"%s\".\n" _C_ str);
exit(0);
DebugCheck(1);
}
type->MustBuildOnTop=auxtype;
free(str);
@ -428,43 +429,55 @@ local SCM CclDefineUnitType(SCM list)
type->Coward=1;
} else if( gh_eq_p(value,gh_symbol2scm("harvester")) ) {
type->Harvester=1;
} else if( gh_eq_p(value,gh_symbol2scm("harvest-from-outside")) ) {
type->HarvestFromOutside=1;
} else if( gh_eq_p(value,gh_symbol2scm("resource-step")) ) {
type->ResourceStep=gh_scm2int(gh_car(list));
} else if( gh_eq_p(value,gh_symbol2scm("can-gather-resource")) ) {
sublist=gh_car(list);
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("resource-harvested")) ) {
type->ResourceHarvested=CclGetResourceByName(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("wait-at-resource")) ) {
type->WaitAtResource=gh_scm2int(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("wait-at-depot")) ) {
type->WaitAtDepot=gh_scm2int(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("resource-capacity")) ) {
type->ResourceCapacity=gh_scm2int(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("transform-when-empty")) ) {
str=gh_scm2newstr(gh_car(list),NULL);
auxtype=UnitTypeByIdent(str);
if (!auxtype) {
DebugLevel0("Undefined unit \"%s\".\n" _C_ str);
exit(0);
res=(ResourceInfo*)malloc(sizeof(ResourceInfo));
memset(res,0,sizeof(ResourceInfo));
while( !gh_null_p(sublist) ) {
value=gh_car(sublist);
sublist=gh_cdr(sublist);
if (gh_eq_p(value,gh_symbol2scm("resource-id")) ) {
res->ResourceId=CclGetResourceByName(gh_car(sublist));
type->ResInfo[res->ResourceId]=res;
sublist=gh_cdr(sublist);
} else if( gh_eq_p(value,gh_symbol2scm("resource-step")) ) {
res->ResourceStep=gh_scm2int(gh_car(sublist));
sublist=gh_cdr(sublist);
} else if( gh_eq_p(value,gh_symbol2scm("final-resource")) ) {
res->FinalResource=CclGetResourceByName(gh_car(sublist));
sublist=gh_cdr(sublist);
} else if( gh_eq_p(value,gh_symbol2scm("wait-at-resource")) ) {
res->WaitAtResource=gh_scm2int(gh_car(sublist));
sublist=gh_cdr(sublist);
} else if( gh_eq_p(value,gh_symbol2scm("wait-at-depot")) ) {
res->WaitAtDepot=gh_scm2int(gh_car(sublist));
sublist=gh_cdr(sublist);
} else if( gh_eq_p(value,gh_symbol2scm("resource-capacity")) ) {
res->ResourceCapacity=gh_scm2int(gh_car(sublist));
sublist=gh_cdr(sublist);
} else if( gh_eq_p(value,gh_symbol2scm("terrain-harvester")) ) {
res->TerrainHarvester=1;
} else if( gh_eq_p(value,gh_symbol2scm("lose-resources")) ) {
res->LoseResources=1;
} else if( gh_eq_p(value,gh_symbol2scm("harvest-from-outside")) ) {
res->HarvestFromOutside=1;
} else if( gh_eq_p(value,gh_symbol2scm("file-when-empty")) ) {
res->FileWhenLoaded=gh_scm2newstr(gh_car(sublist),0);
sublist=gh_cdr(sublist);
} else if( gh_eq_p(value,gh_symbol2scm("file-when-loaded")) ) {
res->FileWhenLoaded=gh_scm2newstr(gh_car(sublist),0);
sublist=gh_cdr(sublist);
} else {
printf("\n%s\n",type->Name);
errl("Unsupported tag",value);
DebugCheck( 1 );
}
}
type->TransformWhenEmpty=auxtype;
free(str);
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("transform-when-loaded")) ) {
str=gh_scm2newstr(gh_car(list),NULL);
auxtype=UnitTypeByIdent(str);
if (!auxtype) {
DebugLevel0("Undefined unit \"%s\".\n" _C_ str);
exit(0);
if (!res->FinalResource) {
res->FinalResource=res->ResourceId;
}
type->TransformWhenLoaded=auxtype;
free(str);
list=gh_cdr(list);
DebugCheck(!res->ResourceId);
} else if( gh_eq_p(value,gh_symbol2scm("gives-resource")) ) {
type->GivesResource=CclGetResourceByName(gh_car(list));
list=gh_cdr(list);
@ -562,8 +575,8 @@ local SCM CclDefineUnitType(SCM list)
} else {
// FIXME: this leaves a half initialized unit-type
printf("\n%s\n",type->Name);
DebugCheck( 1 );
errl("Unsupported tag",value);
DebugCheck( 1 );
}
}

View file

@ -2462,15 +2462,152 @@ global int CanBuildUnitType(const Unit* unit,const UnitType* type,int x,int y)
----------------------------------------------------------------------------*/
/**
** Find wood in sight range.
** Find the closest piece of wood for an unit.
**
** @param unit Unit that needs wood.
** @param px OUT: Map X position of wood.
** @param py OUT: Map Y position of wood.
** @param unit The unit.
** @param x OUT: Map X position of tile.
** @param y OUT: Map Y position of tile.
*/
global int FindWoodInSight(const Unit* unit,int* x,int* y)
{
return FindTerrainType(UnitMovementMask(unit),0,MapFieldForest,9999,
unit->Player,unit->X,unit->Y,x,y);
}
/**
** Find the closest piece of terrain with the given flags.
**
** @param movemask The movement mask to reach that location.
** @param resmask Result tile mask.
** @param rvresult Return a tile that doesn't match.
** @param range Maximum distance for the search.
** @param player Only search fields explored by player
** @param x Map X start position for the search.
** @param y Map Y start position for the search.
**
** @param px OUT: Map X position of tile.
** @param py OUT: Map Y position of tile.
**
** @notes Movement mask can be 0xFFFFFFFF to have no effect
** Range is not circular, but square.
** Player is ignored if nil(search the entire map)
** Use rvresult if you search for a til;e that doesn't
** match resmask. Like for a tile where an unit can go
** with it's movement mask.
**
** @return True if wood was found.
*/
global int FindWoodInSight(const Unit* unit,int* px,int* py)
global int FindTerrainType(int movemask,int resmask,int rvresult,int range,
const Player *player,int x,int y,int* px,int* py)
{
static const int xoffset[]={ 0,-1,+1, 0, -1,+1,-1,+1 };
static const int yoffset[]={ -1, 0, 0,+1, -1,-1,+1,+1 };
struct {
unsigned short X;
unsigned short Y;
} * points;
int size;
int rx;
int ry;
int wp;
int rp;
int ep;
int i;
int w;
unsigned char* m;
unsigned char* matrix;
int destx;
int desty;
int cdist;
destx=x;
desty=y;
size=min(TheMap.Width*TheMap.Height/4,range*range*5);
points=malloc(size*sizeof(*points));
// Make movement matrix. FIXME: can create smaller matrix.
matrix=CreateMatrix();
w=TheMap.Width+2;
matrix+=w+w+2;
points[0].X=x;
points[0].Y=y;
rp=0;
matrix[x+y*w]=1; // mark start point
ep=wp=1; // start with one point
cdist=0; // current distance is 0
//
// Pop a point from stack, push all neighbors which could be entered.
//
for( ;; ) {
while( rp!=ep ) {
rx=points[rp].X;
ry=points[rp].Y;
DebugLevel3("%d,%d\n" _C_ rx _C_ ry);
for( i=0; i<8; ++i ) { // mark all neighbors
x=rx+xoffset[i];
y=ry+yoffset[i];
// Make sure we don't leave the map.
if (x<0||y<0||x>=TheMap.Width||y>=TheMap.Height) {
continue;
}
m=matrix+x+y*w;
// Check if visited or unexplored
if( *m || (player&&!IsMapFieldExplored(player,x,y))) {
continue;
}
// Look if found what was required.
if ( rvresult?CanMoveToMask(x,y,resmask):!CanMoveToMask(x,y,resmask) ) {
*px=x;
*py=y;
DebugLevel3("Found it! %X %X\n" _C_ TheMap.Fields[x+y*TheMap.Width].Flags _C_ resmask);
return 1;
}
if( CanMoveToMask(x,y,movemask) ) { // reachable
*m=1;
points[wp].X=x; // push the point
points[wp].Y=y;
if( ++wp>=size ) { // round about
wp=0;
}
if (wp==ep) {
// We are out of points, give up!
DebugLevel0Fn("Ran out of points the hard way, beware.\n");
break;
}
} else { // unreachable
*m=99;
}
}
if( ++rp>=size ) { // round about
rp=0;
}
}
cdist++;
if( rp==wp||cdist>=range ) { // unreachable, no more points available
break;
}
// Continue with next set.
ep=wp;
}
free(points);
return 0;
}
/**
** Find Resource.
**
** @param unit The unit that wants to find a resource.
** @param x Closest to x
** @param x Closest to y
** @param range Maximum distance to the resource.
**
** @notes This will return an usable resource building that
** belongs to "player" or is neutral.
**
** @return NoUnitP or resource unit
*/
global Unit* FindResource(const Unit * unit,int x,int y,int range)
{
static const int xoffset[]={ 0,-1,+1, 0, -1,+1,-1,+1 };
static const int yoffset[]={ -1, 0, 0,+1, -1,-1,+1,+1 };
@ -2479,8 +2616,6 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
unsigned short Y;
} * points;
int size;
int x;
int y;
int rx;
int ry;
int mask;
@ -2493,80 +2628,42 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
unsigned char* m;
unsigned char* matrix;
const Unit* destu;
Unit* mine;
Unit* bestmine;
int destx;
int desty;
int bestx;
int besty;
int bestd;
int cdist;
int resource;
destx=x=unit->X;
desty=y=unit->Y;
size=TheMap.Width*TheMap.Height/4;
resource=unit->CurrentResource;
destx=x;
desty=y;
size=min(TheMap.Width*TheMap.Height/4,range*range*5);
points=malloc(size*sizeof(*points));
//
// Find the nearest wood depot
//
if( (destu=FindDeposit(unit->Player,x,y,WoodCost)) ) {
// Find the nearest gold depot
if( (destu=FindDeposit(unit,x,y,range)) ) {
NearestOfUnit(destu,x,y,&destx,&desty);
}
bestd=99999;
IfDebug( bestx=besty=0; ); // keep the compiler happy
//
// Make movement matrix. FIXME: can create smaller matrix.
//
matrix=CreateMatrix();
w=TheMap.Width+2;
matrix+=w+w+2;
//
// Mark sight range as border. FIXME: matrix didn't need to be bigger.
//
n=unit->Stats->SightRange;
rx=x-n;
if( rx<0 ) {
rx=0;
}
ep=x+n;
if( ep>TheMap.Width ) {
ep=TheMap.Width;
}
ry=y-n;
if( ry<0 ) {
ry=0;
}
wp=y+n;
if( wp>TheMap.Height ) {
wp=TheMap.Height;
}
for( i=rx; i<ep; ++i ) { // top bottom line
matrix[i+ry*w]=matrix[i+wp*w]=66;
}
for( i=ry+1; i<wp-1; ++i ) {
matrix[rx+i*w]=matrix[ep+i*w]=66;
}
#if 0
matrix[x+n+(y+n)*w]=matrix[x-n+(y+n)*w]=
matrix[x+n+(y-n)*w]=matrix[x-n+(y-n)*w]=66;
for( i=n; i--; ) {
// FIXME: marks out of map area
DebugCheck( x-i+(y-n)*w<0 || x+i+(y+n)*w>w*TheMap.Hight );
matrix[x+n+(y+i)*w]=matrix[x-n+(y+i)*w]=
matrix[x+n+(y-i)*w]=matrix[x-n+(y-i)*w]=
matrix[x-i+(y+n)*w]=matrix[x+i+(y+n)*w]=
matrix[x-i+(y-n)*w]=matrix[x+i+(y-n)*w]=66;
}
#endif
// Unit movement mask
mask=UnitMovementMask(unit);
// Ignore all units along the way. Might seem wierd, but otherwise
// peasants would lock at a mine with a lot of workers.
mask&=~(MapFieldLandUnit|MapFieldSeaUnit|MapFieldAirUnit);
points[0].X=x;
points[0].Y=y;
rp=0;
matrix[x+y*w]=1; // mark start point
ep=wp=1; // start with one point
cdist=0; // current distance is 0
bestmine=NoUnitP;
//
// Pop a point from stack, push all neighbors which could be entered.
@ -2583,23 +2680,28 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
continue;
}
if (!IsMapFieldExplored(unit->Player,x,y)) { // Unknown.
continue;
}
//
// Look if there is wood
// Look if there is a mine
//
if ( ForestOnMap(x,y) && IsMapFieldExplored(unit->Player,x,y) ) {
if ((mine=ResourceOnMap(x,y,resource))&&
(mine->Type->CanHarvest)&&
((mine->Player->Player==PlayerMax-1)||
(mine->Player==unit->Player)||
(IsAllied(unit->Player,mine)))) {
if( destu ) {
n=max(abs(destx-x),abs(desty-y));
if( n<bestd ) {
bestd=n;
bestx=x;
besty=y;
bestmine=mine;
}
*m=22;
*m=99;
} else { // no goal take the first
*px=x;
*py=y;
free(points);
return 1;
return mine;
}
}
@ -2610,6 +2712,10 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
if( ++wp>=size ) { // round about
wp=0;
}
if (wp==ep) {
// We are out of points, give up!
break;
}
} else { // unreachable
*m=99;
}
@ -2618,138 +2724,141 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
rp=0;
}
}
//
// Take best of this frame, if any.
//
if( bestd!=99999 ) {
*px=bestx;
*py=besty;
free(points);
return 1;
return bestmine;
}
//
// Continue with next frame.
//
if( rp==wp ) { // unreachable, no more points available
cdist++;
if( rp==wp||cdist>=range ) { // unreachable, no more points available
break;
}
// Continue with next set.
ep=wp;
}
DebugLevel3Fn("no wood in sight-range\n");
DebugLevel3Fn("no resource found\n");
free(points);
return 0;
}
/**
** Find Resource.
**
** @param player The player that wants to find a resource.
** @param x Nearest to X position.
** @param y Nearest to Y position
** @param resource The ID of the resource.
**
** @notes This will return an usable resource building that
** belongs to "player" or is neutral.
**
** @return NoUnitP or oil platform unit
*/
global Unit* FindResource(const Player* player,int x,int y,int resource)
{
Unit* unit;
Unit* best;
Unit** units;
int nunits;
int best_d;
int d;
int i;
int pnum;
// FIXME: this is not the best one
// We need the deposit with the shortest way!
// At least it must be reachable!
best=NoUnitP;
best_d=99999;
for (pnum=0;pnum<PlayerMax;++pnum) {
// FIXME: allow harvesting from ally
if ( (pnum!=PlayerMax-1) && (pnum!=player->Player) ) {
continue;
}
nunits=Players[pnum].TotalNumUnits;
units=Players[pnum].Units;
for( i=0; i<nunits; i++ ) {
unit=units[i];
if( UnitUnusable(unit) || !unit->Type->CanHarvest ) {
continue;
}
// Want platform
if( unit->Type->GivesResource==resource ) {
d=MapDistanceToUnit(x,y,unit);
if( d<best_d ) {
best_d=d;
best=unit;
}
}
}
}
DebugLevel3Fn("%d %d,%d\n" _C_ best?UnitNumber(best):-1 _C_
best?best->X:-1 _C_ best?best->Y:-1);
return best;
return NoUnitP;
}
/**
** Find deposit. This will find a deposit for a resource
**
** @param player The player the deposit must belong to.
** @param x Nearest to X position.
** @param y Nearest to Y position.
** @param resource The resource you need the deposit to hold.
** @param unit The unit that wants to find a resource.
** @param x Closest to x
** @param x Closest to y
** @param range Maximum distance to the deposit.
**
** @notes This will return a reachable allied depot.
**
** @return NoUnitP or oil deposit unit
*/
global Unit* FindDeposit(const Player* player,int x,int y,int resource)
global Unit* FindDeposit(const Unit* unit,int x,int y,int range)
{
Unit* unit;
Unit* best;
Unit** units;
int nunits;
int best_d;
int d,i;
static const int xoffset[]={ 0,-1,+1, 0, -1,+1,-1,+1 };
static const int yoffset[]={ -1, 0, 0,+1, -1,-1,+1,+1 };
struct {
unsigned short X;
unsigned short Y;
} * points;
int size;
int rx;
int ry;
int mask;
int wp;
int rp;
int ep;
int i;
int w;
unsigned char* m;
unsigned char* matrix;
Unit* depot;
int destx;
int desty;
int cdist;
int resource;
resource=unit->CurrentResource;
destx=x;
desty=y;
size=min(TheMap.Width*TheMap.Height/4,range*range*5);
points=malloc(size*sizeof(*points));
// Make movement matrix. FIXME: can create smaller matrix.
matrix=CreateMatrix();
w=TheMap.Width+2;
matrix+=w+w+2;
// Unit movement mask
mask=UnitMovementMask(unit);
// Ignore all units along the way. Might seem wierd, but otherwise
// peasants would lock at a mine with a lot of workers.
mask&=~(MapFieldLandUnit|MapFieldSeaUnit|MapFieldAirUnit);
points[0].X=x;
points[0].Y=y;
rp=0;
matrix[x+y*w]=1; // mark start point
ep=wp=1; // start with one point
cdist=0; // current distance is 0
// FIXME: this is not the best one
// We need the deposit with the shortest way!
// At least it must be reachable!
// FIXME: Could we use unit-cache to find it faster?
//
best=NoUnitP;
best_d=INT_MAX;
nunits=player->TotalNumUnits;
units=player->Units;
for( i=0; i<nunits; i++ ) {
unit=units[i];
if( UnitUnusable(unit) ) {
continue;
}
if( unit->Type->CanStore[resource] ) {
d=MapDistanceToUnit(x,y,unit);
if( d<best_d
// FIXME: UnitReachable didn't work with unit inside
/*&& (d=UnitReachable(source,unit,1)) && d<best_d*/ ) {
best_d=d;
best=unit;
// Pop a point from stack, push all neighbors which could be entered.
//
for( ;; ) {
while( rp!=ep ) {
rx=points[rp].X;
ry=points[rp].Y;
for( i=0; i<8; ++i ) { // mark all neighbors
x=rx+xoffset[i];
y=ry+yoffset[i];
// Make sure we don't leave the map.
if (x<0||y<0||x>=TheMap.Width||y>=TheMap.Height) {
continue;
}
m=matrix+x+y*w;
// Check if visited or unexplored
if( *m || !IsMapFieldExplored(unit->Player,x,y)) {
continue;
}
//
// Look if there is a mine
//
if ((depot=ResourceDepositOnMap(x,y,resource))&&
((IsAllied(unit->Player,depot)) ||
(unit->Player==depot->Player))) {
free(points);
return depot;
}
if( CanMoveToMask(x,y,mask) ) { // reachable
*m=1;
points[wp].X=x; // push the point
points[wp].Y=y;
if( ++wp>=size ) { // round about
wp=0;
}
if (wp==ep) {
// We are out of points, give up!
DebugLevel0Fn("Ran out of points the hard way, beware.\n");
break;
}
} else { // unreachable
*m=99;
}
}
if( ++rp>=size ) { // round about
rp=0;
}
}
cdist++;
if( rp==wp||cdist>=range ) { // unreachable, no more points available
break;
}
// Continue with next set.
ep=wp;
}
DebugLevel3Fn("%d %d,%d\n" _C_ best?UnitNumber(best):-1 _C_
best?best->X:-1 _C_ best?best->Y:-1);
return best;
DebugLevel3Fn("no resource deposit found\n");
free(points);
return NoUnitP;
}
/**
@ -3146,14 +3255,14 @@ global void HitUnit(Unit* attacker,Unit* target,int damage)
}
#endif
// FIXME: this is dumb. I made repairers capture. crap.
// david: capture enemy buildings
// Only worker types can capture.
// Still possible to destroy building if not careful (too many attackers)
if( EnableBuildingCapture && attacker
&& type->Building && target->HP<=damage*3
&& IsEnemy(attacker->Player,target)
&& (attacker->Type==UnitTypeOrcWorker
|| attacker->Type==UnitTypeHumanWorker) ) {
&& attacker->Type->RepairRange ) {
ChangeUnitOwner(target,attacker->Player);
CommandStopUnit(attacker); // Attacker shouldn't continue attack!
}
@ -3558,9 +3667,6 @@ local void SaveOrder(const Order* order,CLFile* file)
case UnitActionRepair:
CLprintf(file,"action-repair");
break;
case UnitActionHarvest:
CLprintf(file,"action-harvest");
break;
case UnitActionResource:
CLprintf(file,"action-resource");
break;
@ -3731,6 +3837,9 @@ global void SaveUnit(const Unit* unit,CLFile* file)
CLprintf(file,"'last-group %d\n ",unit->LastGroup);
CLprintf(file,"'value %d\n ",unit->Value);
if (unit->CurrentResource) {
CLprintf(file,"'current-resource '%s\n ",DefaultResourceNames[unit->CurrentResource]);
}
CLprintf(file,"'sub-action %d ",unit->SubAction);
CLprintf(file,"'wait %d ",unit->Wait);
@ -3775,6 +3884,13 @@ global void SaveUnit(const Unit* unit,CLFile* file)
CLprintf(file," 'resource-active %d",unit->Data.Resource.Active);
}
break;
case UnitActionResource:
CLprintf(file," 'data-res-worker '(time-to-harvest %d",unit->Data.ResWorker.TimeToHarvest);
if (unit->Data.ResWorker.DoneHarvesting) {
CLprintf(file," done-harvesting");
}
CLprintf(file,")");
break;
case UnitActionBuilded:
{
ConstructionFrame* cframe;

View file

@ -965,13 +965,12 @@ local void DrawDecoration(const Unit* unit,const UnitType* type,int x,int y)
,unit->Data.UpgradeTo.Ticks);
//
// Chopping wood.
// Carry resource.
// Don't display if empty.
//
} else if( unit->Orders[0].Action==UnitActionHarvest
&& unit->SubAction==64 ) {
DrawManaBar(x,y,type,CHOP_FOR_WOOD,
unit->Value>CHOP_FOR_WOOD?
0:CHOP_FOR_WOOD-unit->Value);
} else if( unit->Type->Harvester&&unit->CurrentResource&&unit->Value>0 ) {
DrawManaBar(x,y,type,unit->Type->ResInfo[unit->CurrentResource]->ResourceCapacity,
unit->Value);
//
// Building research new technologie.
@ -1031,15 +1030,13 @@ local void DrawDecoration(const Unit* unit,const UnitType* type,int x,int y)
DrawManaSprite(x,y,type,unit->Orders[0].Type
->Stats[unit->Player->Player].Costs[TimeCost]
,unit->Data.UpgradeTo.Ticks);
//
// Chopping wood.
// Carry resource.
//
} else if( unit->Orders[0].Action==UnitActionHarvest
&& unit->SubAction==64 ) {
DrawManaSprite(x,y,type,CHOP_FOR_WOOD,
unit->Value>CHOP_FOR_WOOD?
0:CHOP_FOR_WOOD-unit->Value);
} else if( unit->Type->Harvester&&unit->CurrentResource&&unit->Value>0 ) {
DrawManaSprite(x,y,type,unit->Type->ResInfo[unit->CurrentResource]->ResourceCapacity,
unit->Value);
//
// Building research new technologie.
@ -1492,11 +1489,6 @@ local void ShowSingleOrder(const Unit* unit, int x1, int y1, const Order* order)
e_color = color = ColorGray;
break;
case UnitActionHarvest:
e_color = color = ColorYellow;
dest = 1;
break;
case UnitActionResource:
e_color = color = ColorYellow;
dest = 1;
@ -1839,6 +1831,8 @@ global void DrawUnit(const Unit* unit)
{
int x;
int y;
Graphic* Sprite;
ResourceInfo* resinfo;
const UnitType* type;
if ( unit->Type->Revealer ) { // Revealers are not drawn
@ -1859,13 +1853,35 @@ global void DrawUnit(const Unit* unit)
DrawUnitSelection(unit);
GraphicUnitPixels(unit,type->Sprite);
DrawUnitType(type,unit->Frame,x,y);
Sprite=type->Sprite;
if (type->Harvester && unit->CurrentResource) {
resinfo=type->ResInfo[unit->CurrentResource];
if (unit->Value) {
if (resinfo->SpriteWhenLoaded) {
Sprite=resinfo->SpriteWhenLoaded;
}
} else {
if (resinfo->SpriteWhenEmpty) {
Sprite=resinfo->SpriteWhenEmpty;
}
}
}
if( unit->Frame<0 ) {
VideoDrawClipX(Sprite,-unit->Frame,
x-(type->Width-type->TileWidth*TileSizeX)/2,
y-(type->Height-type->TileHeight*TileSizeY)/2);
} else {
VideoDrawClip(Sprite,unit->Frame,
x-(type->Width-type->TileWidth*TileSizeX)/2,
y-(type->Height-type->TileHeight*TileSizeY)/2);
}
#ifdef USE_OPENGL
DrawUnitPlayerColor(type,unit->Player->Player,unit->Frame,x,y);
#endif
#ifndef NEW_DECODRAW
// Unit's extras not fully supported.. need to be deocrations themselves.
// Unit's extras not fully supported.. need to be decorations themselves.
DrawInformations(unit,type,x,y);
#endif
}

View file

@ -417,7 +417,7 @@ global Unit* ResourceOnMap(int tx,int ty,int resource)
n=SelectUnitsOnTile(tx,ty,table);
for( i=0; i<n; ++i ) {
if( UnitUnusable(table[i]) || !table[i]->Type->CanHarvest ){
if( UnitUnusable(table[i]) || !table[i]->Type->CanHarvest || table[i]->Value==0) {
continue;
}
if( table[i]->Type->GivesResource==resource ) {

View file

@ -76,10 +76,6 @@ global int NumUnitTypes; /// number of unit-types made
**
** FIXME: find a way to make it configurable!
*/
global UnitType*UnitTypeHumanWorker; /// Human worker
global UnitType*UnitTypeOrcWorker; /// Orc worker
global UnitType*UnitTypeHumanWorkerWithWood; /// Human worker with wood
global UnitType*UnitTypeOrcWorkerWithWood; /// Orc worker with wood
global UnitType*UnitTypeHumanWall; /// Human wall
global UnitType*UnitTypeOrcWall; /// Orc wall
global UnitType*UnitTypeCritter; /// Critter unit type pointer
@ -453,8 +449,13 @@ global void ParsePudUDTA(const char* udta,int length __attribute__((unused)))
// Cowards
unittype->Coward=BIT(8,v)|BIT(26,v);
if (BIT(9,v)) {
unittype->Harvester=1;
unittype->ResourceHarvested=OilCost;
unittype->ResInfo[OilCost]=(ResourceInfo*)malloc(sizeof(ResourceInfo));
memset(unittype->ResInfo[OilCost],0,sizeof(ResourceInfo));
unittype->ResInfo[OilCost]->ResourceId=OilCost;
unittype->ResInfo[OilCost]->FinalResource=OilCost;
unittype->ResInfo[OilCost]->WaitAtResource=150;
unittype->ResInfo[OilCost]->WaitAtDepot=150;
unittype->ResInfo[OilCost]->ResourceCapacity=100;
}
unittype->Transporter=BIT(10,v);
unittype->CanStore[GoldCost]=BIT(12,v);
@ -645,6 +646,7 @@ local void SaveUnitType(CLFile* file,const UnitType* type,int all)
{
int i;
int flag;
ResourceInfo* res;
CLprintf(file,"(define-unit-type '%s",type->Ident);
CLprintf(file," 'name \"%s\"\n ",type->Name);
@ -905,36 +907,53 @@ local void SaveUnitType(CLFile* file,const UnitType* type,int all)
if( type->Coward ) {
CLprintf(file," 'coward\n");
}
if( type->Harvester ) {
CLprintf(file," 'harvester 'resource-harvested '%s\n",DefaultResourceNames[type->ResourceHarvested]);
}
if( type->HarvestFromOutside ) {
CLprintf(file," 'harvest-from-outside\n");
}
if ( type->WaitAtResource ) {
CLprintf(file," 'wait-at-resource %d\n",type->WaitAtResource);
}
if ( type->WaitAtDepot ) {
CLprintf(file," 'wait-at-depot %d\n",type->WaitAtDepot);
}
if ( type->ResourceCapacity ) {
CLprintf(file," 'resource-capacity %d\n",type->ResourceCapacity);
}
if ( type->TransformWhenEmpty ) {
CLprintf(file," 'transform-when-empty '%s\n",type->TransformWhenEmpty->Ident);
}
if ( type->TransformWhenLoaded ) {
CLprintf(file," 'transform-when-loaded '%s\n",type->TransformWhenLoaded->Ident);
CLprintf(file," 'harvester\n");
for (i=0;i<MaxCosts;i++) {
if (type->ResInfo[i]) {
res=type->ResInfo[i];
CLprintf(file," 'can-gather-resource '(\n");
CLprintf(file," resource-id %s\n",DefaultResourceNames[res->ResourceId]);
CLprintf(file," final-resource %s\n",DefaultResourceNames[res->FinalResource]);
if( res->HarvestFromOutside ) {
CLprintf(file," harvest-from-outside\n");
}
if ( res->WaitAtResource ) {
CLprintf(file," wait-at-resource %d\n",res->WaitAtResource);
}
if ( res->WaitAtDepot ) {
CLprintf(file," wait-at-depot %d\n",res->WaitAtDepot);
}
if ( res->ResourceCapacity ) {
CLprintf(file," resource-capacity %d\n",res->ResourceCapacity);
}
if( res->ResourceStep ) {
CLprintf(file," resource-step %d\n",res->ResourceStep);
}
if( res->TerrainHarvester ) {
CLprintf(file," terrain-harvester\n");
}
if( res->LoseResources ) {
CLprintf(file," lose-resources\n");
}
if ( res->FileWhenEmpty ) {
CLprintf(file," file-when-empty %s\n",res->FileWhenEmpty);
}
if ( res->FileWhenLoaded ) {
CLprintf(file," file-when-loaded %s\n",res->FileWhenLoaded);
}
CLprintf(file," )\n");
}
}
}
if( type->GivesResource ) {
CLprintf(file," 'gives-resource '%s\n",DefaultResourceNames[type->GivesResource]);
}
if( type->MaxWorkers ) {
CLprintf(file," 'max-workers %d\n",type->MaxWorkers);
}
if( type->ResourceStep ){
CLprintf(file," 'resource-step %d\n",type->ResourceStep);
}
// Save store info.
for (flag=i=0;i<MaxCosts;i++)
@ -1222,10 +1241,6 @@ global void InitUnitTypes(int reset_player_stats)
//
// Setup hardcoded unit types. FIXME: should be moved to some configs.
//
UnitTypeHumanWorker=UnitTypeByIdent("unit-peasant");
UnitTypeOrcWorker=UnitTypeByIdent("unit-peon");
UnitTypeHumanWorkerWithWood=UnitTypeByIdent("unit-peasant-with-wood");
UnitTypeOrcWorkerWithWood=UnitTypeByIdent("unit-peon-with-wood");
UnitTypeHumanWall=UnitTypeByIdent("unit-human-wall");
UnitTypeOrcWall=UnitTypeByIdent("unit-orc-wall");
UnitTypeCritter=UnitTypeByIdent("unit-critter");
@ -1239,18 +1254,37 @@ global void LoadUnitTypes(void)
{
UnitType* type;
const char* file;
char buf[1000];
int i;
int res;
ResourceInfo* resinfo;
for( i=0; i<NumUnitTypes; ++i ) {
type=UnitTypes[i];
if( (file=type->ShadowFile) ) {
char *buf;
buf=alloca(strlen(file)+9+1);
file=strcat(strcpy(buf,"graphics/"),file);
ShowLoadProgress("\tUnit `%s'\n",file);
type->ShadowSprite=LoadSprite(file,type->ShadowWidth,type->ShadowHeight);
}
// Load empty/loaded graphics
if (type->Harvester) {
for (res=0;res<MaxCosts;res++) {
if ((resinfo=type->ResInfo[res])) {
if ((file=resinfo->FileWhenLoaded)) {
file=strcat(strcpy(buf,"graphics/"),file);
ShowLoadProgress("\tUnit `%s'\n",file);
resinfo->SpriteWhenLoaded=LoadSprite(file,type->Width,type->Height);
}
if ((file=resinfo->FileWhenEmpty)) {
file=strcat(strcpy(buf,"graphics/"),file);
ShowLoadProgress("\tUnit `%s'\n",file);
resinfo->SpriteWhenEmpty=LoadSprite(file,type->Width,type->Height);
}
}
}
}
//
// Unit-type uses the same sprite as an other.
//
@ -1310,9 +1344,6 @@ global void LoadUnitTypes(void)
// FIXME: should i copy the animations of same graphics?
}
// FIXME: must copy unit data from peon/peasant to with gold/wood
// FIXME: must copy unit data from tanker to tanker full
}
/**
@ -1324,6 +1355,7 @@ global void CleanUnitTypes(void)
void** ptr;
int i;
int j;
int res;
Animations* anims;
DebugLevel0Fn("FIXME: icon, sounds not freed.\n");
@ -1407,6 +1439,24 @@ global void CleanUnitTypes(void)
free(type->CorpseName);
}
for (res=0;res<MaxCosts;res++) {
if (type->ResInfo[res]) {
if (type->ResInfo[res]->SpriteWhenLoaded) {
free (type->ResInfo[res]->SpriteWhenLoaded);
}
if (type->ResInfo[res]->SpriteWhenEmpty) {
free (type->ResInfo[res]->SpriteWhenEmpty);
}
if (type->ResInfo[res]->FileWhenEmpty) {
free (type->ResInfo[res]->FileWhenEmpty);
}
if (type->ResInfo[res]->FileWhenLoaded) {
free (type->ResInfo[res]->FileWhenLoaded);
}
free (type->ResInfo[res]);
}
}
//
// FIXME: Sounds can't be freed, they still stuck in sound hash.
//
@ -1445,10 +1495,6 @@ global void CleanUnitTypes(void)
//
// Clean hardcoded unit types.
//
UnitTypeHumanWorker=NULL;
UnitTypeOrcWorker=NULL;
UnitTypeHumanWorkerWithWood=NULL;
UnitTypeOrcWorkerWithWood=NULL;
UnitTypeHumanWall=NULL;
UnitTypeOrcWall=NULL;
UnitTypeCritter=NULL;