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:
parent
a3ca771643
commit
9fe8fc9ff2
34 changed files with 1099 additions and 1494 deletions
doc
src
action
Module.makeaction_build.cppaction_harvest.cppaction_move.cppaction_resource.cppaction_returngoods.cppaction_train.cppactions.cppcommand.cpp
ai
include
map
network
sound
stratagus
ui
unit
|
@ -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).
|
||||
|
|
|
@ -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+=
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
//@}
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <bzlib.h>
|
||||
#undef DrawIcon
|
||||
#undef EndMenu
|
||||
#undef FindResource
|
||||
#endif
|
||||
|
||||
#ifdef USE_ZZIPLIB
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) ) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue