- fixed fireball

- fixed blizzard/death-and-decay
- fixed invisibility
- fixed unholy-armor
- multiple duplicates messages handler
This commit is contained in:
cade 2000-07-01 22:38:41 +00:00
parent 079b1f90c4
commit 0524cdb99c
8 changed files with 138 additions and 37 deletions

View file

@ -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;
}
}
//

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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++;
}

View file

@ -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.
//

View file

@ -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 ) {