- fixed fireball
- fixed blizzard/death-and-decay - fixed invisibility - fixed unholy-armor - multiple duplicates messages handler
This commit is contained in:
parent
079b1f90c4
commit
0524cdb99c
8 changed files with 138 additions and 37 deletions
|
@ -99,8 +99,8 @@ local void RepairUnit(Unit* unit,Unit* goal)
|
|||
for( i=1; i<MaxCosts; ++i ) {
|
||||
if( player->Resources[i]<costs[i] ) {
|
||||
SetMessage("We need resources!");
|
||||
// FIXME: perhaps we should not animate if no resources are available.
|
||||
return;
|
||||
// FIXME: perhaps we should not animate if no resources are available.
|
||||
return;
|
||||
}
|
||||
}
|
||||
//
|
||||
|
|
|
@ -45,8 +45,9 @@ global void HandleActionResearch(Unit* unit)
|
|||
if( unit->Command.Data.Research.Ticks>=upgrade->Costs[TimeCost] ) {
|
||||
|
||||
// FIXME: should als speak and tell ai
|
||||
SetMessage2( unit->X, unit->Y, "%s: Upgrade complete", unit->Type->Name );
|
||||
|
||||
if( unit->Player==ThisPlayer ) {
|
||||
SetMessage2( unit->X, unit->Y, "%s: Upgrade complete", unit->Type->Name );
|
||||
}
|
||||
UpgradeAcquire(unit->Player,upgrade);
|
||||
|
||||
unit->Reset=1;
|
||||
|
|
|
@ -136,8 +136,11 @@ global void HandleActionSpellCast(Unit* unit)
|
|||
const SpellType* spell = SpellTypeById( unit->Command.Data.Move.SpellId );
|
||||
if ( unit->Mana < spell->ManaCost )
|
||||
{
|
||||
SetMessage( "%s: not enough mana to cast spell: %s",
|
||||
unit->Type->Name, spell->Ident );
|
||||
if( unit->Player==ThisPlayer )
|
||||
{
|
||||
SetMessage( "%s: not enough mana to cast spell: %s",
|
||||
unit->Type->Name, spell->Ident );
|
||||
}
|
||||
repeat = 0;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -210,7 +210,7 @@ global MissileType MissileTypes[MissileTypeMax] = {
|
|||
"death and decay.png",
|
||||
32,32,
|
||||
{ NULL },
|
||||
MissileClassStayWithDelay,
|
||||
MissileClassDeathDecay,
|
||||
1,
|
||||
},
|
||||
{ MissileTypeType,
|
||||
|
@ -603,13 +603,15 @@ local int CalculateDamageStats(const UnitStats* attacker_stats
|
|||
,const UnitStats* goal_stats)
|
||||
{
|
||||
int damage;
|
||||
|
||||
int basic_damage = attacker_stats->BasicDamage;
|
||||
int piercing_damage = attacker_stats->PiercingDamage;
|
||||
|
||||
damage=-goal_stats->Armor;
|
||||
damage+=attacker_stats->BasicDamage;
|
||||
damage+= basic_damage;
|
||||
if( damage<0 ) {
|
||||
damage=0;
|
||||
}
|
||||
damage+=attacker_stats->PiercingDamage+1; // round up
|
||||
damage+=piercing_damage+1; // round up
|
||||
damage/=2;
|
||||
damage*=((SyncRand()>>15)&1)+1;
|
||||
DebugLevel3Fn("Damage done %d\n",damage);
|
||||
|
@ -984,6 +986,7 @@ local int PointToPointMissile(Missile* missile)
|
|||
return 0;
|
||||
}
|
||||
|
||||
local int BlizzardMissileHit = 0;
|
||||
/**
|
||||
** Work for missile hit.
|
||||
*/
|
||||
|
@ -1038,6 +1041,9 @@ global void MissileHit(const Missile* missile)
|
|||
DebugLevel3Fn("Oops nothing to hit (%d,%d)?\n",x,y);
|
||||
return;
|
||||
}
|
||||
if ( BlizzardMissileHit && goal == missile->SourceUnit )
|
||||
return; // blizzard cannot hit owner unit
|
||||
BlizzardMissileHit = 0;
|
||||
if ( missile->Damage )
|
||||
HitUnit(goal,missile->Damage); // direct damage, spells mostly
|
||||
else
|
||||
|
@ -1184,11 +1190,26 @@ global void MissileActions(void)
|
|||
missile->Frame+=4; // FIXME: frames pro row
|
||||
if( (missile->Frame&127)
|
||||
>=VideoGraphicFrames(missile->Type->Sprite) ) {
|
||||
//NOTE: vladi: blizzard cannot hit owner...
|
||||
BlizzardMissileHit = 1;
|
||||
MissileHit(missile);
|
||||
missile->Type=MissileFree;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MissileClassDeathDecay:
|
||||
//NOTE: vladi: this is exact copy of MissileClassStayWithDelay
|
||||
// but with check for blizzard-type hit (friendly fire:))
|
||||
missile->Wait=missile->Type->Speed;
|
||||
if( ++missile->Frame
|
||||
==VideoGraphicFrames(missile->Type->Sprite) ) {
|
||||
BlizzardMissileHit = 1;
|
||||
MissileHit(missile);
|
||||
missile->Type=MissileFree;
|
||||
}
|
||||
break;
|
||||
|
||||
case MissileClassWhirlwind:
|
||||
missile->Wait=missile->Type->Speed;
|
||||
missile->Frame++;
|
||||
|
@ -1199,7 +1220,7 @@ global void MissileActions(void)
|
|||
if ( missile->TTL < 1 || missile->TTL % 10 == 0 )
|
||||
PointToPointMissile(missile);
|
||||
break;
|
||||
|
||||
|
||||
case MissileClassStayWithDelay:
|
||||
missile->Wait=missile->Type->Speed;
|
||||
if( ++missile->Frame
|
||||
|
|
|
@ -75,7 +75,7 @@ global SpellType SpellTypeTable[] = {
|
|||
{ 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-fireball", 8, 100,1000, 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 },
|
||||
|
@ -109,8 +109,11 @@ MissileType* missile_rune = NULL;
|
|||
----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
** Missile controllers should return 0 to continue
|
||||
** or 1 to cancel the spell/missile
|
||||
** Missile controllers
|
||||
**
|
||||
** To cancel a missile set it's TTL to 0, it will be handled right after
|
||||
** the controller call and missile will be down.
|
||||
**
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -125,9 +128,10 @@ global int SpellFireballController( void* missile )
|
|||
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.
|
||||
// explosions start at target and continue (10 tiles) beyond
|
||||
// explosions are on each tile on the way
|
||||
|
||||
if ( mis->TTL <= mis->State && mis->TTL % 2 == 0 ) // approx.
|
||||
{
|
||||
//+TileSize/2 to align gfx to baseline
|
||||
int x = mis->X + TileSizeX/2;
|
||||
|
@ -144,7 +148,8 @@ global int SpellFireballController( void* missile )
|
|||
for( i=0; i<n; ++i )
|
||||
HitUnit(table[i],FIREBALL_DAMAGE);
|
||||
}
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -486,6 +491,7 @@ global int SpellCast( int SpellId, Unit* unit, Unit* target, int x, int y )
|
|||
int sy = unit->Y;
|
||||
int dx = x;
|
||||
int dy = y;
|
||||
int dist;
|
||||
|
||||
if ( target )
|
||||
{
|
||||
|
@ -493,15 +499,22 @@ global int SpellCast( int SpellId, Unit* unit, Unit* target, int x, int y )
|
|||
dy = target->Y;
|
||||
}
|
||||
|
||||
dist = MapDistance( sx, sy, dx, dy );
|
||||
dx += ((dx - sx)*10)/dist;
|
||||
dy += ((dy - sy)*10)/dist;
|
||||
|
||||
sx = sx*TileSizeX+TileSizeX/2;
|
||||
sy = sy*TileSizeX+TileSizeX/2;
|
||||
dx = dx*TileSizeX+TileSizeX/2;
|
||||
dy = dy*TileSizeX+TileSizeX/2;
|
||||
|
||||
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 );
|
||||
sx, sy, dx, dy );
|
||||
|
||||
mis->State = spell->TTL - (dist - 1) * 2;
|
||||
mis->TTL = spell->TTL;
|
||||
mis->Controller = SpellFireballController;
|
||||
}
|
||||
|
@ -646,7 +659,7 @@ global int SpellCast( int SpellId, Unit* unit, Unit* target, int x, int y )
|
|||
// ---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;
|
||||
|
|
|
@ -480,7 +480,7 @@ global void DrawResources(void)
|
|||
|
||||
// FIXME: need messages for chat!
|
||||
|
||||
#define MESSAGES_TIMEOUT FRAMES_PER_SECOND*2 // two seconds
|
||||
#define MESSAGES_TIMEOUT FRAMES_PER_SECOND*5 // 5 seconds
|
||||
|
||||
local char MessageBuffer[40]; // message buffer
|
||||
local char* Message; // message in map window
|
||||
|
@ -490,6 +490,7 @@ local int MessageFrameTimeout; // frame to expire message
|
|||
|
||||
local char Messages[ MESSAGES_MAX ][64];
|
||||
local int MessagesCount;
|
||||
local int SameMessageCount;
|
||||
|
||||
local char MessagesEvent[ MESSAGES_MAX ][64];
|
||||
local int MessagesEventX[ MESSAGES_MAX ];
|
||||
|
@ -550,11 +551,51 @@ global void DrawMessage(void)
|
|||
}
|
||||
for ( z = 0; z < MessagesCount; z++ )
|
||||
{
|
||||
if ( Messages[z][0] == '*' )
|
||||
DrawText(TheUI.MapX+8,TheUI.MapY+8 + z*16,GameFont,Messages[z]+1);
|
||||
else
|
||||
DrawReverseText(TheUI.MapX+8,TheUI.MapY+8 + z*16,GameFont,Messages[z]);
|
||||
DrawText(TheUI.MapX+8,TheUI.MapY+8 + z*16,GameFont,Messages[z] );
|
||||
}
|
||||
if ( MessagesCount < 1 )
|
||||
SameMessageCount = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Adds message to the stack
|
||||
**
|
||||
** @param msg Message to add.
|
||||
*/
|
||||
global void AddMessage( const char* msg )
|
||||
{
|
||||
if ( MessagesCount == MESSAGES_MAX )
|
||||
ShiftMessages();
|
||||
strcpy( Messages[ MessagesCount ], msg );
|
||||
MessagesCount++;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if this message repeats
|
||||
**
|
||||
** @param msg Message to check.
|
||||
** @return non-zero to skip this message
|
||||
*/
|
||||
global int CheckRepeatMessage( const char* msg )
|
||||
{
|
||||
if ( MessagesCount < 1 )
|
||||
return 0;
|
||||
if ( strcmp( msg, Messages[ MessagesCount-1 ] ) == 0 )
|
||||
{
|
||||
SameMessageCount++;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
if ( SameMessageCount > 0 )
|
||||
{
|
||||
char temp[128];
|
||||
int n = SameMessageCount;
|
||||
SameMessageCount = 0;
|
||||
// NOTE: vladi: yep it's a tricky one, but should work fine prbably :)
|
||||
sprintf( temp, "Last message repeated ~<%d~> times", n+1 );
|
||||
AddMessage( temp );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -569,10 +610,9 @@ global void SetMessage( char* fmt, ... )
|
|||
va_start( va, fmt );
|
||||
vsprintf( temp, fmt, va );
|
||||
va_end( va );
|
||||
if ( MessagesCount == MESSAGES_MAX )
|
||||
ShiftMessages();
|
||||
strcpy( Messages[ MessagesCount ], temp );
|
||||
MessagesCount++;
|
||||
if ( CheckRepeatMessage( temp ) )
|
||||
return;
|
||||
AddMessage( temp );
|
||||
MustRedraw|=RedrawMessage|RedrawMap;
|
||||
MessageFrameTimeout = FrameCounter + MESSAGES_TIMEOUT;
|
||||
}
|
||||
|
@ -594,10 +634,10 @@ global void SetMessage2( int x, int y, char* fmt, ... )
|
|||
va_start( va, fmt );
|
||||
vsprintf( temp, fmt, va );
|
||||
va_end( va );
|
||||
if ( MessagesCount == MESSAGES_MAX )
|
||||
ShiftMessages();
|
||||
strcpy( Messages[ MessagesCount ], temp );
|
||||
MessagesCount++;
|
||||
if ( CheckRepeatMessage( temp ) == 0 )
|
||||
{
|
||||
AddMessage( temp );
|
||||
}
|
||||
|
||||
if ( MessagesEventCount == MESSAGES_MAX )
|
||||
ShiftMessagesEvent();
|
||||
|
@ -667,7 +707,7 @@ global void CenterOnMessage(void)
|
|||
return;
|
||||
MapCenter( MessagesEventX[ MessagesEventIndex ],
|
||||
MessagesEventY[ MessagesEventIndex ] );
|
||||
SetMessage( "*Event: %s", MessagesEvent[ MessagesEventIndex ] );
|
||||
SetMessage( "~<Event: %s~>", MessagesEvent[ MessagesEventIndex ] );
|
||||
MessagesEventIndex++;
|
||||
}
|
||||
|
||||
|
|
|
@ -535,6 +535,12 @@ global void UIHandleMouseMove(int x,int y)
|
|||
}
|
||||
}
|
||||
|
||||
//NOTE: vladi: if unit is invisible, no cursor hint should be allowed
|
||||
if ( UnitUnderCursor && !UnitVisible( UnitUnderCursor ) )
|
||||
{
|
||||
UnitUnderCursor = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Selecting target.
|
||||
//
|
||||
|
|
|
@ -663,6 +663,12 @@ global int UnitVisible(const Unit* unit)
|
|||
unsigned m;
|
||||
MapField* mf;
|
||||
|
||||
if ( unit->Invisible && unit->Player != ThisPlayer )
|
||||
{
|
||||
//FIXME: vladi: should handle teams and shared vision
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Check if visible on screen
|
||||
//
|
||||
|
@ -705,6 +711,12 @@ global int UnitVisible(const Unit* unit)
|
|||
}
|
||||
);
|
||||
|
||||
if ( unit->Invisible && unit->Player != ThisPlayer )
|
||||
{
|
||||
//FIXME: vladi: should handle teams and shared vision
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Check if visible on screen
|
||||
//
|
||||
|
@ -2127,6 +2139,11 @@ global void HitUnit(Unit* unit,int damage)
|
|||
|
||||
DebugCheck( damage==0 || unit->HP==0 || unit->Type->Vanishes );
|
||||
|
||||
if ( unit->UnholyArmor > 0 )
|
||||
{ //NOTE: vladi: units with active UnholyArmour are invulnerable
|
||||
return;
|
||||
}
|
||||
|
||||
type=unit->Type;
|
||||
if( !unit->Attacked ) {
|
||||
if( unit->Player==ThisPlayer ) {
|
||||
|
|
Loading…
Add table
Reference in a new issue