- Added MF5_CANTSEEK flag to prevent seeker missiles from homing in on

certain actors and added an option to APowerInvisibility to set this
  flag when active.
- Added map specific automap backgrounds.
- Fixed: Voodoo dolls did not play a sound when dying.
- Added colorized error messages to DECORATE and made a few more error
  conditions that do not block further parsing not immediately abort.
- Made all errors in CreateNewActor not immediately fatal so that the
  rest of the DECORATE lump can be parsed normally to look for more errors.
- Fixed: Defining classes with the same name as their immediate base class
  was legal. It should not be allowed that a class has another one with the
  same name in its ancestry.
- Fixed: Formatting of the intermission screen on Heretic, Hexen and Strife
  was broken. Changed it to use WI_Drawpercent which does it properly and
  also allows showing percentage in these games now.
- Fixed: The MAPINFO parser ignored missing terminating braces of the last
  block in the file.

SVN r1425 (trunk)
This commit is contained in:
Christoph Oelckers 2009-02-19 14:36:37 +00:00
parent 0acc6a4ee3
commit 666e40c8bb
23 changed files with 545 additions and 416 deletions

View File

@ -1,3 +1,27 @@
February 15, 2009 (Changes by Graf Zahl)
- Fixed: The CHARFORMAT structure that is used to set the color in a Windows
Rich Edit control was not fully initialized resulting in incorrect colors
being set.
February 14, 2009 (Changes by Graf Zahl)
- Added MF5_CANTSEEK flag to prevent seeker missiles from homing in on
certain actors and added an option to APowerInvisibility to set this
flag when active.
- Added map specific automap backgrounds.
- Fixed: Voodoo dolls did not play a sound when dying.
- Added colorized error messages to DECORATE and made a few more error
conditions that do not block further parsing not immediately abort.
- Made all errors in CreateNewActor not immediately fatal so that the
rest of the DECORATE lump can be parsed normally to look for more errors.
- Fixed: Defining classes with the same name as their immediate base class
was legal. It should not be allowed that a class has another one with the
same name in its ancestry.
- Fixed: Formatting of the intermission screen on Heretic, Hexen and Strife
was broken. Changed it to use WI_Drawpercent which does it properly and
also allows showing percentage in these games now.
- Fixed: The MAPINFO parser ignored missing terminating braces of the last
block in the file.
February 10, 2009
- Moved the V_InitFontColors() call earlier in the startup sequence so that
colored error messages appear colored in the startup window. Also lightened

View File

@ -304,6 +304,7 @@ enum
MF5_SUMMONEDMONSTER = 0x02000000, // To mark the friendly Minotaur. Hopefully to be generalized later.
MF5_NOVERTICALMELEERANGE=0x04000000,// Does not check vertical distance for melee range
MF5_BRIGHT = 0x08000000, // Actor is always rendered fullbright
MF5_CANTSEEK = 0x10000000, // seeker missiles cannot home in on this actor
// --- mobj.renderflags ---

View File

@ -798,7 +798,9 @@ void AM_loadPics ()
marknums[i] = TexMan.CheckForTexture (namebuf, FTexture::TEX_MiscPatch);
}
mapback = TexMan.CheckForTexture("AUTOPAGE", FTexture::TEX_MiscPatch);
const char *autopage = level.info->mapbg[0] == 0? "AUTOPAGE" : (const char*)level.info->mapbg[0];
mapback = TexMan.CheckForTexture(autopage, FTexture::TEX_MiscPatch);
}
bool AM_clearMarks ()

View File

@ -73,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer)
// adjust direction
dest = self->tracer;
if (!dest || dest->health <= 0 || self->Speed == 0)
if (!dest || dest->health <= 0 || self->Speed == 0 || (dest->flags5 & MF5_CANTSEEK))
return;
// change angle

View File

@ -95,6 +95,7 @@ struct FMapInfoParser
bool CheckNumber();
bool CheckFloat();
void SkipToNext();
void CheckEndOfFile(const char *block);
};
#define DEFINE_MAP_OPTION(name, old) \
@ -284,6 +285,7 @@ struct level_info_t
FString SoundInfo;
FString SndSeq;
char bordertexture[9];
char mapbg[9];
float teamdamage;

View File

@ -541,6 +541,21 @@ void FMapInfoParser::SkipToNext()
}
}
//==========================================================================
//
// checks if the current block was properly terminated
//
//==========================================================================
void FMapInfoParser::CheckEndOfFile(const char *block)
{
if (format_type == FMT_New && !sc.Compare("}"))
{
sc.ScriptError("Unexpected end of file in %s definition", block);
}
}
//==========================================================================
//
// ParseLookupname
@ -715,6 +730,7 @@ void FMapInfoParser::ParseCluster()
break;
}
}
CheckEndOfFile("cluster");
}
@ -1191,6 +1207,13 @@ DEFINE_MAP_OPTION(teamdamage, true)
info->teamdamage = parse.sc.Float;
}
DEFINE_MAP_OPTION(mapbackground, true)
{
parse.ParseAssign();
parse.ParseLumpOrTextureName(info->mapbg);
}
//==========================================================================
//
// All flag based map options
@ -1421,6 +1444,7 @@ void FMapInfoParser::ParseMapDefinition(level_info_t &info)
}
}
}
CheckEndOfFile("map");
}
@ -1620,6 +1644,7 @@ void FMapInfoParser::ParseEpisodeInfo ()
break;
}
}
CheckEndOfFile("episode");
if (extended && !(gameinfo.flags & GI_MENUHACK_EXTENDED))
{ // If the episode is for the extended Heretic, but this is

View File

@ -540,6 +540,22 @@ PalEntry APowerStrength::GetBlend ()
IMPLEMENT_CLASS (APowerInvisibility)
//===========================================================================
//
// APowerInvisibility :: CommonInit
//
// stuff that's done for all subclasses
//
//===========================================================================
void APowerInvisibility::CommonInit()
{
Owner->flags |= MF_SHADOW;
// transfer seeker missile blocking (but only if the owner does not already have this flag
if (!(Owner->flags5 & MF5_CANTSEEK) && (flags5 & MF5_CANTSEEK)) Owner->flags5 |= MF5_CANTSEEK;
else flags &=~MF5_CANTSEEK;
}
//===========================================================================
//
// APowerInvisibility :: InitEffect
@ -548,11 +564,16 @@ IMPLEMENT_CLASS (APowerInvisibility)
void APowerInvisibility::InitEffect ()
{
Owner->flags |= MF_SHADOW;
CommonInit();
Owner->alpha = FRACUNIT/5;
Owner->RenderStyle = STYLE_OptFuzzy;
}
//===========================================================================
//
// APowerInvisibility :: DoEffect
//
//===========================================================================
void APowerInvisibility::DoEffect ()
{
Super::DoEffect();
@ -571,6 +592,7 @@ void APowerInvisibility::EndEffect ()
{
if (Owner != NULL)
{
if (flags5 & MF5_CANTSEEK) Owner->flags5 &= ~MF5_CANTSEEK;
Owner->flags &= ~MF_SHADOW;
Owner->flags3 &= ~MF3_GHOST;
Owner->RenderStyle = STYLE_Normal;
@ -628,7 +650,7 @@ IMPLEMENT_CLASS (APowerGhost)
void APowerGhost::InitEffect ()
{
Owner->flags |= MF_SHADOW;
CommonInit();
Owner->flags3 |= MF3_GHOST;
Owner->alpha = HR_SHADOW;
Owner->RenderStyle = STYLE_Translucent;
@ -705,7 +727,7 @@ bool APowerShadow::HandlePickup (AInventory *item)
void APowerShadow::InitEffect ()
{
Owner->flags |= MF_SHADOW;
CommonInit();
Owner->alpha = special1 == 0 ? TRANSLUC25 : 0;
Owner->RenderStyle = STYLE_Translucent;
}

View File

@ -77,6 +77,7 @@ class APowerInvisibility : public APowerup
{
DECLARE_CLASS (APowerInvisibility, APowerup)
protected:
void CommonInit ();
void InitEffect ();
void DoEffect ();
void EndEffect ();

View File

@ -309,7 +309,7 @@ void DSBarInfo::Tick ()
oldHealth += clamp((health - oldHealth), 1, script->interpolationSpeed);
}
}
AInventory *armor = CPlayer->mo->FindInventory<ABasicArmor>();
AInventory *armor = CPlayer->mo != NULL? CPlayer->mo->FindInventory<ABasicArmor>() : NULL;
if(armor == NULL)
{
oldArmor = 0;

View File

@ -225,6 +225,7 @@ void FMapInfoParser::ParseSkill ()
break;
}
}
CheckEndOfFile("skill");
for(unsigned int i = 0; i < AllSkills.Size(); i++)
{
if (AllSkills[i].Name == skill.Name)

View File

@ -91,7 +91,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2)
dest = self->tracer;
if (dest == NULL || dest->health <= 0 || self->Speed == 0)
if (!dest || dest->health <= 0 || self->Speed == 0 || (dest->flags5 & MF5_CANTSEEK))
return;
// change angle

View File

@ -71,6 +71,7 @@ EXTERN_CVAR (Color, am_wallcolor)
EXTERN_CVAR (Color, am_fdwallcolor)
EXTERN_CVAR (Color, am_cdwallcolor)
EXTERN_CVAR (Float, spc_amp)
EXTERN_CVAR (Bool, wi_percents)
FString WeaponSection;
@ -638,6 +639,8 @@ void FGameConfigFile::SetRavenDefaults (bool isHexen)
color.ResetToDefault ();
}
val.Bool = false;
wi_percents.SetGenericRepDefault (val, CVAR_Bool);
val.Bool = true;
con_centernotify.SetGenericRepDefault (val, CVAR_Bool);
snd_pitched.SetGenericRepDefault (val, CVAR_Bool);

View File

@ -1284,7 +1284,7 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax)
AActor *target;
target = actor->tracer;
if (target == NULL || actor->Speed == 0)
if (target == NULL || actor->Speed == 0 || (target->flags5 & MF5_CANTSEEK))
{
return false;
}

View File

@ -1220,8 +1220,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream)
int chan = CHAN_VOICE;
if (self->player == NULL || self->DeathSound != 0)
{
if (self->DeathSound != 0)
{
S_Sound (self, CHAN_VOICE, self->DeathSound, 1, ATTN_NORM);
}
else
{
S_Sound (self, CHAN_VOICE, "*death", 1, ATTN_NORM);
}
return;
}

View File

@ -1013,7 +1013,7 @@ void STACK_ARGS FScanner::ScriptMessage (const char *message, ...)
va_end (arglist);
}
Printf (TEXTCOLOR_RED"Script error, \"%s\" line %d:\n%s\n", ScriptName.GetChars(),
Printf (TEXTCOLOR_RED"Script error, \"%s\" line %d:\n"TEXTCOLOR_RED"%s\n", ScriptName.GetChars(),
AlreadyGot? AlreadyGotLine : Line, composed.GetChars());
}
@ -1087,6 +1087,7 @@ void STACK_ARGS FScriptPosition::Message (int severity, const char *message, ...
va_end (arglist);
}
const char *type = "";
const char *color;
int level = PRINT_HIGH;
switch (severity)
@ -1096,29 +1097,34 @@ void STACK_ARGS FScriptPosition::Message (int severity, const char *message, ...
case MSG_WARNING:
type = "warning";
color = TEXTCOLOR_YELLOW;
break;
case MSG_ERROR:
ErrorCounter++;
type = "error";
color = TEXTCOLOR_RED;
break;
case MSG_MESSAGE:
case MSG_DEBUG:
type = "message";
color = TEXTCOLOR_GREEN;
break;
case MSG_DEBUGLOG:
case MSG_LOG:
type = "message";
level = PRINT_LOG;
color = "";
break;
case MSG_FATAL:
I_Error ("Script error, \"%s\" line %d:\n%s\n",
FileName.GetChars(), ScriptLine, composed.GetChars());
}
Printf (level, "Script %s, \"%s\" line %d:\n%s\n",
type, FileName.GetChars(), ScriptLine, composed.GetChars());
Printf (level, "%sScript %s, \"%s\" line %d:\n%s%s\n",
color, type, FileName.GetChars(), ScriptLine, color, composed.GetChars());
}

View File

@ -227,7 +227,8 @@ enum
MSG_ERROR,
MSG_DEBUG,
MSG_LOG,
MSG_DEBUGLOG
MSG_DEBUGLOG,
MSG_MESSAGE
};
//==========================================================================

View File

@ -78,7 +78,7 @@ PSymbolTable GlobalSymbols;
// Starts a new actor definition
//
//==========================================================================
FActorInfo *CreateNewActor(FName typeName, FName parentName, bool native)
FActorInfo *CreateNewActor(FScriptPosition &sc, FName typeName, FName parentName, bool native)
{
const PClass *replacee = NULL;
PClass *ti = NULL;
@ -90,17 +90,31 @@ FActorInfo *CreateNewActor(FName typeName, FName parentName, bool native)
{
parent = const_cast<PClass *> (PClass::FindClass (parentName));
const PClass *p = parent;
while (p != NULL)
{
if (p->TypeName == typeName)
{
sc.Message(MSG_ERROR, "'%s' inherits from a class with the same name", typeName.GetChars());
break;
}
p = p->ParentClass;
}
if (parent == NULL)
{
I_Error( "Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars());
sc.Message(MSG_ERROR, "Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars());
parent = RUNTIME_CLASS(AActor);
}
else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor)))
{
I_Error( "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars());
sc.Message(MSG_ERROR, "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars());
parent = RUNTIME_CLASS(AActor);
}
else if (parent->ActorInfo == NULL)
{
I_Error( "uninitialized parent type '%s' in %s", parentName.GetChars(), typeName.GetChars());
sc.Message(MSG_ERROR, "uninitialized parent type '%s' in %s", parentName.GetChars(), typeName.GetChars());
parent = RUNTIME_CLASS(AActor);
}
}
@ -109,21 +123,26 @@ FActorInfo *CreateNewActor(FName typeName, FName parentName, bool native)
ti = (PClass*)PClass::FindClass(typeName);
if (ti == NULL)
{
I_Error( "Unknown native class '%s'", typeName.GetChars());
sc.Message(MSG_ERROR, "Unknown native class '%s'", typeName.GetChars());
goto create;
}
else if (ti != RUNTIME_CLASS(AActor) && ti->ParentClass->NativeClass() != parent->NativeClass())
{
I_Error( "Native class '%s' does not inherit from '%s'", typeName.GetChars(), parentName.GetChars());
sc.Message(MSG_ERROR, "Native class '%s' does not inherit from '%s'", typeName.GetChars(), parentName.GetChars());
parent = RUNTIME_CLASS(AActor);
goto create;
}
else if (ti->ActorInfo != NULL)
{
I_Error( "Redefinition of internal class '%s'", typeName.GetChars());
sc.Message(MSG_ERROR, "Redefinition of internal class '%s'", typeName.GetChars());
goto create;
}
ti->InitializeActorInfo();
info = ti->ActorInfo;
}
else
{
create:
ti = parent->CreateDerivedClass (typeName, parent->Size);
info = ti->ActorInfo;
}

View File

@ -189,7 +189,7 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name);
//
//==========================================================================
FActorInfo *CreateNewActor(FName typeName, FName parentName, bool native);
FActorInfo *CreateNewActor(FScriptPosition &sc, FName typeName, FName parentName, bool native);
void SetReplacement(FActorInfo *info, FName replaceName);
void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod);

View File

@ -206,6 +206,7 @@ static FFlagDef ActorFlags[]=
DEFINE_FLAG(MF5, SUMMONEDMONSTER, AActor, flags5),
DEFINE_FLAG(MF5, NOVERTICALMELEERANGE, AActor, flags5),
DEFINE_FLAG(MF5, BRIGHT, AActor, flags5),
DEFINE_FLAG(MF5, CANTSEEK, AActor, flags5),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),

View File

@ -704,13 +704,18 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
}
else
{
sc.ScriptError("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), prop->cls->TypeName.GetChars());
sc.ScriptMessage("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), prop->cls->TypeName.GetChars());
FScriptPosition::ErrorCounter++;
}
}
else if (!propname.CompareNoCase("States"))
{
if (!bag.StateSet) ParseStates(sc, bag.Info, (AActor *)bag.Info->Class->Defaults, bag);
else sc.ScriptError("Multiple state declarations not allowed");
if (bag.StateSet)
{
sc.ScriptMessage("'%s' contains multiple state declarations", bag.Info->Class->TypeName.GetChars());
FScriptPosition::ErrorCounter++;
}
ParseStates(sc, bag.Info, (AActor *)bag.Info->Class->Defaults, bag);
bag.StateSet=true;
}
else if (MatchString(propname, statenames) != -1)
@ -740,6 +745,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
OPTIONAL = 1
};
bool error = false;
AFuncDesc *afd;
FName funcname;
FString args;
@ -748,7 +754,8 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0)
{
sc.ScriptError ("action functions can only be imported by internal class and actor definitions!");
sc.ScriptMessage ("action functions can only be imported by internal class and actor definitions!");
error++;
}
sc.MustGetToken(TK_Native);
@ -757,7 +764,8 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
afd = FindFunction(sc.String);
if (afd == NULL)
{
sc.ScriptError ("The function '%s' has not been exported from the executable.", sc.String);
sc.ScriptMessage ("The function '%s' has not been exported from the executable.", sc.String);
error++;
}
sc.MustGetToken('(');
if (!sc.CheckToken(')'))
@ -808,7 +816,9 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
sc.UnGet();
break;
default:
sc.ScriptError ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars());
sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars());
type = 'x';
FScriptPosition::ErrorCounter++;
break;
}
// Read the optional variable name
@ -862,11 +872,16 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
{
sym->defaultparameterindex = -1;
}
if (cls->Symbols.AddSymbol (sym) == NULL)
if (error)
{
FScriptPosition::ErrorCounter++;
}
else if (cls->Symbols.AddSymbol (sym) == NULL)
{
delete sym;
sc.ScriptError ("'%s' is already defined in class '%s'.",
sc.ScriptMessage ("'%s' is already defined in class '%s'.",
funcname.GetChars(), cls->TypeName.GetChars());
FScriptPosition::ErrorCounter++;
}
}
@ -935,7 +950,12 @@ static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag)
if (sc.CheckNumber())
{
if (sc.Number>=-1 && sc.Number<32768) DoomEdNum = sc.Number;
else sc.ScriptError ("DoomEdNum must be in the range [-1,32767]");
else
{
// does not need to be fatal.
sc.ScriptMessage ("DoomEdNum must be in the range [-1,32767]");
FScriptPosition::ErrorCounter++;
}
}
if (sc.CheckString("native"))
@ -945,7 +965,7 @@ static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag)
try
{
FActorInfo *info = CreateNewActor(typeName, parentName, native);
FActorInfo *info = CreateNewActor(FScriptPosition(sc), typeName, parentName, native);
info->DoomEdNum = DoomEdNum > 0? DoomEdNum : -1;
SetReplacement(info, replaceName);

View File

@ -1807,25 +1807,18 @@ void WI_drawStats (void)
screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 90, "ITEMS", DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 115, "SECRETS", DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
int slashpos = gameinfo.gametype==GAME_Strife? 235:237;
int countpos = gameinfo.gametype==GAME_Strife? 185:200;
int countpos = gameinfo.gametype==GAME_Strife? 285:270;
if (sp_state >= 2)
{
WI_drawNum (IntermissionFont, countpos, 65, cnt_kills[0], 3, false);
WI_DrawCharPatch (IntermissionFont, '/', slashpos, 65);
WI_drawNum (IntermissionFont, 248, 65, wbs->maxkills, 3, false);
WI_drawPercent (IntermissionFont, countpos, 65, cnt_kills[0], wbs->maxkills);
}
if (sp_state >= 4)
{
WI_drawNum (IntermissionFont, countpos, 90, cnt_items[0], 3, false);
WI_DrawCharPatch (IntermissionFont, '/', slashpos, 90);
WI_drawNum (IntermissionFont, 248, 90, wbs->maxitems, 3, false);
WI_drawPercent (IntermissionFont, countpos, 90, cnt_items[0], wbs->maxitems);
}
if (sp_state >= 6)
{
WI_drawNum (IntermissionFont, countpos, 115, cnt_secret[0], 3, false);
WI_DrawCharPatch (IntermissionFont, '/', slashpos, 115);
WI_drawNum (IntermissionFont, 248, 115, wbs->maxsecret, 3, false);
WI_drawPercent (IntermissionFont, countpos, 115, cnt_secret[0], wbs->maxsecret);
}
if (sp_state >= 8)
{

View File

@ -566,6 +566,7 @@ void I_PrintStr (const char *cp)
// Change the color.
format.cbSize = sizeof(format);
format.dwMask = CFM_COLOR;
format.dwEffects = 0;
format.crTextColor = color;
SendMessage (edit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);
}

File diff suppressed because it is too large Load Diff