- The Spells are ready now!
This commit is contained in:
parent
1b7e613b54
commit
be03bc5d50
30 changed files with 1455 additions and 532 deletions
225
Rules.make
225
Rules.make
|
@ -1,6 +1,6 @@
|
|||
## ___________ _________ _____ __
|
||||
## \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
|
||||
## | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
||||
## | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \ __\ __\
|
||||
## | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
|
||||
## \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
|
||||
## \/ \/ \/ \/ \/
|
||||
|
@ -8,244 +8,71 @@
|
|||
## T H E W A R B E G I N S
|
||||
## FreeCraft - A free fantasy real time strategy game engine
|
||||
##
|
||||
## Rules.make - Make RULES (GNU MAKE).
|
||||
##
|
||||
## (c) Copyright 1998-2000 by Lutz Sammer
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
############################################################################
|
||||
# Configurable:
|
||||
# Choose what you want to include and the correct
|
||||
# version. Minimal is now the default.
|
||||
############################################################################
|
||||
# Compile commands
|
||||
CC=gcc
|
||||
RM=rm -f
|
||||
MAKE=make
|
||||
|
||||
# Uncomment next to get guile with gtk (and choose your gtklib version)
|
||||
|
||||
#GUILEGTK = -DGUILE_GTK $(shell gtk-config --cflags)
|
||||
#GUILEGTK = -DGUILE_GTK -I/usr/X11R6/include -I/usr/lib/glib/include
|
||||
#GUILEGTKLIB = -lguilegtk-1.0 $(shell gtk-config --libs)
|
||||
#GUILEGTKLIB = -lguilegtk-1.2 $(shell gtk-config --libs)
|
||||
#GUILEGTKLIB = -L/opt/gnome/lib -lguilegtk-1.1 \
|
||||
$(shell /opt/gnome/bin/gtk-config --libs)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Uncomment next for a version with guile (GNU scheme interpreter)
|
||||
# (and choose your guile version)
|
||||
|
||||
# guile 1.2 old version
|
||||
# If you have unreferenced "gh_vector_ref" define LIBGUILE12
|
||||
#GUILE = -DLIBGUILE12 -DUSE_CCL $(GUILEGTK)
|
||||
#GUILELIB = $(GUILEGTKLIB) -lguile -ldl
|
||||
|
||||
# guile 1.3 latest version
|
||||
# -lreadline -lncurses are needed with the distribution SuSe 5.3
|
||||
#GUILE_CFLAGS = $(shell guile-config compile)
|
||||
#GUILE = -DUSE_CCL $(GUILEGTK) $(GUILE_CFLAGS)
|
||||
#GUILELIB = $(GUILEGTKLIB) -lguile -lqthreads -ldl -lm
|
||||
#GUILELIB = $(GUILEGTKLIB) $(shell guile-config link) -lreadline -lncurses
|
||||
#GUILELIB = $(GUILEGTKLIB) $(shell guile-config link)
|
||||
|
||||
# guile
|
||||
#CCL = $(GUILE)
|
||||
#CCLLIB = $(GUILELIB)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Comment next for a version without SIOD (scheme interpreter)
|
||||
#
|
||||
|
||||
# Try to use siod (currently default)
|
||||
CCL = -DUSE_CCL2
|
||||
CCLLIB = -lm
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Uncomment next to add threaded sound support
|
||||
# You should have a thread safe X11 (libc6 or glibc)
|
||||
|
||||
#THREAD = -D_REENTRANT -DUSE_THREAD
|
||||
#THREADLIB = -lpthread
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Choose correct version of glib (needed for gtk)
|
||||
|
||||
# Where do you have installed your glib?
|
||||
#GLIB = -DUSE_GLIB -I/usr/lib/glib/include/
|
||||
#GLIBLIB = -lglib
|
||||
|
||||
# Should work with >= 1.2
|
||||
#GLIB_CFLAGS = $(shell glib-config glib --cflags)
|
||||
#GLIBLIB = $(shell glib-config glib --libs)
|
||||
#GLIB = -DUSE_GLIB $(GLIB_CFLAGS)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Video driver part
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Uncomment the next for the normal X11 support.
|
||||
# Use SIOD support
|
||||
CCL = -DUSE_CCL2
|
||||
CCLLIB = -lm -ldl
|
||||
|
||||
# Video support
|
||||
VIDEO = -DUSE_X11
|
||||
VIDEOLIB = -lXext -lX11 -ldl
|
||||
|
||||
# Uncomment the next to get the support for SDL.
|
||||
|
||||
# Old SDL <1.0.0
|
||||
#SDL_CFLAGS =
|
||||
#SDLLIB = -lSDL -ldl -lpthread
|
||||
|
||||
# New SDL >=1.0.0
|
||||
SDL_CFLAGS = $(shell sdl-config --cflags)
|
||||
#SDLLIB = $(shell sdl-config --static-libs)
|
||||
SDLLIB = $(shell sdl-config --libs)
|
||||
|
||||
# Without SDL Sound
|
||||
#SDL = -DUSE_SDL $(SDL_CFLAGS)
|
||||
# With SDL Sound
|
||||
SDL = -DUSE_SDL -DUSE_SDLA $(SDL_CFLAGS)
|
||||
|
||||
# Uncomment the next for the SDL X11/SVGALIB support.
|
||||
|
||||
VIDEO = $(SDL)
|
||||
VIDEOLIB = $(SDLLIB) -lXext -lX11 -lXxf86dga -lXxf86vm -lvga -lvgagl -ldl -lesd -lm
|
||||
|
||||
# Choose next to get svgalib support.
|
||||
|
||||
#VIDEO = -DUSE_SVGALIB
|
||||
#VIDEOLIB = -lvga -lm -ldl
|
||||
|
||||
# Uncomment the next for the win32/cygwin support.
|
||||
|
||||
#VIDEO = -DUSE_WIN32 $(SDL)
|
||||
#VIDEOLIB = $(SDLLIB)
|
||||
|
||||
# Uncomment the next for the win32/mingw32 support.
|
||||
|
||||
#VIDEO = -DUSE_WIN32 $(SDL)
|
||||
#VIDEOLIB = $(SDLLIB) -lwsock32 -Wl,--stack,33554432
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Sound driver part
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Comment next if you want to remove sound support.
|
||||
VIDEOLIB = -lXext -lX11 -ldl
|
||||
|
||||
# Sound support
|
||||
DSOUND = -DWITH_SOUND
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Choose which compress you like
|
||||
# The win32 port didn't support BZ2LIB
|
||||
|
||||
# None
|
||||
#ZDEFS =
|
||||
#ZLIBS =
|
||||
# GZ compression
|
||||
ZDEFS = -DUSE_ZLIB
|
||||
ZLIBS = -lz
|
||||
# BZ2 compression
|
||||
#ZDEFS = -DUSE_BZ2LIB
|
||||
#ZLIBS = -lbz2
|
||||
# GZ + BZ2 compression
|
||||
#ZDEFS = -DUSE_ZLIB -DUSE_BZ2LIB
|
||||
#ZLIBS = -lz -lbz2
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# May be required on some distributions for libpng and libz!
|
||||
# extra linker flags and include directory
|
||||
# -L/usr/lib
|
||||
# Compression support
|
||||
ZDEFS = -DUSE_ZLIB -DUSE_BZ2LIB
|
||||
ZLIBS = -lz -lbz2
|
||||
|
||||
XLDFLAGS = -L/usr/X11R6/lib -L/usr/local/lib \
|
||||
-L$(TOPDIR)/libpng-1.0.5 -L$(TOPDIR)/zlib-1.1.3
|
||||
XIFLAGS = -I/usr/X11R6/include -I/usr/local/include \
|
||||
-I$(TOPDIR)/libpng-1.0.5 -I$(TOPDIR)/zlib-1.1.3
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Uncomment next to profile
|
||||
#PROFILE= -pg
|
||||
#####################################################################
|
||||
# Don't change anything below here unless you know what you're doing!
|
||||
|
||||
# Version
|
||||
VERSION= '-DVERSION="1.17pre1-build7"'
|
||||
PROFILE=
|
||||
|
||||
############################################################################
|
||||
# below this, nothing should be changed!
|
||||
|
||||
# Libraries needed to build tools
|
||||
TOOLLIBS=$(XLDFLAGS) -lpng -lz -lm $(THREADLIB)
|
||||
|
||||
# Libraries needed to build freecraft
|
||||
CLONELIBS=$(XLDFLAGS) -lpng -lz -lm \
|
||||
$(THREADLIB) $(CCLLIB) $(GLIBLIB) $(VIDEOLIB) $(ZLIBS)
|
||||
|
||||
$(THREADLIB) $(CCLLIB) $(VIDEOLIB) $(ZLIBS)
|
||||
DISTLIST=$(TOPDIR)/distlist
|
||||
TAGS=$(TOPDIR)/src/tags
|
||||
|
||||
# LINUX
|
||||
# Linux
|
||||
EXE=
|
||||
OUTFILE=$(TOPDIR)/freecraft
|
||||
ARCH=linux
|
||||
OE=o
|
||||
EXE=
|
||||
|
||||
# WIN32
|
||||
#OUTFILE=$(TOPDIR)/freecraft$(EXE)
|
||||
#ARCH=win32
|
||||
#OE=o
|
||||
#EXE=.exe
|
||||
|
||||
## architecture-dependant objects
|
||||
#ARCHOBJS=stdmman.$(OE) svgalib.$(OE) unix_lib.$(OE) bitm_lnx.$(OE)
|
||||
|
||||
## include flags
|
||||
IFLAGS= -I$(TOPDIR)/src/include $(XIFLAGS)
|
||||
## define flags
|
||||
DEBUG= -DDEBUG #-DNEW_AI # -DFLAG_DEBUG
|
||||
DFLAGS= $(THREAD) $(CCL) $(VERSION) $(GLIB) $(VIDEO) $(ZDEFS) $(DSOUND) \
|
||||
$(DEBUG) -DUNIT_ON_MAP # -DNEW_NAMES
|
||||
|
||||
## choose optimise level
|
||||
#CFLAGS=-g -O0 $(PROFILE) -pipe -Wall -Werror $(IFLAGS) $(DFLAGS)
|
||||
#CFLAGS=-g -O1 $(PROFILE) -pipe -Wall -Werror $(IFLAGS) $(DFLAGS)
|
||||
#CFLAGS=-g -O2 $(PROFILE) -pipe -Wall -Werror $(IFLAGS) $(DFLAGS)
|
||||
CFLAGS=-g -O3 $(PROFILE) -pipe -Wall -Werror $(IFLAGS) $(DFLAGS)
|
||||
#CFLAGS=-g -O3 $(PROFILE) -pipe -Wall $(IFLAGS) $(DFLAGS)
|
||||
#CFLAGS=-g -O6 -pipe -fconserve-space -fexpensive-optimizations -ffast-math $(IFLAGS) $(DFLAGS)
|
||||
#-- Production
|
||||
#CFLAGS=-O6 -pipe -fomit-frame-pointer -fconserve-space -fexpensive-optimizations -ffast-math $(IFLAGS) $(DFLAGS)
|
||||
CFLAGS=-O6 -pipe -fomit-frame-pointer -fconserve-space -fexpensive-optimizations -ffast-math $(IFLAGS) $(DFLAGS) -static
|
||||
|
||||
CC=gcc
|
||||
RM=rm -f
|
||||
MAKE=make
|
||||
|
||||
## JOHNS: my ctags didn't support
|
||||
#CTAGSFLAGS=-i defmpstuvFS -a -f
|
||||
DFLAGS= $(THREAD) $(CCL) $(VERSION) \
|
||||
$(VIDEO) $(ZDEFS) $(DSOUND) \
|
||||
$(DEBUG)
|
||||
CFLAGS=-g $(IFLAGS) $(DFLAGS) -DSLOW_INPUT -DUNIT_ON_MAP
|
||||
CTAGSFLAGS=-i defptvS -a -f
|
||||
|
||||
#
|
||||
# Locks versions with symbolic name
|
||||
#
|
||||
# Locks versions with a symbolic name
|
||||
LOCKVER= rcs -q -n$(NAME)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $< -o $@
|
||||
@ar cru $(TOPDIR)/src/libclone.a $@
|
||||
|
||||
#------------
|
||||
# Source code documentation
|
||||
#
|
||||
# Source code documentation
|
||||
DOXYGEN= doxygen
|
||||
DOCIFY= docify
|
||||
DOCPP= doc++
|
||||
# Still didn't work
|
||||
#DOCIFY= /root/doc++-3.4.2/src/docify
|
||||
#DOCPP= /root/doc++-3.4.2/src/doc++
|
||||
|
||||
%.doc: %.c
|
||||
@$(TOPDIR)/tools/aledoc $< | $(DOCIFY) > $*-c.doc 2>/dev/null
|
||||
|
||||
%.doc: %.h
|
||||
@$(TOPDIR)/tools/aledoc $< | $(DOCIFY) > $*-h.doc 2>/dev/null
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
## ___________ _________ _____ __
|
||||
## \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
|
||||
## | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
||||
## | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
||||
## | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
|
||||
## \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
|
||||
## \/ \/ \/ \/ \/
|
||||
|
@ -27,6 +27,7 @@ OBJS = command.$(OE) actions.$(OE) action_die.$(OE) action_patrol.$(OE) \
|
|||
action_board.$(OE) action_unload.$(OE) action_repair.$(OE) \
|
||||
action_harvest.$(OE) action_minegold.$(OE) action_hauloil.$(OE) \
|
||||
action_returngoods.$(OE) action_research.$(OE) action_demolish.$(OE) \
|
||||
action_build.$(OE) action_train.$(OE) action_upgradeto.$(OE)
|
||||
action_build.$(OE) action_train.$(OE) action_upgradeto.$(OE) \
|
||||
action_spellcast.$(OE)
|
||||
|
||||
include $(TOPDIR)/Common.mk
|
||||
|
|
|
@ -73,6 +73,7 @@ local void DoActionAttackGeneric(Unit* unit,const Animation* attack)
|
|||
|
||||
if( flags&AnimationMissile ) { // time to fire projectil
|
||||
FireMissile(unit);
|
||||
unit->Invisible = 0; // unit is invisible untill attacks
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -130,7 +130,8 @@ global void HandleActionDemolish(Unit* unit)
|
|||
n=SelectUnits(x-2,y-2, x+2, y+2,table);
|
||||
// FIXME: Don't hit flying units!
|
||||
for( i=0; i<n; ++i ) {
|
||||
HitUnit(table[i],DEMOLISH_DAMAGE);
|
||||
if ( table[i]->Type->LandUnit )
|
||||
HitUnit(table[i],DEMOLISH_DAMAGE);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -46,6 +46,14 @@
|
|||
*/
|
||||
global int HandleActionDie(Unit* unit)
|
||||
{
|
||||
if ( unit->Revealer )
|
||||
{
|
||||
unit->HP--;
|
||||
if( unit->HP == 0 )
|
||||
ReleaseUnit(unit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Show death animation
|
||||
//
|
||||
|
|
|
@ -94,6 +94,10 @@ global int UnitShowAnimation(Unit* unit,const Animation* animation)
|
|||
*/
|
||||
local void HandleUnitAction(Unit* unit)
|
||||
{
|
||||
if ( unit->Revealer )
|
||||
{
|
||||
unit->Command.Action = UnitActionDie;
|
||||
}
|
||||
//
|
||||
// If current action is breakable proceed with next one.
|
||||
//
|
||||
|
@ -237,6 +241,10 @@ local void HandleUnitAction(Unit* unit)
|
|||
HandleActionDemolish(unit);
|
||||
break;
|
||||
|
||||
case UnitActionSpellCast:
|
||||
HandleActionSpellCast(unit);
|
||||
break;
|
||||
|
||||
default:
|
||||
DebugLevel1Fn("Unknown action %d\n",unit->Command.Action);
|
||||
break;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "map.h"
|
||||
#include "upgrade.h"
|
||||
#include "pathfinder.h"
|
||||
#include "spells.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
|
@ -829,4 +830,66 @@ global void CommandDemolish(Unit* unit,int x,int y,Unit* dest,int flush)
|
|||
unit->SavedCommand.Action=UnitActionStill; // clear saved action
|
||||
}
|
||||
|
||||
/**
|
||||
** Demolish at position
|
||||
**
|
||||
** @param unit pointer to unit.
|
||||
** @param x X map position to spell cast on.
|
||||
** @param y Y map position to spell cast on.
|
||||
** @param dest Spell cast on unit (if exist).
|
||||
** @param spellid Spell type id.
|
||||
** @param flush if true, flush command queue.
|
||||
*/
|
||||
global void CommandSpellCast(Unit* unit,int x,int y,Unit* dest,int spellid,int flush)
|
||||
{
|
||||
Command* command;
|
||||
const SpellType* spell;
|
||||
|
||||
IfDebug(
|
||||
if( x<0 || y<0 || x>=TheMap.Width || y>=TheMap.Height ) {
|
||||
DebugLevel0("Internal movement error\n");
|
||||
return;
|
||||
}
|
||||
if( unit->Type->Vanishes ) {
|
||||
DebugLevel0("Internal error\n");
|
||||
abort();
|
||||
}
|
||||
);
|
||||
|
||||
DebugLevel3(__FUNCTION__": %Zd spell-casts on %Zd\n"
|
||||
,UnitNumber(unit),dest ? UnitNumber(dest) : 0);
|
||||
|
||||
if( unit->Type->Building ) {
|
||||
// FIXME: should find a better way for pending commands.
|
||||
command=&unit->PendCommand;
|
||||
} else if( !(command=GetNextCommand(unit,flush)) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
spell = SpellTypeById( spellid );
|
||||
|
||||
command->Action=UnitActionSpellCast;
|
||||
ResetPath(*command);
|
||||
|
||||
if (dest)
|
||||
dest->Refs++;
|
||||
|
||||
command->Data.Move.Goal=dest;
|
||||
command->Data.Move.Range=spell->Range;
|
||||
command->Data.Move.SX=unit->X;
|
||||
command->Data.Move.SY=unit->Y;
|
||||
command->Data.Move.DX=x;
|
||||
command->Data.Move.DY=y;
|
||||
command->Data.Move.SpellId = spellid;
|
||||
|
||||
/*
|
||||
command->Data.Spell.Goal=dest;
|
||||
command->Data.Spell.Range=spell->Range;
|
||||
command->Data.Spell.DX=x;
|
||||
command->Data.Spell.DY=y;
|
||||
*/
|
||||
|
||||
unit->SavedCommand.Action=UnitActionStill; // clear saved action
|
||||
}
|
||||
|
||||
//@}
|
||||
|
|
|
@ -88,6 +88,8 @@ extern void CommandCancelResearch(Unit* unit);
|
|||
//extern void CommandUpgradeUnit(Unit* unit,int what,int flush);
|
||||
/// Prepare command demolish
|
||||
extern void CommandDemolish(Unit* unit,int x,int y,Unit* dest,int flush);
|
||||
/// Prepare command spellcast
|
||||
extern void CommandSpellCast(Unit* unit,int x,int y,Unit* dest,int spellid, int flush);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Actions: in action_<name>.c
|
||||
|
@ -135,6 +137,8 @@ extern void HandleActionUpgrade(Unit* unit);
|
|||
extern void HandleActionResearch(Unit* unit);
|
||||
/// Handle command demolish
|
||||
extern void HandleActionDemolish(Unit* unit);
|
||||
/// Handle command spellcast
|
||||
extern void HandleActionSpellCast(Unit* unit);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Actions: actions.c
|
||||
|
|
|
@ -82,6 +82,7 @@ extern CursorType Cursors[CursorMax]; /// cursor types description
|
|||
|
||||
extern enum CursorState_e CursorState; /// cursor state
|
||||
extern int CursorAction; /// action for selection
|
||||
extern int CursorValue; /// value for CursorAction (spell type f.e.)
|
||||
extern UnitType* CursorBuilding; /// building cursor
|
||||
|
||||
extern CursorType* GameCursor; /// cursor type
|
||||
|
|
|
@ -47,7 +47,7 @@ enum _button_cmd_ {
|
|||
B_AttackGround, /// order attack ground
|
||||
B_Return, /// order return goods
|
||||
B_Demolish, /// order demolish/explode
|
||||
B_Magic, /// order cast spell
|
||||
B_SpellCast, /// order cast spell
|
||||
B_Research, /// order reseach
|
||||
B_UpgradeTo, /// order upgrade
|
||||
B_Unload, /// order unload unit
|
||||
|
|
|
@ -69,7 +69,7 @@ struct _missile_type_ {
|
|||
};
|
||||
|
||||
/// how many missile type are maximal supported
|
||||
#define MissileTypeMax 0x1E
|
||||
#define MissileTypeMax 0x22
|
||||
|
||||
/// mark a free missile slot
|
||||
#define MissileFree (MissileType*)0
|
||||
|
@ -96,11 +96,18 @@ typedef struct _missile_ {
|
|||
UnitStats* SourceStats; /// stats of unit that fires
|
||||
Player* SourcePlayer; /// player of unit that fires
|
||||
|
||||
Unit* TargetUnit; /// target unit, used for spells
|
||||
|
||||
int Damage; /// direct damage that missile applies
|
||||
|
||||
int D; /// for point to point missiles
|
||||
int Dx; /// delta x
|
||||
int Dy; /// delta y
|
||||
int Xstep; /// X step
|
||||
int Ystep; /// Y step
|
||||
|
||||
int TTL; /// time to live (ticks) used for spells
|
||||
int (*Controller)( void* this_missile ); /// used to controll spells
|
||||
} Missile;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
|
|
@ -105,7 +105,8 @@ extern void SendCommandResearch(Unit* unit,Upgrade* what,int flush);
|
|||
extern void SendCommandCancelResearch(Unit* unit);
|
||||
/// Send demolish command
|
||||
extern void SendCommandDemolish(Unit* unit,int x,int y,Unit* dest,int flush);
|
||||
|
||||
/// Send spell cast command
|
||||
extern void SendCommandSpellCast(Unit* unit,int x,int y,Unit* dest,int spellid,int flush);
|
||||
//@}
|
||||
|
||||
#endif // !__NETWORK_H__
|
||||
|
|
112
src/include/spells.h
Normal file
112
src/include/spells.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
// ___________ _________ _____ __
|
||||
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
|
||||
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
||||
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
|
||||
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
|
||||
// \/ \/ \/ \/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// FreeCraft - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spells.h - The Spells. */
|
||||
/*
|
||||
** (c) Copyright 1999,2000 by Vladi Belperchinov-Shabanski
|
||||
**
|
||||
** $Id$
|
||||
*/
|
||||
|
||||
#ifndef __SPELLS_H__
|
||||
#define __SPELLS_H__
|
||||
|
||||
//@{
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Includes
|
||||
----------------------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "freecraft.h"
|
||||
#include "sound_id.h"
|
||||
#include "sound.h"
|
||||
#include "unittype.h"
|
||||
#include "unit.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Definitons
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
typedef enum _spell_action_type_ {
|
||||
SpellActionNone,
|
||||
// ---human paladins---
|
||||
SpellActionHolyVision,
|
||||
SpellActionHealing,
|
||||
SpellActionExorcism,
|
||||
// ---human mages---
|
||||
SpellActionFireball,
|
||||
SpellActionSlow,
|
||||
SpellActionFlameShield,
|
||||
SpellActionInvisibility,
|
||||
SpellActionPolymorph,
|
||||
SpellActionBlizzard,
|
||||
// ---orc ogres---
|
||||
SpellActionEyeOfKilrogg,
|
||||
SpellActionBloodlust,
|
||||
SpellActionRunes,
|
||||
// ---orc death knights---
|
||||
SpellActionDeathCoil,
|
||||
SpellActionHaste,
|
||||
SpellActionRaiseDead,
|
||||
SpellActionWhirlwind,
|
||||
SpellActionUnholyArmor,
|
||||
SpellActionDeathAndDecay
|
||||
} SpellActionType;
|
||||
|
||||
typedef struct _spell_type_ {
|
||||
|
||||
int Id; /// index in the table (set by InitSpells())
|
||||
char Ident[64]; /// spell name (ident)
|
||||
|
||||
int Range; /// spell range
|
||||
int ManaCost; /// required mana for each cast
|
||||
int TTL; /// time to live (ticks)
|
||||
|
||||
SpellActionType Action; /// SpellAction*
|
||||
|
||||
char SoundIdent[64]; /// sound string id
|
||||
SoundId SoundId; /// sound id
|
||||
|
||||
} SpellType;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Variables
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/// init spell tables
|
||||
extern global void InitSpells();
|
||||
|
||||
/// done spell tables
|
||||
extern global void DoneSpells();
|
||||
|
||||
/// return spell id by ident string
|
||||
extern global int SpellIdByIdent( const char* Ident );
|
||||
|
||||
/// return spell type by ident string
|
||||
extern global const SpellType* SpellTypeByIdent( const char* Ident );
|
||||
|
||||
/// return spell type by ident string
|
||||
extern global const SpellType* SpellTypeById( int Id );
|
||||
|
||||
/* /// returns != 0 if spell can be casted by this unit, enough mana?
|
||||
extern global int CanCastSpell( Unit* unit, int SpellId );
|
||||
*/
|
||||
/// fire spell on target unit or place at x,y
|
||||
extern global int SpellCast( int SpellId, Unit* unit, Unit* target, int x, int y );
|
||||
|
||||
//@}
|
||||
|
||||
#endif // !__BUTTON_H__
|
|
@ -1,6 +1,6 @@
|
|||
// ___________ _________ _____ __
|
||||
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
|
||||
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
||||
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
||||
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
|
||||
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
|
||||
// \/ \/ \/ \/ \/
|
||||
|
@ -62,6 +62,8 @@ enum _unit_action_ {
|
|||
UnitActionAttackGround, /// unit attacks ground
|
||||
UnitActionDie, /// unit dies
|
||||
|
||||
UnitActionSpellCast, /// unit casts spell
|
||||
|
||||
UnitActionTrain, /// building is training
|
||||
UnitActionUpgradeTo, /// building is upgrading itself
|
||||
// UnitActionUpgrade, /// building is researching upgrade
|
||||
|
@ -130,6 +132,7 @@ struct _command_ {
|
|||
unsigned SY; /// Source
|
||||
unsigned DX;
|
||||
unsigned DY; /// Destination
|
||||
int SpellId; /// spell type id
|
||||
} Move; /// move:
|
||||
struct {
|
||||
unsigned Fast : 1; /// Can fast move
|
||||
|
@ -152,7 +155,7 @@ struct _command_ {
|
|||
struct {
|
||||
unsigned Ticks; /// Ticks to complete
|
||||
unsigned Count; /// Units in training queue
|
||||
// FIXME: cade: later we should train more units or automatic
|
||||
// FIXME: vladi: later we should train more units or automatic
|
||||
#define MAX_UNIT_TRAIN 6
|
||||
UnitType* What[MAX_UNIT_TRAIN]; /// Unit trained
|
||||
} Train; /// train:
|
||||
|
@ -230,7 +233,7 @@ struct _unit_ {
|
|||
UnitType* Type; /// pointer to unit type (peon,...)
|
||||
Player* Player; /// owner of this unit
|
||||
UnitStats* Stats; /// current unit stats
|
||||
|
||||
|
||||
// DISPLAY:
|
||||
char IX;
|
||||
char IY; /// image displacement to map position
|
||||
|
@ -252,10 +255,11 @@ struct _unit_ {
|
|||
unsigned HP; /// hit points
|
||||
|
||||
unsigned Bloodlust; /// ticks bloodlust
|
||||
unsigned Haste; /// ticks haste
|
||||
unsigned Slow; /// ticks slow
|
||||
unsigned Haste; /// ticks haste (disables slow)
|
||||
unsigned Slow; /// ticks slow (disables haste)
|
||||
unsigned Invisible; /// ticks invisible
|
||||
unsigned Shield; /// ticks shield
|
||||
unsigned FlameShield; /// ticks flame shield
|
||||
unsigned UnholyArmor; /// ticks unholy armor
|
||||
|
||||
unsigned GroupId; /// unit belongs to this group id
|
||||
|
||||
|
@ -273,6 +277,10 @@ struct _unit_ {
|
|||
** ,used for fancy buildings
|
||||
*/
|
||||
unsigned Rs : 8;
|
||||
unsigned Revealer; // hack -- `revealer' is unit that
|
||||
// has to keep FOW revealed for some
|
||||
// time, this unit cannot be used in
|
||||
// usual manner
|
||||
|
||||
#define MAX_UNITS_ONBOARD 6 /// max number of units in transporter
|
||||
// FIXME: use the new next pointer
|
||||
|
|
|
@ -358,11 +358,13 @@ global void MapUpdateVisible(void)
|
|||
#ifdef NEW_FOW
|
||||
MapMarkSight(unit->Player,unit->X+unit->Type->TileWidth/2
|
||||
,unit->Y+unit->Type->TileHeight/2
|
||||
,unit->Stats->SightRange);
|
||||
,unit->Stats->SightRange*(unit->Revealer == 0)
|
||||
+ 12*(unit->Revealer != 0));
|
||||
#else
|
||||
MapMarkSight(unit->X+unit->Type->TileWidth/2
|
||||
,unit->Y+unit->Type->TileHeight/2
|
||||
,unit->Stats->SightRange);
|
||||
,unit->Stats->SightRange*(unit->Revealer == 0)
|
||||
+ 12*(unit->Revealer != 0));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ enum _message_type_ {
|
|||
MessageCommandResearch, /// unit command research
|
||||
MessageCommandCancelResearch, /// unit command cancel research
|
||||
MessageCommandDemolish, /// unit command demolish
|
||||
MessageCommandSpellCast /// unit command spell cast
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -710,6 +711,30 @@ global void SendCommandDemolish(Unit* unit,int x,int y,Unit* attack,int flush)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Send command: Unit spell cast on position/unit.
|
||||
**
|
||||
** @param unit pointer to unit.
|
||||
** @param x X map tile position where to cast spell.
|
||||
** @param y Y map tile position where to cast spell.
|
||||
** @param attack Cast spell on unit (if exist).
|
||||
** @param spellid Spell type id.
|
||||
** @param flush Flag flush all pending commands.
|
||||
*/
|
||||
global void SendCommandSpellCast(Unit* unit,int x,int y,Unit* dest,int spellid,int flush)
|
||||
{
|
||||
CommandLog("spell-cast",unit,flush,1,x,y,dest,NULL); //FIXME: vladi: spellid?
|
||||
if( NetworkFildes==-1 ) {
|
||||
CommandSpellCast(unit,x,y,dest,spellid,flush);
|
||||
} else {
|
||||
// FIXME: WARNING: vladi: this is weird, we should have and
|
||||
// integer argument to all this or just few bytes buffer or
|
||||
// something... I'll pass spell id's as pointers until...
|
||||
UnitType* ut = (UnitType*)spellid;
|
||||
NetworkSendCommand(MessageCommandSpellCast,unit,x,y,dest,ut,flush);
|
||||
}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -1718,6 +1743,12 @@ local void ParseNetworkCommand(const NetworkCommandQueue* ncq)
|
|||
}
|
||||
CommandDemolish(unit,x,y,dest,status);
|
||||
break;
|
||||
case MessageCommandSpellCast:
|
||||
// FIXME: WARNING: vladi: currently network protocol
|
||||
// cannot carry required information for spell cast
|
||||
// it is required to handle dest unit and aditional
|
||||
// integer value!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ MODULE = clone
|
|||
OBJS = clone.$(OE) unit.$(OE) unit_draw.$(OE) unitcache.$(OE) \
|
||||
unit_find.$(OE) missile.$(OE) construct.$(OE)\
|
||||
player.$(OE) pud.$(OE) ccl.$(OE) interface.$(OE) iolib.$(OE) \
|
||||
mainloop.$(OE) goal.$(OE) selection.$(OE) groups.$(OE)
|
||||
mainloop.$(OE) goal.$(OE) selection.$(OE) groups.$(OE) \
|
||||
spells.$(OE)
|
||||
|
||||
include $(TOPDIR)/Common.mk
|
||||
|
|
|
@ -318,7 +318,27 @@ local int InputKey(int key)
|
|||
SpeedResearch=1; /// speed factor for researching
|
||||
SetMessage( "NORMAL DEBUG SPEED" );
|
||||
}
|
||||
|
||||
if (strcmp(Input, "make it so") == 0)
|
||||
{
|
||||
SpeedMine=10; /// speed factor for mine gold
|
||||
SpeedGold=10; /// speed factor for getting gold
|
||||
SpeedChop=10; /// speed factor for chop
|
||||
SpeedWood=10; /// speed factor for getting wood
|
||||
SpeedHaul=10; /// speed factor for haul oil
|
||||
SpeedOil=10; /// speed factor for getting oil
|
||||
SpeedBuild=10; /// speed factor for building
|
||||
SpeedTrain=10; /// speed factor for training
|
||||
SpeedUpgrade=10; /// speed factor for upgrading
|
||||
SpeedResearch=10; /// speed factor for researching
|
||||
ThisPlayer->Resources[GoldCost] += 32000;
|
||||
ThisPlayer->Resources[WoodCost] += 32000;
|
||||
ThisPlayer->Resources[OilCost] += 32000;
|
||||
ThisPlayer->Resources[OreCost] += 32000;
|
||||
ThisPlayer->Resources[StoneCost]+= 32000;
|
||||
ThisPlayer->Resources[CoalCost] += 32000;
|
||||
MustRedraw|=RedrawResources;
|
||||
SetMessage( "SO!" );
|
||||
} else
|
||||
// FIXME: only to selected players
|
||||
NetworkChatMessage(Input);
|
||||
#if defined(USE_CCL) || defined(USE_CCL2)
|
||||
|
|
|
@ -95,6 +95,10 @@
|
|||
** Missile don't move, than checks the source unit for HP.
|
||||
*/
|
||||
#define MissileClassFire 12
|
||||
/**
|
||||
** Missile is controlled completely by Controller() function. (custom)
|
||||
*/
|
||||
#define MissileClassCustom 13
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Variables
|
||||
|
@ -135,6 +139,9 @@ local const char* MissileTypeWcNames[] = {
|
|||
"missile-cannon-tower-explosion",
|
||||
"missile-daemon-fire",
|
||||
"missile-green-cross",
|
||||
"missile-blizzard-hit",
|
||||
"missile-death-coil",
|
||||
"missile-custom",
|
||||
"missile-none",
|
||||
};
|
||||
|
||||
|
@ -178,7 +185,7 @@ global MissileType MissileTypes[MissileTypeMax] = {
|
|||
"fireball.png",
|
||||
32,32,
|
||||
{ "fireball hit" },
|
||||
MissileClassFireball,
|
||||
MissileClassPointToPoint,
|
||||
1,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
|
@ -194,15 +201,16 @@ global MissileType MissileTypes[MissileTypeMax] = {
|
|||
"blizzard.png",
|
||||
32,32,
|
||||
{ NULL },
|
||||
MissileClassBlizzard,
|
||||
MissileClassBlizzard,
|
||||
1,
|
||||
"missile-blizzard-hit", NULL
|
||||
},
|
||||
{ MissileTypeType,
|
||||
"missile-death-and-decay",
|
||||
"death and decay.png",
|
||||
32,32,
|
||||
{ NULL },
|
||||
MissileClassDeathDecay,
|
||||
MissileClassStayWithDelay,
|
||||
1,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
|
@ -227,7 +235,7 @@ global MissileType MissileTypes[MissileTypeMax] = {
|
|||
"heal effect.png",
|
||||
48,48,
|
||||
{ NULL },
|
||||
MissileClassPointToPoint,
|
||||
MissileClassStayWithDelay,
|
||||
1,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
|
@ -244,7 +252,7 @@ global MissileType MissileTypes[MissileTypeMax] = {
|
|||
16,16,
|
||||
{ NULL },
|
||||
MissileClassStayWithDelay,
|
||||
1,
|
||||
5,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
"missile-whirlwind",
|
||||
|
@ -320,7 +328,7 @@ global MissileType MissileTypes[MissileTypeMax] = {
|
|||
48,48,
|
||||
{ NULL },
|
||||
MissileClassFire,
|
||||
8,
|
||||
8,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
"missile-impact",
|
||||
|
@ -395,6 +403,38 @@ global MissileType MissileTypes[MissileTypeMax] = {
|
|||
MissileClassNone,
|
||||
1,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
"missile-blizzard-hit",
|
||||
"blizzard.png",
|
||||
32,32,
|
||||
{ NULL },
|
||||
MissileClassStayWithDelay,
|
||||
1,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
"missile-death-coil",
|
||||
"touch of death.png",
|
||||
32,32,
|
||||
{ NULL },
|
||||
MissileClassPointToPoint,
|
||||
1,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
"missile-custom",
|
||||
NULL,
|
||||
32,32,
|
||||
{ NULL },
|
||||
MissileClassCustom,
|
||||
1,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
"missile-none",
|
||||
NULL,
|
||||
32,32,
|
||||
{ NULL },
|
||||
MissileClassNone,
|
||||
1,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -409,7 +449,7 @@ local int NumMissiles; /// currently used missiles
|
|||
local Missile Missiles[MAX_MISSILES]; /// all missiles on map
|
||||
|
||||
/// lookup table for missile names
|
||||
local hashtable(MissileType*,61) MissileHash;
|
||||
local hashtable(MissileType*,65) MissileHash;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
|
@ -531,6 +571,11 @@ found:
|
|||
missile->SourceStats=NULL;
|
||||
missile->SourcePlayer=NULL;
|
||||
|
||||
missile->Damage = 0;
|
||||
missile->TargetUnit = NULL;
|
||||
missile->TTL = -1;
|
||||
missile->Controller = NULL;
|
||||
|
||||
return missile;
|
||||
}
|
||||
|
||||
|
@ -762,6 +807,9 @@ global void DrawMissiles(void)
|
|||
if( missile->Type==MissileFree ) {
|
||||
continue;
|
||||
}
|
||||
if( missile->Type->Class == MissileClassCustom ) {
|
||||
continue; // custom missiles are handled by Controller() only
|
||||
}
|
||||
// Draw only visibile missiles
|
||||
if (MissileVisible(missile)) {
|
||||
x=missile->X-MapX*TileSizeX+TheUI.MapX;
|
||||
|
@ -830,7 +878,15 @@ local int PointToPointMissile(Missile* missile)
|
|||
}
|
||||
|
||||
// FIXME: could be better written
|
||||
MissileNewHeadingFromXY(missile,dx*xstep,dy*ystep);
|
||||
if( missile->Type->Class == MissileClassWhirlwind )
|
||||
{
|
||||
// must not call MissileNewHeading nor frame change
|
||||
}
|
||||
else
|
||||
if( missile->Type->Class == MissileClassBlizzard )
|
||||
missile->Frame = 0;
|
||||
else
|
||||
MissileNewHeadingFromXY(missile,dx*xstep,dy*ystep);
|
||||
|
||||
if( dy==0 ) { // horizontal line
|
||||
if( dx==0 ) {
|
||||
|
@ -943,7 +999,9 @@ global void MissileHit(const Missile* missile)
|
|||
x=missile->X+missile->Type->Width/2;
|
||||
y=missile->Y+missile->Type->Height/2;
|
||||
if( missile->Type->ImpactMissile ) {
|
||||
MakeMissile(missile->Type->ImpactMissile,x,y,0,0);
|
||||
Missile* mis = MakeMissile(missile->Type->ImpactMissile,x,y,0,0);
|
||||
mis->Damage = missile->Damage; // direct damage, spells mostly
|
||||
mis->SourceUnit = missile->SourceUnit;
|
||||
}
|
||||
if( !missile->SourceType ) { // no target
|
||||
return;
|
||||
|
@ -961,19 +1019,27 @@ global void MissileHit(const Missile* missile)
|
|||
DebugLevel3Fn("Missile on wall?\n");
|
||||
// FIXME: don't use UnitTypeByIdent here, this is slow!
|
||||
if( HumanWallOnMap(x,y) ) {
|
||||
HitWall(x,y,CalculateDamageStats(missile->SourceStats,
|
||||
UnitTypeByIdent("unit-human-wall")->Stats));
|
||||
if ( missile->Damage )
|
||||
HitWall(x,y,missile->Damage); // direct damage, spells mostly
|
||||
else
|
||||
HitWall(x,y,CalculateDamageStats(missile->SourceStats,
|
||||
UnitTypeByIdent("unit-human-wall")->Stats));
|
||||
} else {
|
||||
HitWall(x,y,CalculateDamageStats(missile->SourceStats,
|
||||
UnitTypeByIdent("unit-orc-wall")->Stats));
|
||||
if ( missile->Damage )
|
||||
HitWall(x,y,missile->Damage); // direct damage, spells mostly
|
||||
else
|
||||
HitWall(x,y,CalculateDamageStats(missile->SourceStats,
|
||||
UnitTypeByIdent("unit-orc-wall")->Stats));
|
||||
}
|
||||
return;
|
||||
}
|
||||
DebugLevel3Fn("Oops nothing to hit (%d,%d)?\n",x,y);
|
||||
return;
|
||||
}
|
||||
|
||||
HitUnit(goal,CalculateDamage(missile->SourceStats,goal));
|
||||
if ( missile->Damage )
|
||||
HitUnit(goal,missile->Damage); // direct damage, spells mostly
|
||||
else
|
||||
HitUnit(goal,CalculateDamage(missile->SourceStats,goal));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -992,6 +1058,25 @@ global void MissileActions(void)
|
|||
if( missile->Wait-- ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( missile->TTL != -1 ) {
|
||||
missile->TTL--; // overall time to live if specified
|
||||
}
|
||||
|
||||
if ( missile->Controller ) {
|
||||
missile->Controller( missile );
|
||||
}
|
||||
|
||||
if ( missile->TTL == 0 ) {
|
||||
missile->Type=MissileFree;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( missile->Type->Class == MissileClassCustom ) {
|
||||
missile->Wait=missile->Type->Speed;
|
||||
continue; // custom missiles are handled by Controller() only
|
||||
}
|
||||
|
||||
if (MissileVisible(missile)) {
|
||||
// check before movement
|
||||
MustRedraw|=RedrawMap;
|
||||
|
@ -1088,6 +1173,31 @@ global void MissileActions(void)
|
|||
}
|
||||
break;
|
||||
|
||||
case MissileClassBlizzard:
|
||||
missile->Wait=missile->Type->Speed;
|
||||
if( PointToPointMissile(missile) ) {
|
||||
//
|
||||
// Animate hit
|
||||
//
|
||||
missile->Frame+=4; // FIXME: frames pro row
|
||||
if( (missile->Frame&127)
|
||||
>=VideoGraphicFrames(missile->Type->Sprite) ) {
|
||||
MissileHit(missile);
|
||||
missile->Type=MissileFree;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MissileClassWhirlwind:
|
||||
missile->Wait=missile->Type->Speed;
|
||||
missile->Frame++;
|
||||
if ( missile->Frame > 3 )
|
||||
missile->Frame = 0;
|
||||
//NOTE: vladi: whirlwind moves slowly, i.e. it stays
|
||||
// 5 ticks at the same pixels...
|
||||
if ( missile->TTL < 1 || missile->TTL % 10 == 0 )
|
||||
PointToPointMissile(missile);
|
||||
break;
|
||||
|
||||
case MissileClassStayWithDelay:
|
||||
missile->Wait=missile->Type->Speed;
|
||||
if( ++missile->Frame
|
||||
|
|
|
@ -89,6 +89,11 @@ global void ChangeSelectedUnits(Unit** units,int count)
|
|||
*/
|
||||
global int SelectUnit(Unit* unit)
|
||||
{
|
||||
if ( unit->Revealer )
|
||||
{
|
||||
return 0; // Revealers cannot be selected
|
||||
}
|
||||
|
||||
if( NumSelected == MaxSelectable ) {
|
||||
return 0;
|
||||
}
|
||||
|
|
793
src/stratagus/spells.cpp
Normal file
793
src/stratagus/spells.cpp
Normal file
|
@ -0,0 +1,793 @@
|
|||
// ___________ _________ _____ __
|
||||
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
|
||||
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
||||
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
|
||||
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
|
||||
// \/ \/ \/ \/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// FreeCraft - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name action_spellcast.c - The spell cast action. */
|
||||
/*
|
||||
** (c) Copyright 1998-2000 by Vladi Belperchinov-Shabanski
|
||||
**
|
||||
** $Id$
|
||||
*/
|
||||
/*
|
||||
** And when we cast our final spell
|
||||
** And we meet in our dreams
|
||||
** A place that no one else can go
|
||||
** Don't ever let your love die
|
||||
** Don't ever go breaking this spell
|
||||
*/
|
||||
|
||||
//@{
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Notes
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Includes
|
||||
----------------------------------------------------------------------------*/
|
||||
#include "spells.h"
|
||||
#include "sound.h"
|
||||
#include "missile.h"
|
||||
#include "map.h"
|
||||
#include "ui.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Definitons
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
#define FIREBALL_DAMAGE 20
|
||||
#define WHIRLWIND_DAMAGE1 4 // the center of the whirlwind
|
||||
#define WHIRLWIND_DAMAGE2 1 // the periphery of the whirlwind
|
||||
#define BLIZZARD_DAMAGE 10
|
||||
#define DEATHANDDECAY_DAMAGE 10
|
||||
#define RUNE_DAMAGE 50
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Variables
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
NOTE: vladi:
|
||||
|
||||
The point to have variable unosrted list of spell types and
|
||||
dynamic id's and in the same time -- SpellAction id's is that
|
||||
spell actions are hardcoded and cannot be changed at all.
|
||||
On the other hand we can have different spell types as with
|
||||
different range, cost and time to live (possibly and other
|
||||
parameters as extensions)
|
||||
*/
|
||||
|
||||
global SpellType SpellTypeTable[] = {
|
||||
|
||||
//TTL's below are in ticks: approx: 500=13sec, 1000=25sec, 2000=50sec
|
||||
|
||||
//id, ident, range, mana, ttl, spell action, sound ident, sound id
|
||||
// ---human paladins---
|
||||
{ 0, "spell-holy-vision", 1024, 70, -1, SpellActionHolyVision , "holy vision", NULL },
|
||||
{ 0, "spell-healing", 4, 6, -1, SpellActionHealing , "healing", NULL },
|
||||
{ 0, "spell-exorcism", 10, 4, -1, SpellActionExorcism , "exorcism", NULL },
|
||||
// ---human mages--- ---human mages---
|
||||
{ 0, "spell-fireball", 8, 100, 999, SpellActionFireball , "fireball", NULL },
|
||||
{ 0, "spell-slow", 10, 50,1000, SpellActionSlow , "slow", NULL },
|
||||
{ 0, "spell-flame-shield", 6, 80, 600, SpellActionFlameShield , "flame shield", NULL },
|
||||
{ 0, "spell-invisibility", 6, 200,2000, SpellActionInvisibility , "invisibility", NULL },
|
||||
{ 0, "spell-polymorph", 10, 200, -1, SpellActionPolymorph , "polymorph", NULL },
|
||||
{ 0, "spell-blizzard", 12, 5, -1, SpellActionBlizzard , "blizzard", NULL },
|
||||
// ---orc ogres--- ---orc ogres---
|
||||
{ 0, "spell-eye-of-kilrogg",1024, 70, -1, SpellActionEyeOfKilrogg , "eye of kilrogg", NULL },
|
||||
{ 0, "spell-bloodlust", 6, 50,1000, SpellActionBloodlust , "bloodlust", NULL },
|
||||
{ 0, "spell-runes", 10, 50,2000, SpellActionRunes , "runes", NULL },
|
||||
// ---orc death knights--- ---orc death knights-
|
||||
{ 0, "spell-death-coil", 10, 100, -1, SpellActionDeathCoil , "death coil", NULL },
|
||||
{ 0, "spell-haste", 6, 50,1000, SpellActionHaste , "haste", NULL },
|
||||
{ 0, "spell-raise-dead", 6, 50, -1, SpellActionRaiseDead , "raise dead", NULL },
|
||||
{ 0, "spell-whirlwind", 12, 100, 800, SpellActionWhirlwind , "whirlwind", NULL },
|
||||
{ 0, "spell-unholy-armor", 6, 100, 500, SpellActionUnholyArmor , "unholy armor", NULL },
|
||||
{ 0, "spell-death-and-decay", 12, 5, -1, SpellActionDeathAndDecay, "death and decay",NULL },
|
||||
// ---eot marker--- ---eot marker---
|
||||
{-1, "", 1, 1, -1, SpellActionNone , "", }
|
||||
};
|
||||
|
||||
local int SpellTypeCount;
|
||||
|
||||
MissileType* missile_healing = NULL;
|
||||
MissileType* missile_spell = NULL;
|
||||
MissileType* missile_exorcism = NULL;
|
||||
MissileType* missile_explosion = NULL;
|
||||
MissileType* missile_rune = NULL;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions (Spells Controllers/Callbacks)
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
** Missile controllers should return 0 to continue
|
||||
** or 1 to cancel the spell/missile
|
||||
*/
|
||||
|
||||
/*
|
||||
** Fireball controller
|
||||
*/
|
||||
global int SpellFireballController( void* missile )
|
||||
{
|
||||
Unit* table[MAX_UNITS];
|
||||
int i;
|
||||
int n;
|
||||
|
||||
Missile* mis = (Missile*)missile;
|
||||
|
||||
//NOTE: vladi: TTL is used as counter for explosions
|
||||
// first 6 counts there are no explosions, then on each second
|
||||
// and at the target destination
|
||||
if ( (mis->TTL < 993 && mis->TTL % 2 == 0) || (mis->X == mis->DX && mis->Y == mis->DY) ) // approx.
|
||||
{
|
||||
//+TileSize/2 to align gfx to baseline
|
||||
int x = mis->X + TileSizeX/2;
|
||||
int y = mis->Y + TileSizeY/2;
|
||||
MakeMissile( missile_explosion, x, y, x, y );
|
||||
|
||||
x = x / TileSizeX;
|
||||
y = y / TileSizeY;
|
||||
|
||||
//Effect of the explosion on units.
|
||||
//NOTE: vladi: this is slightly different than original
|
||||
// now it hits all units in range 1
|
||||
n = SelectUnits(x-1,y-1, x+1, y+1,table);
|
||||
for( i=0; i<n; ++i )
|
||||
HitUnit(table[i],FIREBALL_DAMAGE);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
/*
|
||||
** Death-Coil controller
|
||||
*/
|
||||
global int SpellDeathCoilController( void* missile )
|
||||
{
|
||||
Unit* table[MAX_UNITS];
|
||||
int i;
|
||||
int n;
|
||||
|
||||
Missile* mis = (Missile*)missile;
|
||||
mis->SourceUnit->Refs--;
|
||||
if ( mis->TargetUnit )
|
||||
mis->TargetUnit->Refs--;
|
||||
if ( mis->X == mis->DX && mis->Y == mis->DY )
|
||||
{ // missile has reached target unit/spot
|
||||
if ( !mis->SourceUnit->Destroyed )
|
||||
{ // source unit still exists
|
||||
if ( mis->TargetUnit && !mis->TargetUnit->Destroyed )
|
||||
{ // target unit still exists
|
||||
int hp = mis->TargetUnit->HP;
|
||||
hp -= 50;
|
||||
mis->SourceUnit->HP += 50;
|
||||
if ( hp <= 0 )
|
||||
{
|
||||
mis->TargetUnit->HP = 0;
|
||||
DestroyUnit( mis->TargetUnit );
|
||||
}
|
||||
else
|
||||
mis->TargetUnit->HP = hp;
|
||||
if ( mis->SourceUnit->HP > mis->SourceUnit->Stats->HitPoints )
|
||||
mis->SourceUnit->HP = mis->SourceUnit->Stats->HitPoints;
|
||||
}
|
||||
else
|
||||
{ // no target unit -- try enemies in range 5x5
|
||||
int ec = 0; // enemy count
|
||||
int x = mis->DX / TileSizeX;
|
||||
int y = mis->DY / TileSizeY;
|
||||
n = SelectUnits(x-2,y-2, x+2, y+2,table);
|
||||
if ( n > 0 )
|
||||
{
|
||||
// calculate organic enemy count
|
||||
for( i=0; i<n; ++i )
|
||||
ec += ( IsEnemy(mis->SourceUnit->Player,table[i])
|
||||
&& table[i]->Type->Organic != 0);
|
||||
if ( ec > 0 )
|
||||
{ // yes organic enemies found
|
||||
for( i=0; i<n; ++i )
|
||||
if ( IsEnemy(mis->SourceUnit->Player,table[i])
|
||||
&& table[i]->Type->Organic != 0 )
|
||||
{
|
||||
// disperse dabage between them
|
||||
int hp = table[i]->HP;
|
||||
hp -= 50/ec; //NOTE: 1 is the minimal damage
|
||||
if ( hp <= 0 )
|
||||
{
|
||||
table[i]->HP = 0;
|
||||
DestroyUnit( table[i] ); // too much damage
|
||||
}
|
||||
else
|
||||
table[i]->HP = hp;
|
||||
}
|
||||
mis->SourceUnit->HP += 50;
|
||||
if ( mis->SourceUnit->HP > mis->SourceUnit->Stats->HitPoints )
|
||||
mis->SourceUnit->HP = mis->SourceUnit->Stats->HitPoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Whirlwind controller
|
||||
*/
|
||||
/*
|
||||
FIXME: vladi: whirlwind is particulary bad! :)
|
||||
we need slow smooth missile movement that we don't
|
||||
have yet... should be fixed later
|
||||
*/
|
||||
global int SpellWhirlwindController( void* missile )
|
||||
{
|
||||
Unit* table[MAX_UNITS];
|
||||
int i;
|
||||
int n;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
Missile* mis = (Missile*)missile;
|
||||
x = mis->X / TileSizeX;
|
||||
y = mis->Y / TileSizeY;
|
||||
|
||||
n = SelectUnitsOnTile( x, y, table);
|
||||
for( i=0; i<n; ++i ) {
|
||||
HitUnit(table[i],WHIRLWIND_DAMAGE1);
|
||||
}
|
||||
n = SelectUnits( x - 1, y - 1, x + 1, y + 1, table);
|
||||
for( i=0; i<n; ++i ) {
|
||||
HitUnit(table[i],WHIRLWIND_DAMAGE2);
|
||||
}
|
||||
//printf( "Whirlwind: %d, %d, TTL: %d\n", mis->X, mis->Y, mis->TTL );
|
||||
if ( mis->TTL % 100 == 0 ) // changes direction every 3 seconds (approx.)
|
||||
{ // missile has reached target unit/spot
|
||||
int nx, ny;
|
||||
do
|
||||
{
|
||||
// find new destination in the map
|
||||
nx = x + rand() % 5 - 2;
|
||||
ny = y + rand() % 5 - 2;
|
||||
}
|
||||
while( nx < 0 && ny < 0 && nx >= TheMap.Width && ny >= TheMap.Height );
|
||||
mis->X = mis->DX;
|
||||
mis->Y = mis->DY;
|
||||
mis->DX = nx * TileSizeX + TileSizeX/2;
|
||||
mis->DY = ny * TileSizeY + TileSizeY/2;
|
||||
//printf( "Whirlwind new direction: %d, %d, TTL: %d\n", mis->X, mis->Y, mis->TTL );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Runes controller
|
||||
*/
|
||||
global int SpellRunesController( void* missile )
|
||||
{
|
||||
Unit* table[MAX_UNITS];
|
||||
int i;
|
||||
int n;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
Missile* mis = (Missile*)missile;
|
||||
x = mis->X / TileSizeX;
|
||||
y = mis->Y / TileSizeY;
|
||||
|
||||
n = SelectUnitsOnTile( x, y, table);
|
||||
for( i=0; i<n; ++i ) {
|
||||
if ( table[i]->Type->LandUnit )
|
||||
HitUnit(table[i],RUNE_DAMAGE);
|
||||
}
|
||||
|
||||
if ( mis->TTL % 100 == 0 || mis->TTL == 0 )
|
||||
{ // show rune every 4 seconds (approx.)
|
||||
MakeMissile( missile_rune, mis->X, mis->Y, mis->X, mis->Y );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
** Spells constructor, inits spell id's and sounds
|
||||
**
|
||||
*/
|
||||
global void InitSpells()
|
||||
{
|
||||
int z = 0;
|
||||
while( SpellTypeTable[z].Id != -1 )
|
||||
{
|
||||
SpellTypeTable[z].Id = z;
|
||||
//FIXME: vladi: this won't work 'cos sound init is called after InitSpells()
|
||||
SpellTypeTable[z].SoundId = SoundIdForName(SpellTypeTable[z].SoundIdent);
|
||||
if( SpellTypeTable[z].SoundId == NULL )
|
||||
{
|
||||
DebugLevel0Fn( "cannot get SoundId for `%s'\n", SpellTypeTable[z].SoundIdent ); //FIXME: vladi: some log level func instead of printf?
|
||||
}
|
||||
z++;
|
||||
}
|
||||
SpellTypeCount = z;
|
||||
|
||||
missile_healing = MissileTypeByIdent( "missile-heal-effect" );
|
||||
missile_spell = MissileTypeByIdent( "missile-normal-spell" );
|
||||
missile_exorcism = MissileTypeByIdent( "missile-exorcism" );
|
||||
missile_explosion = MissileTypeByIdent( "missile-explosion" );
|
||||
missile_rune = MissileTypeByIdent( "missile-rune" );
|
||||
}
|
||||
|
||||
/*
|
||||
** Spells destructor (currently does nothing)
|
||||
**
|
||||
*/
|
||||
global void DoneSpells()
|
||||
{
|
||||
// nothing yet
|
||||
}
|
||||
|
||||
/*
|
||||
** Get spell id by ident
|
||||
**
|
||||
** @param Id Spell ident.
|
||||
**
|
||||
** @return spell id (index in spell type table)
|
||||
*/
|
||||
global int SpellIdByIdent( const char* Ident )
|
||||
{
|
||||
int z = 0;
|
||||
while( SpellTypeTable[z].Id != -1 )
|
||||
{
|
||||
if ( strcmp( SpellTypeTable[z].Ident, Ident ) == 0 )
|
||||
return z;
|
||||
z++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Get spell type struct ptr by ident
|
||||
**
|
||||
** @param Id Spell ident.
|
||||
**
|
||||
** @return spell type struct ptr
|
||||
*/
|
||||
global const SpellType* SpellTypeByIdent( const char* Ident )
|
||||
{
|
||||
int z = SpellIdByIdent( Ident );
|
||||
return z != -1 ? &(SpellTypeTable[z]) : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** Get spell type struct ptr by id
|
||||
**
|
||||
** @param Id Spell id (index in the spell type table).
|
||||
**
|
||||
** @return spell type struct ptr
|
||||
*/
|
||||
global const SpellType* SpellTypeById( int Id )
|
||||
{
|
||||
DebugCheck( Id < 0 || Id >= SpellTypeCount );
|
||||
if ( Id < 0 || Id >= SpellTypeCount ) return NULL;
|
||||
return &(SpellTypeTable[ Id ]);
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if unit can cast spell
|
||||
**
|
||||
** @param unit Unit that has to be checked.
|
||||
** @param SpellId Spell id (index in the spell type table).
|
||||
**
|
||||
** @return 0 if unit cannot or 1 (=!0) if unit can cast this spell type
|
||||
global int CanCastSpell( Unit* unit, int SpellId )
|
||||
{
|
||||
const SpellType* spell = SpellTypeById( SpellId );
|
||||
DebugCheck( spell == NULL );
|
||||
if ( !unit->Type->CanCastSpell ) return 0; // NOTE: this must not happen
|
||||
if ( unit->Mana < spell->ManaCost ) return 0;
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
** Spell cast!
|
||||
**
|
||||
** @param SpellId Spell id (index in the spell type table).
|
||||
** @param unit Unit that casts the spell.
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param X X coord of target spot when/if target does not exist
|
||||
** @param Y Y coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return 0 if spell should/can continue or =! 0 to stop
|
||||
**
|
||||
*/
|
||||
global int SpellCast( int SpellId, Unit* unit, Unit* target, int x, int y )
|
||||
{
|
||||
int repeat = 0;
|
||||
const SpellType* spell = SpellTypeById( SpellId );
|
||||
/*
|
||||
this does not work when no target unit
|
||||
DebugLevel0Fn("Spell cast: %d (%s), %s -> %s (%d,%d)",
|
||||
SpellId, spell->Ident, unit->Type->Name, target->Type->Name, x, y );
|
||||
printf("Spell cast: %d (%s), %s -> %s (%d,%d)\n",
|
||||
SpellId, spell->Ident, unit->Type->Name, target->Type->Name, x, y );
|
||||
*/
|
||||
// the unit can collect mana during the move to target, so check is here...
|
||||
|
||||
#define PLAY_FIREWORKS(s) \
|
||||
{ \
|
||||
PlayGameSound(SoundIdForName(spell->SoundIdent),MaxSampleVolume); \
|
||||
MakeMissile( s, x*TileSizeX+TileSizeX/2, \
|
||||
y*TileSizeX+TileSizeX/2, \
|
||||
x*TileSizeX+TileSizeX/2, \
|
||||
y*TileSizeX+TileSizeX/2 ); \
|
||||
}
|
||||
|
||||
switch( spell->Action )
|
||||
{
|
||||
case SpellActionNone:
|
||||
DebugLevel0Fn( "No spell action" );
|
||||
break;
|
||||
// ---human paladins---
|
||||
case SpellActionHolyVision:
|
||||
unit->Mana -= spell->ManaCost; // get mana cost
|
||||
{
|
||||
Unit* u = MakeUnit(UnitTypeByIdent("unit-daemon"), unit->Player);
|
||||
u->Revealer = 1;
|
||||
u->HP = 2;
|
||||
u->X = x;
|
||||
u->Y = y;
|
||||
}
|
||||
break;
|
||||
case SpellActionHealing:
|
||||
// only can heal organic units
|
||||
if (target && target->Type->Organic)
|
||||
{
|
||||
while( target->HP < target->Stats->HitPoints
|
||||
&& unit->Mana > spell->ManaCost )
|
||||
{
|
||||
unit->Mana -= spell->ManaCost; // get mana cost
|
||||
target->HP++;
|
||||
}
|
||||
PLAY_FIREWORKS(missile_healing);
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionExorcism:
|
||||
// exorcism works only on undead units
|
||||
if ( target && target->Type->IsUndead )
|
||||
{
|
||||
while( target->HP > 0 && unit->Mana > spell->ManaCost )
|
||||
{
|
||||
unit->Mana -= spell->ManaCost; // get mana cost
|
||||
target->HP--;
|
||||
}
|
||||
PLAY_FIREWORKS(missile_exorcism);
|
||||
}
|
||||
else
|
||||
{
|
||||
//FIXME: vladi: exorcism effect should be disperced on near units
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
// ---human mages---
|
||||
case SpellActionFireball:
|
||||
{ //NOTE: fireball can be casted on spot
|
||||
Missile* mis;
|
||||
int sx = unit->X;
|
||||
int sy = unit->Y;
|
||||
int dx = x;
|
||||
int dy = y;
|
||||
|
||||
if ( target )
|
||||
{
|
||||
dx = target->X;
|
||||
dy = target->Y;
|
||||
}
|
||||
|
||||
unit->Mana -= spell->ManaCost;
|
||||
|
||||
PlayGameSound(SoundIdForName(spell->SoundIdent),MaxSampleVolume); \
|
||||
mis = MakeMissile( MissileTypeByIdent("missile-fireball"),
|
||||
sx*TileSizeX+TileSizeX/2,
|
||||
sy*TileSizeX+TileSizeX/2,
|
||||
dx*TileSizeX+TileSizeX/2,
|
||||
dy*TileSizeX+TileSizeX/2 );
|
||||
|
||||
mis->TTL = spell->TTL;
|
||||
mis->Controller = SpellFireballController;
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionSlow:
|
||||
if (target && !target->Type->Building && target->Slow < spell->TTL)
|
||||
{
|
||||
// get mana cost
|
||||
unit->Mana -= spell->ManaCost;
|
||||
target->Slow = spell->TTL; // about 25 sec
|
||||
target->Haste = 0;
|
||||
|
||||
PLAY_FIREWORKS(missile_spell);
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionFlameShield:
|
||||
if ( target && target->Type->Organic && target->Type->LandUnit
|
||||
&& target->FlameShield < spell->TTL )
|
||||
{
|
||||
// get mana cost
|
||||
unit->Mana -= spell->ManaCost;
|
||||
target->FlameShield = spell->TTL; // about 15 sec
|
||||
|
||||
PLAY_FIREWORKS(missile_spell);
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionInvisibility:
|
||||
if (target && target->Type->Organic && target->Invisible < spell->TTL )
|
||||
{
|
||||
// get mana cost
|
||||
unit->Mana -= spell->ManaCost;
|
||||
target->Invisible = spell->TTL; // about 50 sec
|
||||
|
||||
PLAY_FIREWORKS(missile_spell);
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionPolymorph:
|
||||
if ( target && target->Type->Organic )
|
||||
{
|
||||
int x = target->X;
|
||||
int y = target->Y;
|
||||
Player* pl = target->Player;
|
||||
|
||||
// as said somewhere else -- no corpses :)
|
||||
RemoveUnit( target );
|
||||
UnitLost( target );
|
||||
ReleaseUnit( target );
|
||||
MakeUnitAndPlace( x, y, UnitTypeByIdent("unit-critter"), pl );
|
||||
|
||||
unit->Mana -= spell->ManaCost;
|
||||
|
||||
PLAY_FIREWORKS(missile_spell);
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionBlizzard:
|
||||
{
|
||||
/*
|
||||
NOTE: vladi: blizzard differs than original in this way:
|
||||
original: launches 50 shards at 5 random spots x 10 for 25 mana
|
||||
here: launches 10 shards at 10 random spots x 1 for 5 mana
|
||||
reason: it cannot be done w/o aditional spells list... perhasp
|
||||
could be managed with fake spell with controller, but
|
||||
for now it is leaved as it is...
|
||||
*/
|
||||
int shards = 10;
|
||||
while( shards-- )
|
||||
{
|
||||
Missile* mis;
|
||||
int sx, sy, dx, dy;
|
||||
|
||||
do
|
||||
{
|
||||
// find new destination in the map
|
||||
dx = x + rand() % 5 - 2;
|
||||
dy = y + rand() % 5 - 2;
|
||||
}
|
||||
while( dx < 0 && dy < 0 && dx >= TheMap.Width && dy >= TheMap.Height );
|
||||
sx = dx - 1 - rand() % 4;
|
||||
sy = dy - 1 - rand() % 4;
|
||||
|
||||
PlayGameSound(SoundIdForName(spell->SoundIdent),MaxSampleVolume); \
|
||||
mis = MakeMissile( MissileTypeByIdent( "missile-blizzard" ),
|
||||
sx*TileSizeX+TileSizeX/2,
|
||||
sy*TileSizeX+TileSizeX/2,
|
||||
dx*TileSizeX+TileSizeX/2,
|
||||
dy*TileSizeX+TileSizeX/2 );
|
||||
mis->Damage = BLIZZARD_DAMAGE;
|
||||
//FIXME: not correct -- blizzard should continue even if mage is
|
||||
// destroyed (though it will be quite short time...)
|
||||
mis->SourceUnit = unit;
|
||||
mis->SourceType = unit->Type;
|
||||
}
|
||||
|
||||
unit->Mana -= spell->ManaCost;
|
||||
if ( unit->Mana > spell->ManaCost )
|
||||
repeat = 1;
|
||||
}
|
||||
break;
|
||||
// ---orc ogres---
|
||||
case SpellActionEyeOfKilrogg:
|
||||
MakeUnitAndPlace( x, y, UnitTypeByIdent("unit-eye-of-kilrogg"),
|
||||
unit->Player );
|
||||
|
||||
unit->Mana -= spell->ManaCost;
|
||||
|
||||
PLAY_FIREWORKS(missile_spell);
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionBloodlust:
|
||||
if (target && target->Type->Organic && target->Bloodlust < spell->TTL )
|
||||
{
|
||||
// get mana cost
|
||||
unit->Mana -= spell->ManaCost;
|
||||
target->Bloodlust = spell->TTL; // about 25 sec
|
||||
|
||||
PLAY_FIREWORKS(missile_spell);
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionRunes:
|
||||
{
|
||||
//FIXME: vladi: runes should be set in formation as in original
|
||||
//FIXME: vladi: runes should be set on empty tile (ground or water)
|
||||
Missile* mis;
|
||||
unit->Mana -= spell->ManaCost;
|
||||
PlayGameSound(SoundIdForName(spell->SoundIdent),MaxSampleVolume); \
|
||||
mis = MakeMissile( MissileTypeByIdent( "missile-custom" ),
|
||||
x*TileSizeX+TileSizeX/2,
|
||||
y*TileSizeX+TileSizeX/2,
|
||||
x*TileSizeX+TileSizeX/2,
|
||||
y*TileSizeX+TileSizeX/2 );
|
||||
mis->TTL = spell->TTL;
|
||||
mis->Controller = SpellRunesController;
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
// ---orc death knights---
|
||||
case SpellActionDeathCoil:
|
||||
if( (target && target->Type->Organic) || (!target) )
|
||||
{ //NOTE: fireball can be casted on spot
|
||||
Missile* mis;
|
||||
int sx = unit->X;
|
||||
int sy = unit->Y;
|
||||
int dx = x;
|
||||
int dy = y;
|
||||
|
||||
if ( target )
|
||||
{
|
||||
dx = target->X;
|
||||
dy = target->Y;
|
||||
}
|
||||
|
||||
unit->Mana -= spell->ManaCost;
|
||||
|
||||
PlayGameSound(SoundIdForName(spell->SoundIdent),MaxSampleVolume); \
|
||||
mis = MakeMissile( MissileTypeByIdent("missile-death-coil"),
|
||||
sx*TileSizeX+TileSizeX/2,
|
||||
sy*TileSizeX+TileSizeX/2,
|
||||
dx*TileSizeX+TileSizeX/2,
|
||||
dy*TileSizeX+TileSizeX/2 );
|
||||
|
||||
unit->Refs++;
|
||||
mis->SourceUnit = unit;
|
||||
if (target)
|
||||
{
|
||||
mis->TargetUnit = target;
|
||||
target->Refs++;
|
||||
}
|
||||
mis->Controller = SpellDeathCoilController;
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionHaste:
|
||||
if (target && !target->Type->Building && target->Haste < spell->TTL)
|
||||
{
|
||||
// get mana cost
|
||||
unit->Mana -= spell->ManaCost;
|
||||
target->Slow = 0;
|
||||
target->Haste = spell->TTL; // about 25 sec
|
||||
|
||||
PLAY_FIREWORKS(missile_spell);
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionRaiseDead:
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i=0; i<NumUnits; ++i ) {
|
||||
// FIXME: this tries to draw all corps, ohje
|
||||
if( (Units[i]->Type->Vanishes || Units[i]->Command.Action==UnitActionDie)
|
||||
&& Units[i]->X == x && Units[i]->Y == y ) {
|
||||
//FIXME: URGENT: remove corpse
|
||||
//RemoveUnit( Units[i] );
|
||||
//UnitLost( Units[i] );
|
||||
//ReleaseUnit( Units[i] );
|
||||
MakeUnitAndPlace( x, y, UnitTypeByIdent("unit-skeleton"),
|
||||
unit->Player );
|
||||
unit->Mana -= spell->ManaCost;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PLAY_FIREWORKS(missile_spell);
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionWhirlwind:
|
||||
{
|
||||
Missile* mis;
|
||||
unit->Mana -= spell->ManaCost;
|
||||
|
||||
PlayGameSound(SoundIdForName(spell->SoundIdent),MaxSampleVolume); \
|
||||
mis = MakeMissile( MissileTypeByIdent("missile-whirlwind"),
|
||||
x*TileSizeX+TileSizeX/2,
|
||||
y*TileSizeX+TileSizeX/2,
|
||||
x*TileSizeX+TileSizeX/2,
|
||||
y*TileSizeX+TileSizeX/2 );
|
||||
|
||||
mis->TTL = spell->TTL;
|
||||
mis->Controller = SpellWhirlwindController;
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionUnholyArmor:
|
||||
if (target && !target->Type->Building && target->UnholyArmor < spell->TTL)
|
||||
{
|
||||
// get mana cost
|
||||
unit->Mana -= spell->ManaCost;
|
||||
target->UnholyArmor = spell->TTL; // about 13 sec
|
||||
|
||||
PLAY_FIREWORKS(missile_spell);
|
||||
}
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
break;
|
||||
case SpellActionDeathAndDecay:
|
||||
{
|
||||
/*
|
||||
See notes about Blizzard spell above...
|
||||
*/
|
||||
int shards = 10; // blizzard thing, yep :)
|
||||
while( shards-- )
|
||||
{
|
||||
Missile* mis;
|
||||
int dx, dy;
|
||||
|
||||
do
|
||||
{
|
||||
// find new destination in the map
|
||||
dx = x + rand() % 5 - 2;
|
||||
dy = y + rand() % 5 - 2;
|
||||
}
|
||||
while( dx < 0 && dy < 0 && dx >= TheMap.Width && dy >= TheMap.Height );
|
||||
|
||||
PlayGameSound(SoundIdForName(spell->SoundIdent),MaxSampleVolume); \
|
||||
mis = MakeMissile( MissileTypeByIdent( "missile-death-and-decay" ),
|
||||
dx*TileSizeX+TileSizeX/2,
|
||||
dy*TileSizeX+TileSizeX/2,
|
||||
dx*TileSizeX+TileSizeX/2,
|
||||
dy*TileSizeX+TileSizeX/2 );
|
||||
mis->Damage = DEATHANDDECAY_DAMAGE;
|
||||
//FIXME: not correct -- blizzard should continue even if mage is
|
||||
// destroyed (though it will be quite short time...)
|
||||
mis->SourceUnit = unit;
|
||||
mis->SourceType = unit->Type;
|
||||
}
|
||||
|
||||
unit->Mana -= spell->ManaCost;
|
||||
if ( unit->Mana > spell->ManaCost )
|
||||
repeat = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DebugLevel0Fn( "Unknown spell action" );
|
||||
break;
|
||||
}
|
||||
#undef PLAY_FIREWORKS
|
||||
DebugCheck( unit->Mana < 0 );
|
||||
return repeat;
|
||||
}
|
||||
|
||||
|
||||
//@}
|
||||
|
|
@ -71,6 +71,7 @@ extern int getopt(int argc, char *const*argv, const char *opt);
|
|||
#include "sound.h"
|
||||
#include "network.h"
|
||||
#include "pathfinder.h"
|
||||
#include "spells.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Variables
|
||||
|
@ -204,6 +205,7 @@ global void FreeCraftInit(void)
|
|||
LoadTileset();
|
||||
InitUnitButtons();
|
||||
LoadMissileSprites();
|
||||
InitSpells();
|
||||
LoadUnitSprites();
|
||||
LoadConstructions();
|
||||
LoadDecorations();
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "map.h"
|
||||
#include "unit.h"
|
||||
#include "font.h"
|
||||
#include "spells.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Defines
|
||||
|
@ -142,12 +143,12 @@ int AddButton( int pos, int level, const char* IconIdent,
|
|||
ba->ValueStr = strdup( value );
|
||||
switch( action )
|
||||
{
|
||||
case B_Magic: ba->Value = UpgradeIdByIdent( value ); break;
|
||||
case B_Train: ba->Value = UnitTypeIdByIdent( value ); break;
|
||||
case B_Research: ba->Value = UpgradeIdByIdent( value ); break;
|
||||
case B_UpgradeTo: ba->Value = UnitTypeIdByIdent( value ); break;
|
||||
case B_Build: ba->Value = UnitTypeIdByIdent( value ); break;
|
||||
default: ba->Value = atoi( value ); break;
|
||||
case B_SpellCast: ba->Value = SpellIdByIdent( value ); break;
|
||||
case B_Train: ba->Value = UnitTypeIdByIdent( value ); break;
|
||||
case B_Research: ba->Value = UpgradeIdByIdent( value ); break;
|
||||
case B_UpgradeTo: ba->Value = UnitTypeIdByIdent( value ); break;
|
||||
case B_Build: ba->Value = UnitTypeIdByIdent( value ); break;
|
||||
default: ba->Value = atoi( value ); break;
|
||||
}
|
||||
} else {
|
||||
ba->ValueStr = NULL;
|
||||
|
@ -297,9 +298,11 @@ global void DrawButtonPanel(void)
|
|||
case B_Research:
|
||||
SetCosts(0,Upgrades[v].Costs);
|
||||
break;
|
||||
case B_Magic:
|
||||
// FIXME: correct costs!!!
|
||||
SetCosts(11,NULL);
|
||||
case B_SpellCast:
|
||||
{
|
||||
const SpellType* spell = SpellTypeById( v );
|
||||
SetCosts(spell->ManaCost,NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -521,7 +524,7 @@ global void UpdateButtonPanel(void)
|
|||
allow=UpgradeIdentAllowed( ThisPlayer,
|
||||
UnitButtonTable[z]->ValueStr )=='A';
|
||||
}
|
||||
} else if ( UnitButtonTable[z]->Action == B_Magic ) {
|
||||
} else if ( UnitButtonTable[z]->Action == B_SpellCast ) {
|
||||
DebugLevel3("Magic: %d,%c\n",
|
||||
CheckDependByIdent( ThisPlayer,
|
||||
UnitButtonTable[z]->ValueStr ),
|
||||
|
@ -600,9 +603,11 @@ global void DoButtonButtonClicked(int button)
|
|||
case B_Repair:
|
||||
case B_AttackGround:
|
||||
case B_Demolish:
|
||||
case B_SpellCast:
|
||||
CursorState=CursorStateSelect;
|
||||
GameCursor=&Cursors[CursorTypeYellowHair];
|
||||
CursorAction=CurrentButtons[button].Action;
|
||||
CursorValue=CurrentButtons[button].Value;
|
||||
CurrentButtonLevel=9; // level 9 is cancel-only
|
||||
UpdateButtonPanel();
|
||||
MustRedraw|=RedrawCursor;
|
||||
|
|
|
@ -353,20 +353,20 @@ global ButtonAction AllButtons[] = {
|
|||
|
||||
// paladin specific actions --------------------------------------------
|
||||
{ 7, 0, { "icon-holy-vision" },
|
||||
B_Magic, 0, "upgrade-holy-vision",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-holy-vision",
|
||||
CheckTrue, NULL,
|
||||
'v', "HOLY ~!VISION",
|
||||
"unit-paladin"
|
||||
},
|
||||
{ 8, 0, { "icon-heal" },
|
||||
B_Magic, 0, "upgrade-healing",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-healing",
|
||||
CheckUpgrade, "upgrade-healing",
|
||||
'h', "~!HEALING (per 1 HP)",
|
||||
"unit-paladin"
|
||||
},
|
||||
{ 9, 0, { "icon-exorcism" },
|
||||
B_Magic, 0, "upgrade-exorcism",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-exorcism",
|
||||
CheckUpgrade, "upgrade-exorcism",
|
||||
'e', "~!EXORCISM",
|
||||
"unit-paladin"
|
||||
},
|
||||
|
@ -378,38 +378,38 @@ global ButtonAction AllButtons[] = {
|
|||
"unit-mage,unit-khadgar"
|
||||
},
|
||||
{ 4, 0, { "icon-fireball" },
|
||||
B_Magic, 0, "upgrade-fireball",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-fireball",
|
||||
CheckTrue, NULL,
|
||||
'f', "~!FIREBALL",
|
||||
"unit-mage,unit-khadgar"
|
||||
},
|
||||
{ 5, 0, { "icon-slow" },
|
||||
B_Magic, 0, "upgrade-slow",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-slow",
|
||||
CheckUpgrade, "upgrade-slow",
|
||||
'o', "SL~!OW",
|
||||
"unit-mage"
|
||||
},
|
||||
{ 6, 0, { "icon-flame-shield" },
|
||||
B_Magic, 0, "upgrade-flame-shield",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-flame-shield",
|
||||
CheckUpgrade, "upgrade-flame-shield",
|
||||
'l', "F~!LAME SHIELD",
|
||||
"unit-mage"
|
||||
},
|
||||
{ 7, 0, { "icon-invisibility" },
|
||||
B_Magic, 0, "upgrade-invisibility",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-invisibility",
|
||||
CheckUpgrade, "upgrade-invisibility",
|
||||
'i', "~!INVISIBILITY",
|
||||
"unit-mage"
|
||||
},
|
||||
{ 8, 0, { "icon-polymorph" },
|
||||
B_Magic, 0, "upgrade-polymorph",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-polymorph",
|
||||
CheckUpgrade, "upgrade-polymorph",
|
||||
'p', "~!POLYMORPH",
|
||||
"unit-mage"
|
||||
},
|
||||
{ 9, 0, { "icon-blizzard" },
|
||||
B_Magic, 0, "upgrade-blizzard",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-blizzard",
|
||||
CheckUpgrade, "upgrade-blizzard",
|
||||
'b', "~!BLIZZARD",
|
||||
"unit-mage"
|
||||
},
|
||||
|
@ -1080,37 +1080,38 @@ global ButtonAction AllButtons[] = {
|
|||
|
||||
// ogre-mage specific actions --------------------------------------------
|
||||
{ 7, 0, { "icon-eye-of-kilrogg" },
|
||||
B_Magic, 0, "upgrade-eye-of-kilrogg",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-eye-of-kilrogg",
|
||||
CheckTrue, NULL,
|
||||
'k', "EYE OF ~!KILROGG",
|
||||
"unit-ogre-mage"
|
||||
},
|
||||
{ 8, 0, { "icon-bloodlust" },
|
||||
B_Magic, 0, "upgrade-bloodlust",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-bloodlust",
|
||||
CheckUpgrade, "upgrade-bloodlust",
|
||||
'b', "~!BLOODLUST",
|
||||
"unit-ogre-mage"
|
||||
},
|
||||
{ 9, 0, { "icon-runes" },
|
||||
B_Magic, 0, "upgrade-runes",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-runes",
|
||||
CheckTrue, "upgrade-runes",
|
||||
'r', "~!RUNES",
|
||||
"unit-ogre-mage"
|
||||
},
|
||||
// cho'gall specific actions --- same as ogre mage but it has them always --
|
||||
{ 7, 0, { "icon-eye-of-kilrogg" },
|
||||
B_Magic, 0, "upgrade-eye-of-kilrogg",
|
||||
B_SpellCast, 0, "spell-eye-of-kilrogg",
|
||||
CheckTrue, NULL,
|
||||
'k', "EYE OF ~!KILROGG",
|
||||
"unit-cho'gall"
|
||||
},
|
||||
{ 8, 0, { "icon-bloodlust" },
|
||||
B_Magic, 0, "upgrade-bloodlust",
|
||||
B_SpellCast, 0, "spell-bloodlust",
|
||||
CheckTrue, NULL,
|
||||
'b', "~!BLOODLUST",
|
||||
"unit-cho'gall"
|
||||
},
|
||||
{ 9, 0, { "icon-runes" },
|
||||
B_Magic, 0, "upgrade-runes",
|
||||
B_SpellCast, 0, "spell-runes",
|
||||
CheckTrue, NULL,
|
||||
'r', "~!RUNES",
|
||||
"unit-cho'gall"
|
||||
|
@ -1123,38 +1124,38 @@ global ButtonAction AllButtons[] = {
|
|||
"unit-death-knight" ",unit-gul'dan" ",unit-teron-gorefiend"
|
||||
},
|
||||
{ 4, 0, { "icon-death-coil" },
|
||||
B_Magic, 0, "upgrade-death-coil",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-death-coil",
|
||||
CheckTrue, NULL,
|
||||
'c', "DEATH ~!COIL",
|
||||
"unit-death-knight" ",unit-gul'dan" ",unit-teron-gorefiend"
|
||||
},
|
||||
{ 5, 0, { "icon-haste" },
|
||||
B_Magic, 0, "upgrade-haste",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-haste",
|
||||
CheckUpgrade, "upgrade-haste",
|
||||
'h', "~!HASTE",
|
||||
"unit-death-knight"
|
||||
},
|
||||
{ 6, 0, { "icon-raise-dead" },
|
||||
B_Magic, 0, "upgrade-raise-dead",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-raise-dead",
|
||||
CheckUpgrade, "upgrade-raise-dead",
|
||||
'r', "~!RAISE DEAD",
|
||||
"unit-death-knight"
|
||||
},
|
||||
{ 7, 0, { "icon-whirlwind" },
|
||||
B_Magic, 0, "upgrade-whirlwind",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-whirlwind",
|
||||
CheckUpgrade, "upgrade-whirlwind",
|
||||
'w', "~!WHIRLWIND",
|
||||
"unit-death-knight"
|
||||
},
|
||||
{ 8, 0, { "icon-unholy-armor" },
|
||||
B_Magic, 0, "upgrade-unholy-armor",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-unholy-armor",
|
||||
CheckUpgrade, "upgrade-unholy-armor",
|
||||
'u', "~!UNHOLY ARMOR",
|
||||
"unit-death-knight"
|
||||
},
|
||||
{ 9, 0, { "icon-death-and-decay" },
|
||||
B_Magic, 0, "upgrade-death-and-decay",
|
||||
NULL, NULL,
|
||||
B_SpellCast, 0, "spell-death-and-decay",
|
||||
CheckUpgrade, "upgrade-death-and-decay",
|
||||
'd', "~!DEATH AND DECAY",
|
||||
"unit-death-knight"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// ___________ _________ _____ __
|
||||
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
|
||||
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
||||
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
||||
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
|
||||
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
|
||||
// \/ \/ \/ \/ \/
|
||||
|
@ -513,7 +513,7 @@ global void ShiftMessages(void)
|
|||
{
|
||||
strcpy( Messages[z], "" );
|
||||
}
|
||||
MessagesCount--;
|
||||
MessagesCount--;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -534,7 +534,7 @@ global void ShiftMessagesEvent(void)
|
|||
MessagesEventX[z] = -1;
|
||||
MessagesEventY[z] = -1;
|
||||
}
|
||||
MessagesCount--;
|
||||
MessagesCount--;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -571,7 +571,7 @@ global void SetMessage( char* fmt, ... )
|
|||
va_end( va );
|
||||
if ( MessagesCount == MESSAGES_MAX )
|
||||
ShiftMessages();
|
||||
strcpy( Messages[ MessagesCount ], temp );
|
||||
strcpy( Messages[ MessagesCount ], temp );
|
||||
MessagesCount++;
|
||||
MustRedraw|=RedrawMessage|RedrawMap;
|
||||
MessageFrameTimeout = FrameCounter + MESSAGES_TIMEOUT;
|
||||
|
@ -596,16 +596,16 @@ global void SetMessage2( int x, int y, char* fmt, ... )
|
|||
va_end( va );
|
||||
if ( MessagesCount == MESSAGES_MAX )
|
||||
ShiftMessages();
|
||||
strcpy( Messages[ MessagesCount ], temp );
|
||||
strcpy( Messages[ MessagesCount ], temp );
|
||||
MessagesCount++;
|
||||
|
||||
|
||||
if ( MessagesEventCount == MESSAGES_MAX )
|
||||
ShiftMessagesEvent();
|
||||
strcpy( MessagesEvent[ MessagesEventCount ], temp );
|
||||
MessagesEventX[ MessagesEventCount ] = x;
|
||||
MessagesEventY[ MessagesEventCount ] = y;
|
||||
MessagesEventCount++;
|
||||
|
||||
|
||||
MustRedraw|=RedrawMessage|RedrawMap;
|
||||
MessageFrameTimeout = FrameCounter + MESSAGES_TIMEOUT;
|
||||
}
|
||||
|
@ -664,8 +664,8 @@ global void CenterOnMessage(void)
|
|||
MessagesEventIndex = 0;
|
||||
if ( MessagesEventIndex >= MessagesEventCount )
|
||||
return;
|
||||
MapCenter( MessagesEventX[ MessagesEventIndex ],
|
||||
MessagesEventY[ MessagesEventIndex ] );
|
||||
MapCenter( MessagesEventX[ MessagesEventIndex ],
|
||||
MessagesEventY[ MessagesEventIndex ] );
|
||||
SetMessage( "*Event: %s", MessagesEvent[ MessagesEventIndex ] );
|
||||
MessagesEventIndex++;
|
||||
}
|
||||
|
|
|
@ -771,6 +771,43 @@ local void SendUnload(int x,int y)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Send the current selected group for spell cast.
|
||||
**
|
||||
** To empty field:
|
||||
** To unit:
|
||||
** Spell cast on unit or on map spot.
|
||||
**
|
||||
** @param x X map tile position.
|
||||
** @param y Y map tile position.
|
||||
**
|
||||
** @see Selected, @see NumSelected
|
||||
*/
|
||||
local void SendSpellCast(int x,int y)
|
||||
{
|
||||
int i;
|
||||
Unit* unit;
|
||||
Unit* dest;
|
||||
|
||||
dest=UnitOnMapTile(x,y);
|
||||
DebugLevel3Fn("SpellCast on: %p (%d,%d)\n", dest, x, y);
|
||||
/* NOTE: Vladi:
|
||||
This is a high-level function, it sends target spot and unit
|
||||
(if exists). All checks are performed at spell cast handle
|
||||
function which will cancel function if cannot be executed
|
||||
*/
|
||||
for( i=0; i<NumSelected; i++ ) {
|
||||
unit=Selected[i];
|
||||
if( !unit->Type->CanCastSpell )
|
||||
continue; // this unit cannot cast spell
|
||||
if( dest && unit == dest )
|
||||
continue; // no unit can cast spell on himself
|
||||
// CursorValue here holds the spell type id
|
||||
SendCommandSpellCast(unit,x,y,dest,CursorValue,!(KeyModifiers&ModifierShift));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** Send a command to selected units.
|
||||
**
|
||||
|
@ -808,6 +845,9 @@ local void SendCommand(int x,int y)
|
|||
case B_Demolish:
|
||||
SendDemolish(x,y);
|
||||
break;
|
||||
case B_SpellCast:
|
||||
SendSpellCast(x,y);
|
||||
break;
|
||||
default:
|
||||
DebugLevel1("Unsupported send action %d\n",CursorAction);
|
||||
break;
|
||||
|
|
|
@ -271,6 +271,7 @@ global Unit* MakeUnit(UnitType* type,Player* player)
|
|||
unit->Reset=1;
|
||||
|
||||
unit->Rs=MyRand()%100; // used for random fancy buildings and other things
|
||||
unit->Revealer = 0; // FOW revealer
|
||||
|
||||
unit->Command.Action=UnitActionStill;
|
||||
unit->PendCommand.Action=UnitActionStill;
|
||||
|
@ -735,6 +736,9 @@ global int UnitVisible(const Unit* unit)
|
|||
**
|
||||
** NOTE: we could build a table of all magic units reducing cpu use.
|
||||
*/
|
||||
//FIXME: vladi: the doc says incrementing mana is done by 1 per second
|
||||
// the spells effect can be decremented at the same time and this
|
||||
// will reduse calls to this function to one time per second only!
|
||||
global void UnitIncrementMana(void)
|
||||
{
|
||||
Unit** table;
|
||||
|
@ -758,6 +762,20 @@ global void UnitIncrementMana(void)
|
|||
MustRedraw|=RedrawInfoPanel;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// decrease spells effects time
|
||||
//
|
||||
if ( unit->Bloodlust > 0 )
|
||||
unit->Bloodlust--;
|
||||
if ( unit->Haste > 0 )
|
||||
unit->Haste--;
|
||||
if ( unit->Slow > 0 )
|
||||
unit->Slow--;
|
||||
if ( unit->Invisible > 0 )
|
||||
unit->Invisible--;
|
||||
if ( unit->UnholyArmor > 0 )
|
||||
unit->UnholyArmor--;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2018,7 +2036,9 @@ global void DestroyUnit(Unit* unit)
|
|||
|
||||
// FIXME: units in transporters should die without corpes...
|
||||
if( unit->Type->Transporter ) { // Transporters loose their units
|
||||
DestroyAllInside(unit);
|
||||
//FIXME: vladi: it could be usefull if transport is near land
|
||||
// to unload instead of destroying all units in it... ?
|
||||
DestroyAllInside(unit);
|
||||
}
|
||||
|
||||
RemoveUnit(unit);
|
||||
|
@ -2578,12 +2598,13 @@ global void SaveUnit(const Unit* unit,FILE* file)
|
|||
fprintf(file,"\t%d ",unit->Player->Player);
|
||||
fprintf(file,"%d ",unit->Mana);
|
||||
fprintf(file,"%d ",unit->HP);
|
||||
fprintf(file,"(%d %d %d %d %d)\n"
|
||||
fprintf(file,"(%d %d %d %d %d %d)\n"
|
||||
,unit->Bloodlust
|
||||
,unit->Haste
|
||||
,unit->Slow
|
||||
,unit->Invisible
|
||||
,unit->Shield);
|
||||
,unit->FlameShield
|
||||
,unit->UnholyArmor);
|
||||
fprintf(file,"\t%d ",unit->GroupId);
|
||||
fprintf(file,"%d\n",unit->Value);
|
||||
|
||||
|
|
|
@ -60,10 +60,6 @@ global int ShowHealthHorizontal=1;
|
|||
global int ShowManaHorizontal=1;
|
||||
/// Flag: show bars and dot energy only for selected
|
||||
global int ShowEnergySelectedOnly;
|
||||
/// Flag: show health bar always full sized
|
||||
global int ShowFullSizedHealthBar=1;
|
||||
/// Flag: show mana bar always full sized
|
||||
global int ShowFullSizedManaBar=1;
|
||||
|
||||
// FIXME: not all variables of this file are here
|
||||
// FIXME: perhaps split this file into two?
|
||||
|
@ -277,6 +273,11 @@ global Decoration ShadowSprite = {
|
|||
"graphic/unit shadow.png", 0,42, 32,32
|
||||
};
|
||||
|
||||
/**
|
||||
** Sprite to display the active spells on units.
|
||||
*/
|
||||
global Graphic* SpellSprites;
|
||||
|
||||
#if defined(USE_CCL) || defined(USE_CCL2)
|
||||
|
||||
/**
|
||||
|
@ -334,6 +335,7 @@ global void LoadDecorations(void)
|
|||
,ManaSprite.Width,ManaSprite.Height);
|
||||
ShadowSprite.Sprite=LoadSprite(ShadowSprite.File
|
||||
,ShadowSprite.Width,ShadowSprite.Height);
|
||||
SpellSprites=LoadSprite("graphic/bloodlust,haste,slow,invis.,shield.png",16,16);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -348,8 +350,6 @@ local void DrawDecoration(Unit* unit,const UnitType* type,int x,int y)
|
|||
{
|
||||
int f;
|
||||
int color;
|
||||
int deco_x;
|
||||
int deco_y;
|
||||
UnitStats* stats;
|
||||
|
||||
|
||||
|
@ -360,13 +360,11 @@ local void DrawDecoration(Unit* unit,const UnitType* type,int x,int y)
|
|||
return;
|
||||
}
|
||||
|
||||
// FIXME: Should split this into small functions?
|
||||
|
||||
//
|
||||
// Health bar of the unit.
|
||||
// Health bar on left side of unit.
|
||||
//
|
||||
stats=unit->Stats;
|
||||
if( ShowHealthBar ) {
|
||||
if( !type->Critter && ShowHealthBar ) {
|
||||
if( stats->HitPoints
|
||||
&& !(ShowNoFull && unit->HP==stats->HitPoints) ) {
|
||||
f=(100*unit->HP)/stats->HitPoints;
|
||||
|
@ -377,31 +375,26 @@ local void DrawDecoration(Unit* unit,const UnitType* type,int x,int y)
|
|||
} else {
|
||||
color=ColorRed;
|
||||
}
|
||||
if( ShowHealthHorizontal ) {
|
||||
deco_x=x+((type->TileWidth*TileSizeX-type->BoxWidth)/2)-1;
|
||||
deco_y=y+(type->TileHeight*TileSizeY-type->BoxHeight)/2
|
||||
+type->BoxHeight;
|
||||
if( !ShowFullSizedHealthBar ) {
|
||||
if ( ShowHealthHorizontal == 0) {
|
||||
VideoFillRectangleClip(color
|
||||
,x+(type->TileWidth*TileSizeX
|
||||
-type->BoxWidth)/2
|
||||
,y+(type->TileHeight*TileSizeY
|
||||
-type->BoxHeight)/2
|
||||
,2,(f*type->BoxHeight)/100);
|
||||
} else {
|
||||
VideoFillRectangleClip(ColorBlack
|
||||
,deco_x,deco_y,type->BoxWidth+2,4);
|
||||
} else {
|
||||
VideoDrawRectangleClip(ColorBlack
|
||||
,deco_x,deco_y,(f*type->BoxWidth)/100+1,3);
|
||||
}
|
||||
VideoFillRectangleClip(color
|
||||
,deco_x+1,deco_y+1,(f*type->BoxWidth)/100,2);
|
||||
} else {
|
||||
deco_x=x+(type->TileWidth*TileSizeX-type->BoxWidth)/2-3;
|
||||
deco_y=y+(type->TileHeight*TileSizeY-type->BoxHeight)/2;
|
||||
if( ShowFullSizedHealthBar ) {
|
||||
VideoFillRectangleClip(ColorBlack
|
||||
,deco_x,deco_y,4,type->BoxHeight+1);
|
||||
} else {
|
||||
VideoDrawRectangleClip(ColorBlack
|
||||
,deco_x,deco_y,3,(f*type->BoxHeight)/100);
|
||||
}
|
||||
VideoFillRectangleClip(color
|
||||
,deco_x+1,deco_y+1,2,(f*type->BoxHeight)/100-1);
|
||||
,x+((type->TileWidth*TileSizeX-type->BoxWidth)/2)-1
|
||||
,(y+(type->TileHeight*TileSizeY-type->BoxHeight)/2)
|
||||
+type->BoxHeight+1
|
||||
,((f*type->BoxHeight)/100)+2
|
||||
,5);
|
||||
VideoFillRectangleClip(color
|
||||
,x+((type->TileWidth*TileSizeX-type->BoxWidth)/2)
|
||||
,(y+(type->TileHeight*TileSizeY-type->BoxHeight)/2)
|
||||
+type->BoxHeight+2
|
||||
,(f*type->BoxHeight)/100
|
||||
,3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -409,9 +402,11 @@ local void DrawDecoration(Unit* unit,const UnitType* type,int x,int y)
|
|||
//
|
||||
// Health dot on left side of unit.
|
||||
//
|
||||
if( ShowHealthDot ) {
|
||||
if( !type->Critter && ShowHealthDot ) {
|
||||
if( stats->HitPoints
|
||||
&& !(ShowNoFull && unit->HP==stats->HitPoints) ) {
|
||||
int x1;
|
||||
int y1;
|
||||
int n;
|
||||
|
||||
f=(100*unit->HP)/stats->HitPoints;
|
||||
|
@ -426,61 +421,55 @@ local void DrawDecoration(Unit* unit,const UnitType* type,int x,int y)
|
|||
}
|
||||
DebugCheck( n<0 );
|
||||
if( HealthSprite.HotX<0 ) {
|
||||
deco_x=x+HealthSprite.HotX
|
||||
x1=x+HealthSprite.HotX
|
||||
+(type->TileWidth*TileSizeX
|
||||
+type->BoxWidth+1)/2;
|
||||
} else {
|
||||
deco_x=x-HealthSprite.HotX
|
||||
x1=x-HealthSprite.HotX
|
||||
+(type->TileWidth*TileSizeX
|
||||
-type->BoxWidth+1)/2;
|
||||
}
|
||||
if( HealthSprite.HotY<0 ) {
|
||||
deco_y=y+HealthSprite.HotY
|
||||
y1=y+HealthSprite.HotY
|
||||
+(type->TileHeight*TileSizeY
|
||||
+type->BoxHeight+1)/2;
|
||||
} else {
|
||||
deco_y=y-HealthSprite.HotY
|
||||
y1=y-HealthSprite.HotY
|
||||
+(type->TileHeight*TileSizeY
|
||||
-type->BoxHeight+1)/2;
|
||||
}
|
||||
VideoDrawClip(HealthSprite.Sprite,n,deco_x,deco_y);
|
||||
VideoDrawClip(HealthSprite.Sprite,n,x1,y1);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Mana bar for the unit.
|
||||
// Mana bar on right side of unit.
|
||||
//
|
||||
if( ShowManaBar ) {
|
||||
if( type->CanCastSpell
|
||||
&& !(ShowNoFull && unit->Mana==255) ) {
|
||||
if( ShowManaHorizontal ) {
|
||||
f=(100*unit->Mana)/255;
|
||||
deco_x=x+((type->TileWidth*TileSizeX-type->BoxWidth)/2)-1;
|
||||
deco_y=y+(type->TileHeight*TileSizeY-type->BoxHeight)/2
|
||||
+type->BoxHeight+4;
|
||||
if( ShowFullSizedManaBar ) {
|
||||
VideoFillRectangleClip(ColorBlack
|
||||
,deco_x,deco_y,type->BoxHeight+2,4);
|
||||
} else {
|
||||
VideoDrawRectangleClip(ColorBlack
|
||||
,deco_x,deco_y,(f*type->BoxHeight)/100+1,3);
|
||||
}
|
||||
VideoFillRectangleClip(ColorBlue
|
||||
,deco_x+1,deco_y+1,(f*type->BoxHeight)/100,2);
|
||||
} else {
|
||||
deco_x=x+(type->TileWidth*TileSizeX+type->BoxWidth)/2;
|
||||
deco_y=y+(type->TileHeight*TileSizeY-type->BoxHeight)/2;
|
||||
if ( ShowManaHorizontal == 0) {
|
||||
f=(100*unit->Mana)/255;
|
||||
if( ShowFullSizedManaBar ) {
|
||||
VideoFillRectangleClip(ColorBlue
|
||||
,x+(type->TileWidth*TileSizeX
|
||||
+type->BoxWidth)/2
|
||||
,y+(type->TileHeight*TileSizeY
|
||||
-type->BoxHeight)/2
|
||||
,2,(f*type->BoxHeight)/100);
|
||||
} else {
|
||||
f=(100*unit->Mana)/255;
|
||||
VideoFillRectangleClip(ColorBlack
|
||||
,deco_x,deco_y,4,type->BoxHeight+1);
|
||||
} else {
|
||||
VideoDrawRectangleClip(ColorBlack
|
||||
,deco_x,deco_y,3,(f*type->BoxHeight)/100);
|
||||
}
|
||||
VideoFillRectangleClip(ColorBlue
|
||||
,deco_x+1,deco_y+1,2,(f*type->BoxHeight)/100-1);
|
||||
,x+((type->TileWidth*TileSizeX-type->BoxWidth)/2)-1
|
||||
,(y+(type->TileHeight*TileSizeY-type->BoxHeight)/2)+type->BoxHeight+6
|
||||
,(type->BoxHeight)+2
|
||||
,5);
|
||||
VideoFillRectangleClip(ColorBlue
|
||||
,x+(type->TileWidth*TileSizeX-type->BoxWidth)/2
|
||||
,(y+(type->TileHeight*TileSizeY-type->BoxHeight)/2)+type->BoxHeight+7
|
||||
,(f*type->BoxHeight)/100
|
||||
,3);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,6 +479,8 @@ local void DrawDecoration(Unit* unit,const UnitType* type,int x,int y)
|
|||
if( ShowManaDot ) {
|
||||
if( type->CanCastSpell
|
||||
&& !(ShowNoFull && unit->Mana==255) ) {
|
||||
int x1;
|
||||
int y1;
|
||||
int n;
|
||||
|
||||
f=(100*unit->Mana)/255;
|
||||
|
@ -507,27 +498,41 @@ local void DrawDecoration(Unit* unit,const UnitType* type,int x,int y)
|
|||
n=4;
|
||||
}
|
||||
if( ManaSprite.HotX<0 ) {
|
||||
deco_x=x+ManaSprite.HotX
|
||||
x1=x+ManaSprite.HotX
|
||||
+(type->TileWidth*TileSizeX
|
||||
+type->BoxWidth+1)/2;
|
||||
} else {
|
||||
deco_x=x-ManaSprite.HotX
|
||||
x1=x-ManaSprite.HotX
|
||||
+(type->TileWidth*TileSizeX
|
||||
-type->BoxWidth+1)/2;
|
||||
}
|
||||
if( ManaSprite.HotY<0 ) {
|
||||
deco_y=y+ManaSprite.HotY
|
||||
y1=y+ManaSprite.HotY
|
||||
+(type->TileHeight*TileSizeY
|
||||
+type->BoxHeight+1)/2;
|
||||
} else {
|
||||
deco_y=y-ManaSprite.HotY
|
||||
y1=y-ManaSprite.HotY
|
||||
+(type->TileHeight*TileSizeY
|
||||
-type->BoxHeight+1)/2;
|
||||
}
|
||||
VideoDrawClip(ManaSprite.Sprite,n,deco_x,deco_y);
|
||||
VideoDrawClip(ManaSprite.Sprite,n,x1,y1);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Draw spells decoration
|
||||
//
|
||||
if ( unit->Bloodlust > 0 )
|
||||
VideoDrawClip( SpellSprites, 0, x, y );
|
||||
if ( unit->Haste > 0 ) // same slot as slow
|
||||
VideoDrawClip( SpellSprites, 1, x+16, y );
|
||||
if ( unit->Slow > 0 ) // same slot as haste
|
||||
VideoDrawClip( SpellSprites, 2, x+16, y );
|
||||
if ( unit->Invisible > 0 )
|
||||
VideoDrawClip( SpellSprites, 3, x+16+16, y );
|
||||
if ( unit->UnholyArmor > 0 )
|
||||
VideoDrawClip( SpellSprites, 4, x+16+16+16, y );
|
||||
|
||||
// FIXME: group number could also be shown
|
||||
}
|
||||
|
||||
|
@ -559,7 +564,6 @@ local void DrawShadow(Unit* unit,UnitType* type,int x,int y)
|
|||
,x+ShadowSprite.HotX,y+ShadowSprite.HotY);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
** Draw path from current postion to the destination of the move.
|
||||
**
|
||||
|
@ -681,134 +685,15 @@ global void DrawPath(Unit* unit)
|
|||
,6,6);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
** Show the current order of an unit.
|
||||
**
|
||||
** @param unit Pointer to the unit.
|
||||
**
|
||||
*/
|
||||
local void ShowOrder(const Unit* unit)
|
||||
{
|
||||
#ifdef NEW_ORDERS
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
int color;
|
||||
const Unit* goal;
|
||||
int i;
|
||||
|
||||
if( unit->Destroyed ) {
|
||||
return;
|
||||
}
|
||||
x1=Map2ScreenX(unit->X)+unit->IX+unit->Type->TileWidth*TileSizeX/2;
|
||||
y1=Map2ScreenY(unit->Y)+unit->IY+unit->Type->TileHeight*TileSizeY/2;
|
||||
VideoFillCircleClip(ColorGreen,x1,y1,1);
|
||||
|
||||
for( i=0; i<=unit->OrderCount; ++i ) {
|
||||
if( (goal=unit->Orders[i].Goal) ) {
|
||||
x2=Map2ScreenX(goal->X)+goal->IX+goal->Type->TileWidth*TileSizeX/2;
|
||||
y2=Map2ScreenY(goal->Y)+goal->IY+goal->Type->TileHeight*TileSizeY/2;
|
||||
} else {
|
||||
x2=Map2ScreenX(unit->Orders[i].X)+TileSizeX/2;
|
||||
y2=Map2ScreenY(unit->Orders[i].Y)+TileSizeY/2;
|
||||
}
|
||||
switch( unit->Orders[i].Action ) {
|
||||
case UnitActionNone:
|
||||
color=ColorGray;
|
||||
break;
|
||||
|
||||
case UnitActionStill:
|
||||
color=ColorGray;
|
||||
break;
|
||||
|
||||
case UnitActionStandGround:
|
||||
color=ColorGray;
|
||||
break;
|
||||
|
||||
case UnitActionFollow:
|
||||
case UnitActionMove:
|
||||
color=ColorGreen;
|
||||
break;
|
||||
|
||||
case UnitActionPatrol:
|
||||
VideoDrawLineClip(ColorGreen,x1,y1,x2,y2);
|
||||
color=ColorBlue;
|
||||
break;
|
||||
|
||||
case UnitActionRepair:
|
||||
color=ColorGreen;
|
||||
break;
|
||||
|
||||
case UnitActionAttack:
|
||||
case UnitActionAttackGround:
|
||||
color=ColorRed;
|
||||
break;
|
||||
|
||||
case UnitActionBoard:
|
||||
color=ColorGreen;
|
||||
break;
|
||||
|
||||
case UnitActionUnload:
|
||||
color=ColorGreen;
|
||||
break;
|
||||
|
||||
case UnitActionDie:
|
||||
color=ColorGray;
|
||||
break;
|
||||
|
||||
case UnitActionTrain:
|
||||
color=ColorGray;
|
||||
break;
|
||||
|
||||
case UnitActionUpgradeTo:
|
||||
color=ColorGray;
|
||||
break;
|
||||
|
||||
case UnitActionResearch:
|
||||
color=ColorGray;
|
||||
break;
|
||||
|
||||
case UnitActionBuild:
|
||||
color=ColorGreen;
|
||||
break;
|
||||
|
||||
case UnitActionBuilded:
|
||||
color=ColorGray;
|
||||
break;
|
||||
|
||||
case UnitActionHarvest:
|
||||
color=ColorGreen;
|
||||
break;
|
||||
|
||||
case UnitActionMineGold:
|
||||
color=ColorGreen;
|
||||
break;
|
||||
|
||||
case UnitActionHaulOil:
|
||||
color=ColorGreen;
|
||||
break;
|
||||
|
||||
case UnitActionReturnGoods:
|
||||
color=ColorGreen;
|
||||
break;
|
||||
|
||||
case UnitActionDemolish:
|
||||
color=ColorRed;
|
||||
break;
|
||||
|
||||
default:
|
||||
color=ColorGray;
|
||||
DebugLevel1Fn("Unknown action %d\n",unit->Orders[i].Action);
|
||||
break;
|
||||
}
|
||||
VideoDrawLineClip(color,x1,y1,x2,y2);
|
||||
VideoFillCircleClip(color,x2,y2,2);
|
||||
x1=x2;
|
||||
y1=y2;
|
||||
}
|
||||
#else
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
|
@ -925,7 +810,6 @@ local void ShowOrder(const Unit* unit)
|
|||
VideoFillCircleClip(color,x2,y2,2);
|
||||
|
||||
//DrawPath(unit);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -933,7 +817,6 @@ local void ShowOrder(const Unit* unit)
|
|||
**
|
||||
** 1) Must draw underground/underwater units. (FUTURE extension)
|
||||
** 2) Must draw buildings and corpse.
|
||||
** FIXME: Bridges?
|
||||
** 3) Must draw land/sea units.
|
||||
** 4) Must draw decoration units. (FUTURE extension)
|
||||
** 5) Must draw low air units.
|
||||
|
@ -998,34 +881,6 @@ local void DrawBuilding(Unit* unit)
|
|||
DrawSelection(unit,type,x,y);
|
||||
#endif
|
||||
|
||||
#ifdef NEW_ORDERS
|
||||
//
|
||||
// Buildings under construction/upgrade/ready.
|
||||
//
|
||||
if( unit->Orders[0].Action==UnitActionBuilded ) {
|
||||
if( unit->Constructed || VideoGraphicFrames(type->Sprite)<=1 ) {
|
||||
DrawConstruction(type->OverlapFrame
|
||||
,frame&127
|
||||
,x+(type->TileWidth*TileSizeX)/2
|
||||
,y+(type->TileHeight*TileSizeY)/2);
|
||||
} else {
|
||||
DrawUnitType(type,frame,x,y);
|
||||
}
|
||||
} else if( unit->Orders[0].Action==UnitActionUpgradeTo ) {
|
||||
// FIXME: update frame hard coded.
|
||||
DrawUnitType(unit->Orders[0].Type,(frame&128)+1,x,y);
|
||||
} else {
|
||||
DrawUnitType(type,frame,x,y);
|
||||
}
|
||||
|
||||
// FIXME: johns: ugly check here should be removed!
|
||||
if( unit->Orders[0].Action!=UnitActionDie ) {
|
||||
DrawDecoration(unit,type,x,y);
|
||||
#if 0
|
||||
DrawSelection(unit,type,x,y);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
//
|
||||
// Buildings under construction/upgrade/ready.
|
||||
//
|
||||
|
@ -1044,12 +899,16 @@ local void DrawBuilding(Unit* unit)
|
|||
DrawUnitType(type,frame,x,y);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// FIXME: johns: ugly check here should be removed!
|
||||
if( unit->Command.Action!=UnitActionDie ) {
|
||||
DrawDecoration(unit,type,x,y);
|
||||
#if 0
|
||||
DrawSelection(unit,type,x,y);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
// FIXME: johns: ugly check here should be removed!
|
||||
if( unit->Command.Action!=UnitActionDie ) {
|
||||
DrawDecoration(unit,type,x,y);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1067,6 +926,8 @@ local void DrawUnit(Unit* unit)
|
|||
UnitType* type;
|
||||
UnitStats* stats;
|
||||
|
||||
if ( unit->Revealer ) return; // Revealers are not drawn
|
||||
|
||||
type=unit->Type;
|
||||
|
||||
x=Map2ScreenX(unit->X)+unit->IX;
|
||||
|
@ -1124,17 +985,10 @@ local void DrawUnit(Unit* unit)
|
|||
ShowOrder(unit);
|
||||
}
|
||||
|
||||
#ifdef NEW_ORDERS
|
||||
// FIXME: johns: ugly check here should be removed!
|
||||
if( unit->Orders[0].Action!=UnitActionDie ) {
|
||||
DrawDecoration(unit,type,x,y);
|
||||
}
|
||||
#else
|
||||
// FIXME: johns: ugly check here should be removed!
|
||||
if( unit->Command.Action!=UnitActionDie ) {
|
||||
DrawDecoration(unit,type,x,y);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1159,17 +1013,9 @@ global void DrawUnits(void)
|
|||
for( i=0; i<NumUnits; ++i ) {
|
||||
unit=Units[i];
|
||||
// FIXME: this tries to draw all corps, ohje
|
||||
#ifdef NEW_ORDERS
|
||||
if( (unit->Type->Vanishes || unit->Orders[0].Action==UnitActionDie)
|
||||
&& UnitVisible(unit) ) {
|
||||
if( unit->Type->Vanishes || unit->Command.Action==UnitActionDie ) {
|
||||
DrawUnit(unit);
|
||||
}
|
||||
#else
|
||||
if( (unit->Type->Vanishes || unit->Command.Action==UnitActionDie)
|
||||
&& UnitVisible(unit) ) {
|
||||
DrawUnit(unit);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
//
|
||||
// 2b) buildings
|
||||
|
|
|
@ -67,7 +67,10 @@
|
|||
*/
|
||||
global int SelectUnits(int x1,int y1,int x2,int y2,Unit** table)
|
||||
{
|
||||
return UnitCacheSelect(x1,y1,x2,y2,table);
|
||||
if ( x1 == x2 && y1 == y2 )
|
||||
return UnitCacheOnTile(x1,y1,table);
|
||||
else
|
||||
return UnitCacheSelect(x1,y1,x2,y2,table);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -124,6 +124,7 @@ global CursorType Cursors[CursorMax] = {
|
|||
|
||||
global enum CursorState_e CursorState; /// cursor state
|
||||
global int CursorAction; /// action for selection
|
||||
global int CursorValue; /// value for CursorAction (spell type f.e.)
|
||||
global UnitType* CursorBuilding; /// building cursor
|
||||
|
||||
global CursorType* GameCursor; /// cursor type
|
||||
|
|
Loading…
Add table
Reference in a new issue