From 5b079dd40bbbd83617e62b66c62a04c26dd57023 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 6 Aug 2016 17:47:33 +0300 Subject: [PATCH 01/97] Fixed wrong height of player coordinates text --- src/g_shared/shared_hud.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index c9e87d642..cddc86ee4 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -891,16 +891,16 @@ static void DrawCoordinates(player_t * CPlayer) default: case 0: vwidth = SCREENWIDTH; - vheight = SCREENWIDTH; + vheight = SCREENHEIGHT; break; case 1: case 2: vwidth = SCREENWIDTH/2; - vheight = SCREENWIDTH/2; + vheight = SCREENHEIGHT/2; break; case 3: vwidth = SCREENWIDTH/4; - vheight = SCREENWIDTH/4; + vheight = SCREENHEIGHT/4; break; } From 5a66fdf9be3f2dfac07d80b7761b82a8802ef76d Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Sun, 7 Aug 2016 20:55:16 +0200 Subject: [PATCH 02/97] - Hide Clang -Winconsistent-missing-override warnings in non-Apple targets, too. --- src/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5fe947ef8..f6caa2f5d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -484,8 +484,10 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" ) endif() - if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" ) + if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) + if( APPLE OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "3.6" ) + set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" ) + endif() endif() set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" ) From ab837b608d2ad3dba4f9be2a1749a53f8048d0c9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 7 Aug 2016 22:03:36 +0200 Subject: [PATCH 03/97] - compatibility optioned triggering sector actions by indirectly initiated teleports There's several old maps depending on this not happening. - Set the option for Hell's Twisted Influence Part 1. --- src/compatibility.cpp | 1 + src/d_main.cpp | 3 ++- src/doomdef.h | 1 + src/g_mapinfo.cpp | 1 + src/p_map.cpp | 3 ++- wadsrc/static/compatibility.txt | 5 +++++ 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index ae3b905d0..870d2ede6 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -147,6 +147,7 @@ static FCompatOption Options[] = { "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 }, { "pointonline", COMPATF2_POINTONLINE, SLOT_COMPAT2 }, { "multiexit", COMPATF2_MULTIEXIT, SLOT_COMPAT2 }, + { "teleport", COMPATF2_TELEPORT, SLOT_COMPAT2 }, { NULL, 0, 0 } }; diff --git a/src/d_main.cpp b/src/d_main.cpp index d6d53dd77..4e360a38e 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -574,7 +574,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) case 4: // Old ZDoom compat mode v = COMPATF_SOUNDTARGET | COMPATF_LIGHT; - w = COMPATF2_MULTIEXIT; + w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT; break; case 5: // MBF compat mode @@ -630,6 +630,7 @@ CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE); CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF); CVAR (Flag, compat_pointonline, compatflags2, COMPATF2_POINTONLINE); CVAR (Flag, compat_multiexit, compatflags2, COMPATF2_MULTIEXIT); +CVAR (Flag, compat_teleport, compatflags2, COMPATF2_TELEPORT); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index 56b69fe7c..9ebe45cf7 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -342,6 +342,7 @@ enum : unsigned int COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSideCompat() COMPATF2_MULTIEXIT = 1 << 4, // Level exit can be triggered multiple times (required by Daedalus's travel tubes, thanks to a faulty script) + COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions }; // Emulate old bugs for select maps. These are not exposed by a cvar diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 78ba9142b..7d3df69e0 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1341,6 +1341,7 @@ MapFlagHandlers[] = { "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF }, { "compat_pointonline", MITYPE_COMPATFLAG, 0, COMPATF2_POINTONLINE }, { "compat_multiexit", MITYPE_COMPATFLAG, 0, COMPATF2_MULTIEXIT }, + { "compat_teleport", MITYPE_COMPATFLAG, 0, COMPATF2_TELEPORT }, { "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, diff --git a/src/p_map.cpp b/src/p_map.cpp index 110ae5235..e7aceba78 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -434,7 +434,8 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi // If this teleport was caused by a move, P_TryMove() will handle the // sector transition messages better than we can here. - if (!(thing->flags6 & MF6_INTRYMOVE)) + // This needs to be compatibility optioned because some older maps exploited this missing feature. + if (!(thing->flags6 & MF6_INTRYMOVE) && !(i_compatflags2 & COMPATF2_TELEPORT)) { thing->CheckSectorTransition(oldsec); } diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index a2c3794ae..25395dad6 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -430,6 +430,11 @@ C98F79709BD7E0E4C19026AB9575EC6F // cc-cod.zip:codlev.wad map07 maskedmidtex } +7B82B12A6990E09553B12FDB4E3824A0 // hti.wad map01 +{ + teleport +} + D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9 19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update { From 078881a941958b92d76e10d87370fdc00971801d Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Fri, 5 Aug 2016 17:07:51 +0200 Subject: [PATCH 04/97] Parse statements as expressions in sequences This will be needed for assignment operators to work --- src/thingdef/thingdef_states.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index ecc62bf29..652bdf9e9 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -539,7 +539,8 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B sc.MustGetString(); if (!sc.Compare(";")) { - init = ParseAction(sc, state, statestring, bag); // That's all DECORATE can handle for now. + sc.UnGet(); + init = ParseExpression(sc, bag.Info); sc.MustGetStringName(";"); } sc.MustGetString(); @@ -552,7 +553,8 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B sc.MustGetString(); if (!sc.Compare(")")) { - iter = ParseAction(sc, state, statestring, bag); + sc.UnGet(); + iter = ParseExpression(sc, bag.Info); sc.MustGetStringName(")"); } @@ -641,8 +643,9 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg sc.MustGetString(); } else - { // Handle a regular action function call - add = ParseAction(sc, state, statestring, bag); + { // Handle a regular expression + sc.UnGet(); + add = ParseExpression(sc, bag.Info); sc.MustGetStringName(";"); sc.MustGetString(); } From a4142ad9fba4fb26eea2b60277012d6f78dc7766 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Thu, 4 Aug 2016 02:39:00 +0200 Subject: [PATCH 05/97] Re-allow action function calls with no argument list in sequences --- src/thingdef/thingdef_exp.cpp | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 6a756d9b5..b83796860 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -374,6 +374,29 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) case NAME_Random2: return ParseRandom2(sc, cls); default: + if (cls != nullptr) + { + func = dyn_cast(cls->Symbols.FindSymbol(identifier, true)); + + // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. + if (func != nullptr && identifier != NAME_ACS_NamedExecuteWithResult) + { + args = new FArgumentList; + if (sc.CheckToken('(')) + { + sc.UnGet(); + ParseFunctionParameters(sc, cls, *args, func, "", nullptr); + } + if (args->Size() == 0) + { + delete args; + args = nullptr; + } + + return new FxVMFunctionCall(func, args, sc); + } + } + break; } if (sc.CheckToken('(')) @@ -392,17 +415,9 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) return ParseAtan2(sc, identifier, cls); default: args = new FArgumentList; - func = (cls == nullptr) ? nullptr : dyn_cast(cls->Symbols.FindSymbol(identifier, true)); try { - // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. - if (func != NULL && identifier != NAME_ACS_NamedExecuteWithResult) - { - sc.UnGet(); - ParseFunctionParameters(sc, cls, *args, func, "", NULL); - return new FxVMFunctionCall(func, args, sc); - } - else if (!sc.CheckToken(')')) + if (!sc.CheckToken(')')) { do { From db9f4c13857f785b589bfdb01684c38557611a79 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Fri, 5 Aug 2016 17:26:33 +0200 Subject: [PATCH 06/97] Re-allow indexes as state parameter in sequences --- src/namedef.h | 1 + src/thingdef/thingdef_exp.h | 18 ++++++ src/thingdef/thingdef_expression.cpp | 83 ++++++++++++++++++++++++++++ src/thingdef/thingdef_parse.cpp | 29 ++++++---- 4 files changed, 120 insertions(+), 11 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index cd0d5615b..e5b6c452a 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -654,6 +654,7 @@ xx(DecoCallLineSpecial) xx(DecoNameToClass) xx(DecoFindMultiNameState) xx(DecoFindSingleNameState) +xx(DecoHandleRuntimeState) xx(Damage) // basic type names diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index b878e50f1..c1e8863e8 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -1058,6 +1058,24 @@ public: FxExpression *Resolve(FCompileContext&); }; +//========================================================================== +// +// Same as above except for expressions which means it will have to be +// evaluated at runtime +// +//========================================================================== + +class FxRuntimeStateIndex : public FxExpression +{ + FxExpression *Index; + +public: + FxRuntimeStateIndex(FxExpression *index); + ~FxRuntimeStateIndex(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index b57618575..d40b7605c 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -4428,7 +4428,90 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) delete this; return x; } + +//========================================================================== +// +// +// +//========================================================================== + +FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index) +: FxExpression(index->ScriptPosition), Index(index) +{ + ValueType = TypeState; +} + +FxRuntimeStateIndex::~FxRuntimeStateIndex() +{ + SAFE_DELETE(Index); +} + +FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Index, ctx); + + if (!Index->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Index->ValueType->GetRegType() != REGT_INT) + { // Float. + Index = new FxIntCast(Index); + SAFE_RESOLVE(Index, ctx); + } + + return this; +} + +static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(stateowner, AActor); + PARAM_POINTER(stateinfo, FStateParamInfo); + PARAM_INT(index); + + if (index == 0 || !stateowner->GetClass()->OwnsState(stateinfo->mCallingState + index)) + { + // Null is returned if the location was invalid which means that no jump will be performed + // if used as return value + // 0 always meant the same thing so we handle it here for compatibility + ret->SetPointer(nullptr, ATAG_STATE); + } + else + { + ret->SetPointer(stateinfo->mCallingState + index, ATAG_STATE); + } + + return 1; +} + +ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) +{ + assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); + + ExpEmit out(build, REGT_POINTER); + + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // stateowner + build->Emit(OP_PARAM, 0, REGT_POINTER, 2); // stateinfo + ExpEmit id = Index->Emit(build); + build->Emit(OP_PARAM, 0, REGT_INT | (id.Konst ? REGT_KONST : 0), id.RegNum); // index + + VMFunction *callfunc; + PSymbol *sym; + sym = FindDecorateBuiltinFunction(NAME_DecoHandleRuntimeState, DecoHandleRuntimeState); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); + + return out; +} //========================================================================== // diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 566643b8e..b99f1a384 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -138,23 +138,30 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c else if (type == TypeState) { // This forces quotation marks around the state name. - sc.MustGetToken(TK_StringConst); - if (sc.String[0] == 0 || sc.Compare("None")) + if (sc.CheckToken(TK_StringConst)) { - x = new FxConstant((FState*)NULL, sc); - } - else if (sc.Compare("*")) - { - if (constant) + if (sc.String[0] == 0 || sc.Compare("None")) { - x = new FxConstant((FState*)(intptr_t)-1, sc); + x = new FxConstant((FState*)NULL, sc); + } + else if (sc.Compare("*")) + { + if (constant) + { + x = new FxConstant((FState*)(intptr_t)-1, sc); + } + else sc.ScriptError("Invalid state name '*'"); + } + else + { + x = new FxMultiNameState(sc.String, sc); } - else sc.ScriptError("Invalid state name '*'"); } - else + else if (!constant) { - x = new FxMultiNameState(sc.String, sc); + x = new FxRuntimeStateIndex(ParseExpression(sc, cls)); } + else sc.MustGetToken(TK_StringConst); // This is for the error. } else if (type->GetClass() == RUNTIME_CLASS(PClassPointer)) { // Actor name From 2ef51d0d501dccf4d2151f0a2cc85802e7758153 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Fri, 5 Aug 2016 17:32:01 +0200 Subject: [PATCH 07/97] Re-allow casts in sequences --- src/thingdef/thingdef_exp.cpp | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index b83796860..265917175 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -357,6 +357,49 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) // a cheap way to get them working when people use "name" instead of 'name'. return new FxConstant(FName(sc.String), scpos); } + else if (sc.CheckToken(TK_Bool)) + { + sc.MustGetToken('('); + FxExpression *exp = ParseExpressionM(sc, cls); + sc.MustGetToken(')'); + return new FxBoolCast(exp); + } + else if (sc.CheckToken(TK_Int)) + { + sc.MustGetToken('('); + FxExpression *exp = ParseExpressionM(sc, cls); + sc.MustGetToken(')'); + return new FxIntCast(exp); + } + else if (sc.CheckToken(TK_Float)) + { + sc.MustGetToken('('); + FxExpression *exp = ParseExpressionM(sc, cls); + sc.MustGetToken(')'); + return new FxFloatCast(exp); + } + else if (sc.CheckToken(TK_State)) + { + sc.MustGetToken('('); + FxExpression *exp; + if (sc.CheckToken(TK_StringConst)) + { + if (sc.String[0] == 0 || sc.Compare("None")) + { + exp = new FxConstant((FState*)nullptr, sc); + } + else + { + exp = new FxMultiNameState(sc.String, sc); + } + } + else + { + exp = new FxRuntimeStateIndex(ParseExpressionM(sc, cls)); + } + sc.MustGetToken(')'); + return exp; + } else if (sc.CheckToken(TK_Identifier)) { FName identifier = FName(sc.String); From 8437313e7c2d5d8c2db8419da8c00cf4b0759cdf Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Fri, 5 Aug 2016 17:33:29 +0200 Subject: [PATCH 08/97] Added post/pre increment/decrement operators to DECORATE --- src/dobjtype.h | 1 + src/thingdef/thingdef_data.cpp | 68 ++++---- src/thingdef/thingdef_exp.cpp | 15 +- src/thingdef/thingdef_exp.h | 48 +++++- src/thingdef/thingdef_expression.cpp | 240 ++++++++++++++++++++++++--- 5 files changed, 306 insertions(+), 66 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index 7edf8ca6a..d0ccee746 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -18,6 +18,7 @@ typedef std::pair FTypeAndOffset; #define VARF_Method (1<<1) // func has an implied self parameter #define VARF_Action (1<<2) // func has implied owner and state parameters #define VARF_Native (1<<3) // func is native code/don't auto serialize field +#define VARF_ReadOnly (1<<4) // field is read only, do not write to it // Symbol information ------------------------------------------------------- diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 3b114fbee..8fceca8ee 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -631,38 +631,38 @@ void InitThingdef() // Define some member variables we feel like exposing to the user PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols; PType *array5 = NewArray(TypeSInt32, 5); - symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor,Alpha))); - symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Yaw))); - symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor,args))); - symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native, myoffsetof(AActor,ceilingz))); - symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native, myoffsetof(AActor,floorz))); - symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health))); - symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor,Mass))); - symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Pitch))); - symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Roll))); - symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor,special))); - symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid))); - symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate))); - symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel))); - symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.X))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Y))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Z))); // must remain read-only! - symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native, myoffsetof(AActor,Vel.X))); - symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.X))); - symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); - symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); - symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor,Score))); - symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor,accuracy))); - symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor,stamina))); - symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native, myoffsetof(AActor,Height))); - symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native, myoffsetof(AActor,radius))); - symt.AddSymbol(new PField(NAME_ReactionTime,TypeSInt32, VARF_Native, myoffsetof(AActor,reactiontime))); - symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor,meleerange))); - symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor,Speed))); - symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native, myoffsetof(AActor,threshold))); - symt.AddSymbol(new PField(NAME_DefThreshold,TypeSInt32, VARF_Native, myoffsetof(AActor,DefThreshold))); + symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha))); + symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw))); + symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args))); + symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, ceilingz))); + symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, floorz))); + symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, health))); + symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor, Mass))); + symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Pitch))); + symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Roll))); + symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor, special))); + symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid))); + symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate))); + symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel))); + symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only! + symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); + symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); + symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); + symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); + symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); + symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); + symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); + symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); + symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score))); + symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy))); + symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina))); + symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height))); + symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, radius))); + symt.AddSymbol(new PField(NAME_ReactionTime, TypeSInt32, VARF_Native, myoffsetof(AActor, reactiontime))); + symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange))); + symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed))); + symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold))); + symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold))); } diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 265917175..12dd5957e 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -63,6 +63,7 @@ static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls); // // ParseExpression // [GRB] Parses an expression and stores it into Expression array +// It's worth mentioning that this is using C++ operator precedence // static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls); @@ -257,6 +258,10 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls) case '+': return new FxPlusSign(ParseExpressionA (sc, cls)); + case TK_Incr: + case TK_Decr: + return new FxPreIncrDecr(ParseExpressionA(sc, cls), sc.TokenType); + default: sc.UnGet(); return ParseExpressionA (sc, cls); @@ -312,6 +317,14 @@ static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls) sc.MustGetToken(']'); base_expr = new FxArrayElement(base_expr, index); } + else if (sc.CheckToken(TK_Incr)) + { + return new FxPostIncrDecr(base_expr, TK_Incr); + } + else if (sc.CheckToken(TK_Decr)) + { + return new FxPostIncrDecr(base_expr, TK_Decr); + } else break; } @@ -478,7 +491,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) } break; } - } + } else { return new FxIdentifier(identifier, sc); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index c1e8863e8..25c4b3afb 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -201,7 +201,7 @@ public: virtual FxExpression *Resolve(FCompileContext &ctx); virtual bool isConstant() const; - virtual void RequestAddress(); + virtual bool RequestAddress(); virtual VMFunction *GetDirectFunction(); bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } @@ -469,6 +469,45 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxPreIncrDecr +// +//========================================================================== + +class FxPreIncrDecr : public FxExpression +{ + int Token; + FxExpression *Base; + bool AddressRequested; + bool AddressWritable; + +public: + FxPreIncrDecr(FxExpression *base, int token); + ~FxPreIncrDecr(); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxPostIncrDecr +// +//========================================================================== + +class FxPostIncrDecr : public FxExpression +{ + int Token; + FxExpression *Base; + +public: + FxPostIncrDecr(FxExpression *base, int token); + ~FxPostIncrDecr(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxBinary @@ -753,7 +792,7 @@ public: FxClassMember(FxExpression*, PField*, const FScriptPosition&); ~FxClassMember(); FxExpression *Resolve(FCompileContext&); - void RequestAddress(); + bool RequestAddress(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -796,12 +835,13 @@ class FxArrayElement : public FxExpression public: FxExpression *Array; FxExpression *index; - //bool AddressRequested; + bool AddressRequested; + bool AddressWritable; FxArrayElement(FxExpression*, FxExpression*); ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); - //void RequestAddress(); + bool RequestAddress(); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d40b7605c..63b6be9ca 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -218,13 +218,14 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx) //========================================================================== // -// +// Returns true if we can write to the address. // //========================================================================== -void FxExpression::RequestAddress() +bool FxExpression::RequestAddress() { ScriptPosition.Message(MSG_ERROR, "invalid dereference\n"); + return false; } //========================================================================== @@ -887,6 +888,166 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) return from; } +//========================================================================== +// +// FxPreIncrDecr +// +//========================================================================== + +FxPreIncrDecr::FxPreIncrDecr(FxExpression *base, int token) +: FxExpression(base->ScriptPosition), Base(base), Token(token) +{ + AddressRequested = false; + AddressWritable = false; +} + +FxPreIncrDecr::~FxPreIncrDecr() +{ + SAFE_DELETE(Base); +} + +bool FxPreIncrDecr::RequestAddress() +{ + AddressRequested = true; + return AddressWritable; +} + +FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + + ValueType = Base->ValueType; + + if (!Base->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Base->ValueType == TypeBool) + { + ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); + delete this; + return nullptr; + } + if (!(AddressWritable = Base->RequestAddress())) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + return this; +} + +ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) +{ + assert(Token == TK_Incr || Token == TK_Decr); + assert(ValueType == Base->ValueType && IsNumeric()); + + int zero = build->GetConstantInt(0); + int regtype = ValueType->GetRegType(); + ExpEmit pointer = Base->Emit(build); + + ExpEmit value(build, regtype); + build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero); + + if (regtype == REGT_INT) + { + build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, value.RegNum, value.RegNum, build->GetConstantInt(1)); + } + else + { + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, value.RegNum, value.RegNum, build->GetConstantFloat(1.)); + } + + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, value.RegNum, zero); + + if (AddressRequested) + { + value.Free(build); + return pointer; + } + + pointer.Free(build); + return value; +} + +//========================================================================== +// +// FxPostIncrDecr +// +//========================================================================== + +FxPostIncrDecr::FxPostIncrDecr(FxExpression *base, int token) +: FxExpression(base->ScriptPosition), Base(base), Token(token) +{ +} + +FxPostIncrDecr::~FxPostIncrDecr() +{ + SAFE_DELETE(Base); +} + +FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + + ValueType = Base->ValueType; + + if (!Base->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Base->ValueType == TypeBool) + { + ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); + delete this; + return nullptr; + } + if (!Base->RequestAddress()) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + return this; +} + +ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) +{ + assert(Token == TK_Incr || Token == TK_Decr); + assert(ValueType == Base->ValueType && IsNumeric()); + + int zero = build->GetConstantInt(0); + int regtype = ValueType->GetRegType(); + ExpEmit pointer = Base->Emit(build); + + ExpEmit out(build, regtype); + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero); + + ExpEmit assign(build, regtype); + if (regtype == REGT_INT) + { + build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1)); + } + else + { + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.)); + } + + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero); + + pointer.Free(build); + assign.Free(build); + return out; +} + //========================================================================== // // @@ -2995,9 +3156,10 @@ FxClassMember::~FxClassMember() // //========================================================================== -void FxClassMember::RequestAddress() +bool FxClassMember::RequestAddress() { AddressRequested = true; + return !!(~membervar->Flags & VARF_ReadOnly); } //========================================================================== @@ -3027,6 +3189,17 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) ExpEmit obj = classx->Emit(build); assert(obj.RegType == REGT_POINTER); + if (obj.Konst) + { + // If the situation where we are dereferencing a constant + // pointer is common, then it would probably be worthwhile + // to add new opcodes for those. But as of right now, I + // don't expect it to be a particularly common case. + ExpEmit newobj(build, REGT_POINTER); + build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); + obj = newobj; + } + if (AddressRequested) { if (membervar->Offset == 0) @@ -3040,20 +3213,8 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) } int offsetreg = build->GetConstantInt((int)membervar->Offset); - ExpEmit loc, tmp; + ExpEmit loc(build, membervar->Type->GetRegType()); - if (obj.Konst) - { - // If the situation where we are dereferencing a constant - // pointer is common, then it would probably be worthwhile - // to add new opcodes for those. But as of right now, I - // don't expect it to be a particularly common case. - ExpEmit newobj(build, REGT_POINTER); - build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); - obj = newobj; - } - - loc = ExpEmit(build, membervar->Type->GetRegType()); build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); obj.Free(build); return loc; @@ -3071,7 +3232,8 @@ FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index) { Array=base; index = _index; - //AddressRequested = false; + AddressRequested = false; + AddressWritable = false; } //========================================================================== @@ -3092,12 +3254,11 @@ FxArrayElement::~FxArrayElement() // //========================================================================== -/* -void FxArrayElement::RequestAddress() +bool FxArrayElement::RequestAddress() { AddressRequested = true; + return AddressWritable; } -*/ //========================================================================== // @@ -3145,7 +3306,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) delete this; return NULL; } - Array->RequestAddress(); + AddressWritable = Array->RequestAddress(); return this; } @@ -3159,13 +3320,13 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { ExpEmit start = Array->Emit(build); PArray *const arraytype = static_cast(Array->ValueType); - PType *const elementtype = arraytype->ElementType; - ExpEmit dest(build, elementtype->GetRegType()); + ExpEmit dest(build, arraytype->ElementType->GetRegType()); if (start.Konst) { ExpEmit tmpstart(build, REGT_POINTER); build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); + start.Free(build); start = tmpstart; } if (index->isConstant()) @@ -3176,8 +3337,19 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) I_Error("Array index out of bounds"); } indexval *= arraytype->ElementSize; - build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, - start.RegNum, build->GetConstantInt(indexval)); + + if (AddressRequested) + { + if (indexval != 0) + { + build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval)); + } + } + else + { + build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, + start.RegNum, build->GetConstantInt(indexval)); + } } else { @@ -3193,10 +3365,24 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits); } - build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that - dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register + + if (AddressRequested) + { + build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexv.RegNum); + } + else + { + build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that + dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register + } indexv.Free(build); } + if (AddressRequested) + { + dest.Free(build); + return start; + } + start.Free(build); return dest; } From 90cc79a902002c68f5a910dccee1b9e018024459 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Mon, 1 Aug 2016 00:32:02 +0200 Subject: [PATCH 09/97] Added the direct assignment operator to DECORATE --- src/thingdef/thingdef_exp.cpp | 11 +++- src/thingdef/thingdef_exp.h | 21 +++++++ src/thingdef/thingdef_expression.cpp | 94 ++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 12dd5957e..ffe7bf11a 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -96,18 +96,23 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve) static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) { - FxExpression *condition = ParseExpressionL (sc, cls); + FxExpression *base = ParseExpressionL (sc, cls); if (sc.CheckToken('?')) { FxExpression *truex = ParseExpressionM (sc, cls); sc.MustGetToken(':'); FxExpression *falsex = ParseExpressionM (sc, cls); - return new FxConditional(condition, truex, falsex); + return new FxConditional(base, truex, falsex); + } + else if (sc.CheckToken('=')) + { + FxExpression *right = ParseExpressionM(sc, cls); + return new FxAssign(base, right); } else { - return condition; + return base; } } diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 25c4b3afb..1284f364d 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -508,6 +508,27 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxAssign +// +//========================================================================== + +class FxAssign : public FxExpression +{ + FxExpression *Base; + FxExpression *Right; + bool AddressRequested; + bool AddressWritable; + +public: + FxAssign(FxExpression *base, FxExpression *right); + ~FxAssign(); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxBinary diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 63b6be9ca..34a2c0f95 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1048,6 +1048,100 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) return out; } +//========================================================================== +// +// FxAssign +// +//========================================================================== + +FxAssign::FxAssign(FxExpression *base, FxExpression *right) +: FxExpression(base->ScriptPosition), Base(base), Right(right) +{ + AddressRequested = false; + AddressWritable = false; +} + +FxAssign::~FxAssign() +{ + SAFE_DELETE(Base); + SAFE_DELETE(Right); +} + +bool FxAssign::RequestAddress() +{ + AddressRequested = true; + return AddressWritable; +} + +FxExpression *FxAssign::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + SAFE_RESOLVE(Right, ctx); + + ValueType = Base->ValueType; + + if (!Base->IsNumeric() || !Right->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + if (!(AddressWritable = Base->RequestAddress())) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + if (Right->ValueType != ValueType) + { + if (ValueType == TypeBool) + { + Right = new FxBoolCast(Right); + } + else if (ValueType->GetRegType() == REGT_INT) + { + Right = new FxIntCast(Right); + } + else + { + Right = new FxFloatCast(Right); + } + SAFE_RESOLVE(Right, ctx); + } + + return this; +} + +ExpEmit FxAssign::Emit(VMFunctionBuilder *build) +{ + assert(ValueType == Base->ValueType && IsNumeric()); + assert(ValueType->GetRegType() == Right->ValueType->GetRegType()); + + ExpEmit pointer = Base->Emit(build); + ExpEmit result = Right->Emit(build); + + if (result.Konst) + { + ExpEmit temp(build, result.RegType); + build->Emit(result.RegType == REGT_FLOAT ? OP_LKF : OP_LK, temp.RegNum, result.RegNum); + result.Free(build); + result = temp; + } + + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); + + if (AddressRequested) + { + result.Free(build); + return pointer; + } + + pointer.Free(build); + return result; +} + //========================================================================== // // From e79c0225ed7a635870f1d22e31cc9ad45be5fb2f Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Mon, 1 Aug 2016 03:32:02 +0200 Subject: [PATCH 10/97] Added all compound assignment operators to DECORATE --- src/thingdef/thingdef_exp.cpp | 62 +++++++++++++++++++++++++++- src/thingdef/thingdef_exp.h | 18 ++++++++ src/thingdef/thingdef_expression.cpp | 40 +++++++++++++++++- 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index ffe7bf11a..991e9b947 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -112,7 +112,67 @@ static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) } else { - return base; + FxBinary *exp; + FxAssignSelf *left = new FxAssignSelf(sc); + + sc.GetToken(); + switch (sc.TokenType) + { + case TK_AddEq: + exp = new FxAddSub('+', left, nullptr); + break; + + case TK_SubEq: + exp = new FxAddSub('-', left, nullptr); + break; + + case TK_MulEq: + exp = new FxMulDiv('*', left, nullptr); + break; + + case TK_DivEq: + exp = new FxMulDiv('/', left, nullptr); + break; + + case TK_ModEq: + exp = new FxMulDiv('%', left, nullptr); + break; + + case TK_LShiftEq: + exp = new FxBinaryInt(TK_LShift, left, nullptr); + break; + + case TK_RShiftEq: + exp = new FxBinaryInt(TK_RShift, left, nullptr); + break; + + case TK_URShiftEq: + exp = new FxBinaryInt(TK_URShift, left, nullptr); + break; + + case TK_AndEq: + exp = new FxBinaryInt('&', left, nullptr); + break; + + case TK_XorEq: + exp = new FxBinaryInt('^', left, nullptr); + break; + + case TK_OrEq: + exp = new FxBinaryInt('|', left, nullptr); + break; + + default: + sc.UnGet(); + delete left; + return base; + } + + exp->right = ParseExpressionM(sc, cls); + + FxAssign *ret = new FxAssign(base, exp); + left->Assignment = ret; + return ret; } } diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 1284f364d..7ec542772 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -527,6 +527,24 @@ public: FxExpression *Resolve(FCompileContext&); bool RequestAddress(); ExpEmit Emit(VMFunctionBuilder *build); + + ExpEmit Address; +}; + +//========================================================================== +// +// FxAssignSelf +// +//========================================================================== + +class FxAssignSelf : public FxExpression +{ +public: + FxAssign *Assignment; + + FxAssignSelf(const FScriptPosition &pos); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 34a2c0f95..07f4d9fdf 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1077,10 +1077,11 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(Base, ctx); - SAFE_RESOLVE(Right, ctx); ValueType = Base->ValueType; + SAFE_RESOLVE(Right, ctx); + if (!Base->IsNumeric() || !Right->IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); @@ -1120,8 +1121,10 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build) assert(ValueType->GetRegType() == Right->ValueType->GetRegType()); ExpEmit pointer = Base->Emit(build); - ExpEmit result = Right->Emit(build); + Address = pointer; + ExpEmit result = Right->Emit(build); + if (result.Konst) { ExpEmit temp(build, result.RegType); @@ -1142,6 +1145,39 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build) return result; } +//========================================================================== +// +// FxAssignSelf +// +//========================================================================== + +FxAssignSelf::FxAssignSelf(const FScriptPosition &pos) +: FxExpression(pos) +{ + Assignment = nullptr; +} + +FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + + // This should never happen if FxAssignSelf is used correctly + assert(Assignment != nullptr); + + ValueType = Assignment->ValueType; + + return this; +} + +ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) +{ + assert(ValueType = Assignment->ValueType); + ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it + ExpEmit out(build, ValueType->GetRegType()); + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); + return out; +} + //========================================================================== // // From b97024b710ff796391f0c7dda9606b38d8e4608b Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Tue, 2 Aug 2016 18:50:34 +0200 Subject: [PATCH 11/97] The return statement now accepts any expression as its return value So something like 'return ++user_x;' is now possible Admittedly this needed quite a bit of refactoring mainly due to the fact that return types now have to be checked after resolving the function rather than before --- src/thingdef/thingdef.cpp | 41 ++-- src/thingdef/thingdef.h | 4 +- src/thingdef/thingdef_exp.h | 37 ++-- src/thingdef/thingdef_expression.cpp | 314 ++++++++++++++++++++++----- src/thingdef/thingdef_states.cpp | 152 ++----------- 5 files changed, 327 insertions(+), 221 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 04ac21890..4878adfdf 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -270,23 +270,28 @@ static void FinishThingdef() for (i = 0; i < StateTempCalls.Size(); ++i) { FStateTempCall *tcall = StateTempCalls[i]; - VMFunction *func; + VMFunction *func = nullptr; assert(tcall->Code != NULL); - // Can we call this function directly without wrapping it in an - // anonymous function? e.g. Are we passing any parameters to it? - func = tcall->Code->GetDirectFunction(); - if (func == NULL) - { - FCompileContext ctx(tcall->ActorClass); - tcall->Code = tcall->Code->Resolve(ctx); + // We don't know the return type in advance for anonymous functions. + FCompileContext ctx(tcall->ActorClass, nullptr); + tcall->Code = tcall->Code->Resolve(ctx); + tcall->Proto = ctx.ReturnProto; - // Make sure resolving it didn't obliterate it. - if (tcall->Code != NULL) + // Make sure resolving it didn't obliterate it. + if (tcall->Code != nullptr) + { + // Can we call this function directly without wrapping it in an + // anonymous function? e.g. Are we passing any parameters to it? + func = tcall->Code->GetDirectFunction(); + + if (func == nullptr) { VMFunctionBuilder buildit; + assert(tcall->Proto != nullptr); + // Allocate registers used to pass parameters in. // self, stateowner, state (all are pointers) buildit.Registers[REGT_POINTER].Get(3); @@ -300,15 +305,7 @@ static void FinishThingdef() // Generate prototype for this anonymous function TArray args(3); SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action); - if (tcall->Proto != NULL) - { - sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args); - } - else - { - TArray norets(0); - sfunc->Proto = NewPrototype(norets, args); - } + sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args); func = sfunc; @@ -321,11 +318,9 @@ static void FinishThingdef() codesize += sfunc->CodeSize; } } - } - if (tcall->Code != NULL) - { + delete tcall->Code; - tcall->Code = NULL; + tcall->Code = nullptr; for (int k = 0; k < tcall->NumStates; ++k) { tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 8ad28f098..296383a3d 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -190,10 +190,9 @@ AFuncDesc *FindFunction(const char * string); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef); -FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, PPrototype *&proto, bool &endswithret); +FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret); class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag); FName CheckCastKludges(FName in); -void AddImplicitReturn(class FxSequence *code, const PPrototype *proto, FScanner &sc); void SetImplicitArgs(TArray *args, TArray *argflags, PClassActor *cls, DWORD funcflags); PFunction *FindGlobalActionFunction(const char *name); @@ -356,6 +355,7 @@ int MatchString (const char *in, const char **strings); #define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0) +#define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) #define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0) #define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 7ec542772..2f06e085e 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -62,14 +62,16 @@ class FxJumpStatement; struct FCompileContext { TArray Jumps; + PPrototype *ReturnProto; PClassActor *Class; - FCompileContext(PClassActor *cls = nullptr); + FCompileContext(PClassActor *cls = nullptr, PPrototype *ret = nullptr); PSymbol *FindInClass(FName identifier); PSymbol *FindGlobal(FName identifier); void HandleJumps(int token, FxExpression *handler); + void CheckReturn(PPrototype *proto, FScriptPosition &pos); }; //========================================================================== @@ -170,14 +172,14 @@ struct ExpVal struct ExpEmit { - ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false) {} - ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false) {} - ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false) {} + ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false), Final(false) {} + ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false), Final(false) {} + ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false), Final(false) {} ExpEmit(VMFunctionBuilder *build, int type); void Free(VMFunctionBuilder *build); void Reuse(VMFunctionBuilder *build); - BYTE RegNum, RegType, Konst:1, Fixed:1; + BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1; }; //========================================================================== @@ -202,6 +204,7 @@ public: virtual bool isConstant() const; virtual bool RequestAddress(); + virtual PPrototype *ReturnProto(); virtual VMFunction *GetDirectFunction(); bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } @@ -748,6 +751,7 @@ public: class FxRandom : public FxExpression { protected: + bool EmitTail; FRandom *rng; FxExpression *min, *max; @@ -756,7 +760,7 @@ public: FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); ~FxRandom(); FxExpression *Resolve(FCompileContext&); - + PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -802,6 +806,7 @@ public: class FxRandom2 : public FxExpression { + bool EmitTail; FRandom * rng; FxExpression *mask; @@ -810,7 +815,7 @@ public: FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos); ~FxRandom2(); FxExpression *Resolve(FCompileContext&); - + PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -915,8 +920,9 @@ public: class FxActionSpecialCall : public FxExpression { - FxExpression *Self; int Special; + bool EmitTail; + FxExpression *Self; FArgumentList *ArgList; public: @@ -924,6 +930,7 @@ public: FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos); ~FxActionSpecialCall(); FxExpression *Resolve(FCompileContext&); + PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -954,6 +961,7 @@ public: class FxVMFunctionCall : public FxExpression { + bool EmitTail; PFunction *Function; FArgumentList *ArgList; @@ -961,13 +969,10 @@ public: FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); ~FxVMFunctionCall(); FxExpression *Resolve(FCompileContext&); + PPrototype *ReturnProto(); + VMFunction *GetDirectFunction(); ExpEmit Emit(VMFunctionBuilder *build); - ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®); - unsigned GetArgCount() const { return ArgList == NULL ? 0 : ArgList->Size(); } - PFunction *GetFunction() const { return Function; } - VMFunction *GetVMFunction() const { return Function->Variants[0].Implementation; } - bool IsDirectFunction(); }; //========================================================================== @@ -1089,10 +1094,10 @@ public: class FxReturnStatement : public FxExpression { - FxVMFunctionCall *Call; + FxExpression *Value; public: - FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos); + FxReturnStatement(FxExpression *value, const FScriptPosition &pos); ~FxReturnStatement(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); @@ -1146,12 +1151,14 @@ public: class FxRuntimeStateIndex : public FxExpression { + bool EmitTail; FxExpression *Index; public: FxRuntimeStateIndex(FxExpression *index); ~FxRuntimeStateIndex(); FxExpression *Resolve(FCompileContext&); + PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 07f4d9fdf..4af9e33c9 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -91,7 +91,7 @@ static const FLOP FxFlops[] = // //========================================================================== -FCompileContext::FCompileContext(PClassActor *cls) : Class(cls) +FCompileContext::FCompileContext(PClassActor *cls, PPrototype *ret) : Class(cls), ReturnProto(ret) { } @@ -118,6 +118,50 @@ void FCompileContext::HandleJumps(int token, FxExpression *handler) } } +void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) +{ + assert(proto != nullptr); + bool fail = false; + + if (ReturnProto == nullptr) + { + ReturnProto = proto; + return; + } + + // A prototype that defines fewer return types can be compatible with + // one that defines more if the shorter one matches the initial types + // for the longer one. + if (ReturnProto->ReturnTypes.Size() < proto->ReturnTypes.Size()) + { // Make proto the shorter one to avoid code duplication below. + swapvalues(proto, ReturnProto); + } + // If one prototype returns nothing, they both must. + if (proto->ReturnTypes.Size() == 0) + { + if (ReturnProto->ReturnTypes.Size() != 0) + { + fail = true; + } + } + else + { + for (unsigned i = 0; i < proto->ReturnTypes.Size(); i++) + { + if (ReturnProto->ReturnTypes[i] != proto->ReturnTypes[i]) + { // Incompatible + fail = true; + break; + } + } + } + + if (fail) + { + pos.Message(MSG_ERROR, "All return expressions must deduce to the same type"); + } +} + //========================================================================== // // ExpEmit @@ -125,7 +169,7 @@ void FCompileContext::HandleJumps(int token, FxExpression *handler) //========================================================================== ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) -: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) +: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false), Final(false) { } @@ -228,6 +272,26 @@ bool FxExpression::RequestAddress() return false; } +//========================================================================== +// +// Called by return statements. +// +//========================================================================== + +PPrototype *FxExpression::ReturnProto() +{ + assert(ValueType != nullptr); + + TArray ret(0); + TArray none(0); + if (ValueType != TypeVoid) + { + ret.Push(ValueType); + } + + return NewPrototype(ret, none); +} + //========================================================================== // // @@ -2651,6 +2715,7 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build) FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) : FxExpression(pos) { + EmitTail = false; if (mi != NULL && ma != NULL) { min = new FxIntCast(mi); @@ -2679,6 +2744,18 @@ FxRandom::~FxRandom() // //========================================================================== +PPrototype *FxRandom::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + FxExpression *FxRandom::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); @@ -2706,12 +2783,12 @@ int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, FRandom *rng = reinterpret_cast(param[0].a); if (numparam == 1) { - ret->SetInt((*rng)()); + ACTION_RETURN_INT((*rng)()); } else if (numparam == 2) { int maskval = param[1].i; - ret->SetInt(rng->Random2(maskval)); + ACTION_RETURN_INT(rng->Random2(maskval)); } else if (numparam == 3) { @@ -2720,9 +2797,11 @@ int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, { swapvalues(max, min); } - ret->SetInt((*rng)(max - min + 1) + min); + ACTION_RETURN_INT((*rng)(max - min + 1) + min); } - return 1; + + // Shouldn't happen + return 0; } ExpEmit FxRandom::Emit(VMFunctionBuilder *build) @@ -2735,17 +2814,27 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); if (min != NULL && max != NULL) { EmitParameter(build, min, ScriptPosition); EmitParameter(build, max, ScriptPosition); - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); } else { - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); } + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + ExpEmit out(build, REGT_INT); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); return out; @@ -2952,13 +3041,12 @@ int DecoFRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret { swapvalues(max, min); } - ret->SetFloat(frandom * (max - min) + min); + ACTION_RETURN_FLOAT(frandom * (max - min) + min); } else { - ret->SetFloat(frandom); + ACTION_RETURN_FLOAT(frandom); } - return 1; } ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) @@ -2971,17 +3059,27 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); if (min != NULL && max != NULL) { EmitParameter(build, min, ScriptPosition); EmitParameter(build, max, ScriptPosition); - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); } else { - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); } + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + ExpEmit out(build, REGT_FLOAT); build->Emit(OP_RESULT, 0, REGT_FLOAT, out.RegNum); return out; @@ -2996,6 +3094,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos) : FxExpression(pos) { + EmitTail = false; rng = r; if (m) mask = new FxIntCast(m); else mask = new FxConstant(-1, pos); @@ -3019,6 +3118,18 @@ FxRandom2::~FxRandom2() // //========================================================================== +PPrototype *FxRandom2::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + FxExpression *FxRandom2::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); @@ -3042,9 +3153,19 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); EmitParameter(build, mask, ScriptPosition); - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + ExpEmit out(build, REGT_INT); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); return out; @@ -3623,6 +3744,7 @@ FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgum Self = self; Special = special; ArgList = args; + EmitTail = false; } //========================================================================== @@ -3643,6 +3765,18 @@ FxActionSpecialCall::~FxActionSpecialCall() // //========================================================================== +PPrototype *FxActionSpecialCall::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); @@ -3695,7 +3829,6 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { assert(numparam > 2 && numparam < 8); - assert(numret == 1); assert(param[0].Type == REGT_INT); assert(param[1].Type == REGT_POINTER); int v[5] = { 0 }; @@ -3704,8 +3837,7 @@ int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMRet { v[i - 2] = param[i].i; } - ret->SetInt(P_ExecuteSpecial(param[0].i, NULL, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); - return 1; + ACTION_RETURN_INT(P_ExecuteSpecial(param[0].i, NULL, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); } ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) @@ -3750,6 +3882,14 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; + if (EmitTail) + { + build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 0); + ExpEmit call; + call.Final = true; + return call; + } + ExpEmit dest(build, REGT_INT); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 1); build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum); @@ -3767,6 +3907,7 @@ FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const F { Function = func; ArgList = args; + EmitTail = false; } //========================================================================== @@ -3780,6 +3921,38 @@ FxVMFunctionCall::~FxVMFunctionCall() SAFE_DELETE(ArgList); } +//========================================================================== +// +// +// +//========================================================================== + +PPrototype *FxVMFunctionCall::ReturnProto() +{ + EmitTail = true; + return Function->Variants[0].Implementation->Proto; +} + +//========================================================================== +// +// +// +//========================================================================== + +VMFunction *FxVMFunctionCall::GetDirectFunction() +{ + // If this return statement calls a function with no arguments, + // then it can be a "direct" function. That is, the DECORATE + // definition can call that function directly without wrapping + // it inside VM code. + if (EmitTail && (ArgList ? ArgList->Size() : 0) == 0 && (Function->Flags & VARF_Action)) + { + return Function->Variants[0].Implementation; + } + + return nullptr; +} + //========================================================================== // // FxVMFunctionCall :: Resolve @@ -3809,6 +3982,11 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { ValueType = rets[0]; } + else + { + ValueType = TypeVoid; + } + return this; } @@ -3821,19 +3999,14 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) //========================================================================== ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) -{ - return Emit(build, false); -} - -ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) { assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); - int count = GetArgCount(); + int count = (ArgList ? ArgList->Size() : 0); if (count == 1) { ExpEmit reg; - if (CheckEmitCast(build, tailcall, reg)) + if (CheckEmitCast(build, EmitTail, reg)) { return reg; } @@ -3862,10 +4035,12 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) VMFunction *vmfunc = Function->Variants[0].Implementation; int funcaddr = build->GetConstantAddress(vmfunc, ATAG_OBJECT); // Emit the call - if (tailcall) + if (EmitTail) { // Tail call build->Emit(OP_TAIL_K, funcaddr, count, 0); - return ExpEmit(); + ExpEmit call; + call.Final = true; + return call; } else if (vmfunc->Proto->ReturnTypes.Size() > 0) { // Call, expecting one result @@ -3913,6 +4088,7 @@ bool FxVMFunctionCall::CheckEmitCast(VMFunctionBuilder *build, bool returnit, Ex where.Free(build); } reg = ExpEmit(); + reg.Final = true; } else { @@ -4540,54 +4716,77 @@ ExpEmit FxJumpStatement::Emit(VMFunctionBuilder *build) // //========================================================================== -FxReturnStatement::FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos) -: FxExpression(pos), Call(call) +FxReturnStatement::FxReturnStatement(FxExpression *value, const FScriptPosition &pos) +: FxExpression(pos), Value(value) { + ValueType = TypeVoid; } FxReturnStatement::~FxReturnStatement() { - SAFE_DELETE(Call); + SAFE_DELETE(Value); } FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); - if (Call != NULL) + SAFE_RESOLVE_OPT(Value, ctx); + + PPrototype *retproto; + if (Value == nullptr) { - Call = static_cast(Call->Resolve(ctx)); - ABORT(Call); + TArray none(0); + retproto = NewPrototype(none, none); } + else + { + retproto = Value->ReturnProto(); + } + + ctx.CheckReturn(retproto, ScriptPosition); + return this; } ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) { - // If we return nothing, use a regular RET opcode. If we return - // something, use TAIL to call the function. Our return type - // should be compatible with the called function's return type. - if (Call == NULL) + // If we return nothing, use a regular RET opcode. + // Otherwise just return the value we're given. + if (Value == nullptr) { build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); } else { - Call->Emit(build, true); + ExpEmit ret = Value->Emit(build); + + // Check if it is a function call that simplified itself + // into a tail call in which case we don't emit anything. + if (!ret.Final) + { + if (Value->ValueType == TypeVoid) + { // Nothing is returned. + build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); + } + else + { + build->Emit(OP_RET, RET_FINAL, ret.RegType | (ret.Konst ? REGT_KONST : 0), ret.RegNum); + } + } } - return ExpEmit(); + + ExpEmit out; + out.Final = true; + return out; } VMFunction *FxReturnStatement::GetDirectFunction() { - // If this return statement calls a function with no arguments, - // then it can be a "direct" function. That is, the DECORATE - // definition can call that function directly without wrapping - // it inside VM code. - if (Call != NULL && Call->GetArgCount() == 0 && (Call->GetFunction()->Flags & VARF_Action)) + if (Value != nullptr) { - return Call->GetVMFunction(); + return Value->GetDirectFunction(); } - return NULL; + return nullptr; } //========================================================================== @@ -4754,6 +4953,7 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index) : FxExpression(index->ScriptPosition), Index(index) { + EmitTail = false; ValueType = TypeState; } @@ -4762,6 +4962,12 @@ FxRuntimeStateIndex::~FxRuntimeStateIndex() SAFE_DELETE(Index); } +PPrototype *FxRuntimeStateIndex::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); @@ -4794,14 +5000,12 @@ static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numpa // Null is returned if the location was invalid which means that no jump will be performed // if used as return value // 0 always meant the same thing so we handle it here for compatibility - ret->SetPointer(nullptr, ATAG_STATE); + ACTION_RETURN_STATE(nullptr); } else { - ret->SetPointer(stateinfo->mCallingState + index, ATAG_STATE); + ACTION_RETURN_STATE(stateinfo->mCallingState + index); } - - return 1; } ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) @@ -4823,8 +5027,16 @@ ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); - build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); + if (EmitTail) + { + build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + out.Final = true; + } + else + { + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); + } return out; } diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 652bdf9e9..707de3045 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -315,10 +315,10 @@ do_stop: } bool hasfinalret; - tcall->Code = ParseActions(sc, state, statestring, bag, tcall->Proto, hasfinalret); - if (!hasfinalret) + tcall->Code = ParseActions(sc, state, statestring, bag, hasfinalret); + if (!hasfinalret && tcall->Code != nullptr) { - AddImplicitReturn(static_cast(tcall->Code), tcall->Proto, sc); + static_cast(tcall->Code)->Add(new FxReturnStatement(nullptr, sc)); } goto endofstate; } @@ -351,125 +351,37 @@ endofstate: sc.SetEscape(true); // re-enable escape sequences } -//========================================================================== -// -// AddImplicitReturn -// -// Adds an implied return; statement to the end of a code sequence. -// -//========================================================================== - -void AddImplicitReturn(FxSequence *code, const PPrototype *proto, FScanner &sc) -{ - if (code == NULL) - { - return; - } - if (proto == NULL || proto->ReturnTypes.Size() == 0) - { // Returns nothing. Good. We can safely add an implied return. - code->Add(new FxReturnStatement(NULL, sc)); - } - else - { // Something was returned earlier in the sequence. Make it an error - // instead of adding an implicit one. - sc.ScriptError("Not all paths return a value"); - } -} - -//========================================================================== -// -// ReturnCheck -// -// If proto1 is NULL, returns proto2. If proto2 is NULL, returns proto1. -// If neither is null, checks if both prototypes define the same return -// types. If not, an error is flagged. -// -//========================================================================== - -static PPrototype *ReturnCheck(PPrototype *proto1, PPrototype *proto2, FScanner &sc) -{ - if (proto1 == NULL) - { - return proto2; - } - if (proto2 == NULL) - { - return proto1; - } - // A prototype that defines fewer return types can be compatible with - // one that defines more if the shorter one matches the initial types - // for the longer one. - if (proto2->ReturnTypes.Size() < proto1->ReturnTypes.Size()) - { // Make proto1 the shorter one to avoid code duplication below. - swapvalues(proto1, proto2); - } - // If one prototype returns nothing, they both must. - if (proto1->ReturnTypes.Size() == 0) - { - if (proto2->ReturnTypes.Size() == 0) - { - return proto1; - } - proto1 = NULL; - } - else - { - for (unsigned i = 0; i < proto1->ReturnTypes.Size(); ++i) - { - if (proto1->ReturnTypes[i] != proto2->ReturnTypes[i]) - { // Incompatible - proto1 = NULL; - break; - } - } - } - if (proto1 == NULL) - { - sc.ScriptError("Return types are incompatible"); - } - return proto1; -} - //========================================================================== // // ParseActions // -// If this action block contains any return statements, the prototype for -// one of them will be returned. This is used for deducing the return type -// of anonymous functions. All called functions passed to return must have -// matching return types. -// //========================================================================== -static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &lastwasret) +static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret) { FxExpression *add, *cond; - FxExpression *true_part, *false_part = NULL; - PPrototype *true_proto, *false_proto = NULL; + FxExpression *true_part, *false_part = nullptr; bool true_ret, false_ret = false; sc.MustGetStringName("("); cond = ParseExpression(sc, bag.Info); sc.MustGetStringName(")"); sc.MustGetStringName("{"); // braces are mandatory - true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret); + true_part = ParseActions(sc, state, statestring, bag, true_ret); sc.MustGetString(); if (sc.Compare("else")) { if (sc.CheckString("if")) { - false_part = ParseIf(sc, state, statestring, bag, false_proto, false_ret); + false_part = ParseIf(sc, state, statestring, bag, false_ret); } else { sc.MustGetStringName("{"); // braces are still mandatory - false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret); + false_part = ParseActions(sc, state, statestring, bag, false_ret); sc.MustGetString(); } } add = new FxIfStatement(cond, true_part, false_part, sc); - retproto = ReturnCheck(retproto, true_proto, sc); - retproto = ReturnCheck(retproto, false_proto, sc); // If one side does not end with a return, we don't consider the if statement // to end with a return. If the else case is missing, it can never be considered // as ending with a return. @@ -480,11 +392,9 @@ static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Ba return add; } -static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &lastwasret) +static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret) { FxExpression *cond, *code; - PPrototype *proto; bool ret; sc.MustGetStringName("("); @@ -492,24 +402,21 @@ static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, sc.MustGetStringName(")"); sc.MustGetStringName("{"); // Enforce braces like for if statements. - code = ParseActions(sc, state, statestring, bag, proto, ret); + code = ParseActions(sc, state, statestring, bag, ret); sc.MustGetString(); - retproto = ReturnCheck(retproto, proto, sc); lastwasret = false; // A while loop always jumps back. return new FxWhileLoop(cond, code, sc); } -static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &lastwasret) +static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret) { FxExpression *cond, *code; - PPrototype *proto; bool ret; sc.MustGetStringName("{"); // Enforce braces like for if statements. - code = ParseActions(sc, state, statestring, bag, proto, ret); + code = ParseActions(sc, state, statestring, bag, ret); sc.MustGetStringName("while"); sc.MustGetStringName("("); @@ -518,20 +425,17 @@ static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestrin sc.MustGetStringName(";"); sc.MustGetString(); - retproto = ReturnCheck(retproto, proto, sc); lastwasret = false; return new FxDoWhileLoop(cond, code, sc); } -static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &lastwasret) +static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret) { FxExpression *init = nullptr; FxExpression *cond = nullptr; FxExpression *iter = nullptr; FxExpression *code = nullptr; - PPrototype *proto; bool ret; // Parse the statements. @@ -560,24 +464,21 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B // Now parse the loop's content. sc.MustGetStringName("{"); // Enforce braces like for if statements. - code = ParseActions(sc, state, statestring, bag, proto, ret); + code = ParseActions(sc, state, statestring, bag, ret); sc.MustGetString(); - retproto = ReturnCheck(retproto, proto, sc); lastwasret = false; return new FxForLoop(init, cond, iter, code, sc); } -FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &endswithret) +FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret) { // If it's not a '{', then it should be a single action. // Otherwise, it's a sequence of actions. if (!sc.Compare("{")) { FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag); - retproto = call->GetVMFunction()->Proto; endswithret = true; return new FxReturnStatement(call, sc); } @@ -585,7 +486,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg const FScriptPosition pos(sc); FxSequence *seq = NULL; - PPrototype *proto = NULL; bool lastwasret = false; sc.MustGetString(); @@ -595,38 +495,31 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg lastwasret = false; if (sc.Compare("if")) { // Handle an if statement - add = ParseIf(sc, state, statestring, bag, proto, lastwasret); + add = ParseIf(sc, state, statestring, bag, lastwasret); } else if (sc.Compare("while")) { // Handle a while loop - add = ParseWhile(sc, state, statestring, bag, proto, lastwasret); + add = ParseWhile(sc, state, statestring, bag, lastwasret); } else if (sc.Compare("do")) { // Handle a do-while loop - add = ParseDoWhile(sc, state, statestring, bag, proto, lastwasret); + add = ParseDoWhile(sc, state, statestring, bag, lastwasret); } else if (sc.Compare("for")) { // Handle a for loop - add = ParseFor(sc, state, statestring, bag, proto, lastwasret); + add = ParseFor(sc, state, statestring, bag, lastwasret); } else if (sc.Compare("return")) { // Handle a return statement lastwasret = true; - FxVMFunctionCall *retexp = NULL; - PPrototype *retproto; + FxExpression *retexp = nullptr; sc.MustGetString(); if (!sc.Compare(";")) { - retexp = ParseAction(sc, state, statestring, bag); + sc.UnGet(); + retexp = ParseExpression(sc, bag.Info); sc.MustGetStringName(";"); - retproto = retexp->GetVMFunction()->Proto; } - else - { // Returning nothing; we still need a prototype for that. - TArray notypes(0); - retproto = NewPrototype(notypes, notypes); - } - proto = ReturnCheck(proto, retproto, sc); sc.MustGetString(); add = new FxReturnStatement(retexp, sc); } @@ -660,7 +553,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg } } endswithret = lastwasret; - retproto = proto; return seq; } From d62d345a7bbe3baa583a034e1e2af90760ff92f2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Aug 2016 13:06:29 +0200 Subject: [PATCH 12/97] =?UTF-8?q?-=20fixed:=20The=20cosine=20of=200=C2=B0?= =?UTF-8?q?=20is=201,=20not=200,=20as=20the=20portal=20code=20assumed=20fo?= =?UTF-8?q?r=20linked=20portals.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/portal.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/portal.cpp b/src/portal.cpp index bf919f09a..d7dad220e 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -294,7 +294,8 @@ static void SetRotation(FLinePortal *port) else { // Linked portals have no angular difference. - port->mSinRot = port->mCosRot = 0.; + port->mSinRot = 0.; + port->mCosRot = 1.; port->mAngleDiff = 0.; } } From 19b65195eaf1216750c7252012b99c20d86c8de0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Aug 2016 10:07:06 +0200 Subject: [PATCH 13/97] - added an internal compatibility option to disable setting the line ID for the Plane_Align special. There have been reports for some Skulltag maps a few years back and I just ran across an old beta version of a map that got completely broken by this. --- src/compatibility.cpp | 1 + src/doomdef.h | 1 + src/p_setup.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 870d2ede6..ca5d8293c 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -111,6 +111,7 @@ static FCompatOption Options[] = { "linkfrozenprops", BCOMPATF_LINKFROZENPROPS, SLOT_BCOMPAT }, { "disablepushwindowcheck", BCOMPATF_NOWINDOWCHECK, SLOT_BCOMPAT }, { "floatbob", BCOMPATF_FLOATBOB, SLOT_BCOMPAT }, + { "noslopeid", BCOMPATF_NOSLOPEID, SLOT_BCOMPAT }, // list copied from g_mapinfo.cpp { "shorttex", COMPATF_SHORTTEX, SLOT_COMPAT }, diff --git a/src/doomdef.h b/src/doomdef.h index 9ebe45cf7..a36a7a1c2 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -358,6 +358,7 @@ enum BCOMPATF_LINKFROZENPROPS = 1 << 6, // Clearing PROP_TOTALLYFROZEN or PROP_FROZEN also clears the other BCOMPATF_NOWINDOWCHECK = 1 << 7, // Disable the window check in CheckForPushSpecial() BCOMPATF_FLOATBOB = 1 << 8, // Use Hexen's original method of preventing floatbobbing items from falling down + BCOMPATF_NOSLOPEID = 1 << 9, // disable line IDs on slopes. }; // phares 3/20/98: diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 8a69c2de2..92636fb0c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1959,7 +1959,7 @@ void P_SetLineID (int i, line_t *ld) break; case Plane_Align: - setid = ld->args[2]; + if (!(ib_compatflags & BCOMPATF_NOSLOPEID)) setid = ld->args[2]; break; case Static_Init: From b2a6512981b98840c4068588a13c421699931f52 Mon Sep 17 00:00:00 2001 From: yqco Date: Tue, 9 Aug 2016 02:11:13 -0600 Subject: [PATCH 14/97] Fix partial initialization in ACS PickActor function --- src/p_map.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_map.cpp b/src/p_map.cpp index e7aceba78..ec9fea20a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4439,6 +4439,9 @@ AActor *P_LinePickActor(AActor *t1, DAngle angle, double distance, DAngle pitch, TData.Caller = t1; TData.hitGhosts = true; + TData.MThruSpecies = false; + TData.ThruActors = false; + TData.ThruSpecies = false; if (Trace(t1->PosAtZ(shootz), t1->Sector, direction, distance, actorMask, wallMask, t1, trace, TRACE_NoSky | TRACE_PortalRestrict, CheckForActor, &TData)) From 6b27d0c3ba5ae3cdb24ab621ef2b7c97d6e9418e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Aug 2016 15:11:11 +0200 Subject: [PATCH 15/97] - fixed: FPolyObj::RecalcActorFloorCeil altered the floorz of all actors in the same blockmap block as the polyobject, even when they were nowhere near its bounding box. This fix is still incomplete, it should really discard everything outside the polyobject, not outside its bounding box, but at least it eliminates the most severe occurences of dislocated items. --- src/po_man.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/po_man.cpp b/src/po_man.cpp index 001f308f1..e449e0d67 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1327,6 +1327,17 @@ void FPolyObj::RecalcActorFloorCeil(FBoundingBox bounds) const while ((actor = it.Next()) != NULL) { + // skip everything outside the bounding box. + if (actor->X() + actor->radius <= bounds.Left() || + actor->X() - actor->radius >= bounds.Right() || + actor->Y() + actor->radius <= bounds.Bottom() || + actor->Y() - actor->radius >= bounds.Top()) + { + continue; + } + // Todo: Be a little more thorough with what gets altered here + // because this can dislocate a lot of items that were spawned on + // the lower side of a sector boundary. P_FindFloorCeiling(actor); } } From 7104b011931b0dd936ed57304649f93c7814a149 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Aug 2016 17:09:12 +0200 Subject: [PATCH 16/97] - added Hexen compatible handling to specials that stop perpetual sector movement. This uses the same logic as Eternity. --- src/actionspecials.h | 4 ++-- src/p_ceiling.cpp | 20 +++++++++++++++----- src/p_lnspec.cpp | 34 ++++++++++++++++++++++++++++++---- src/p_plats.cpp | 12 +++++++++--- src/p_spec.h | 8 ++++---- 5 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 4ab222b2c..9b9c38cb9 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -42,7 +42,7 @@ DEFINE_SPECIAL(Ceiling_LowerByValue, 40, 3, 5, 5) DEFINE_SPECIAL(Ceiling_RaiseByValue, 41, 3, 4, 4) DEFINE_SPECIAL(Ceiling_CrushAndRaise, 42, 3, 4, 4) DEFINE_SPECIAL(Ceiling_LowerAndCrush, 43, 3, 4, 4) -DEFINE_SPECIAL(Ceiling_CrushStop, 44, 1, 1, 1) +DEFINE_SPECIAL(Ceiling_CrushStop, 44, 1, 2, 2) DEFINE_SPECIAL(Ceiling_CrushRaiseAndStay, 45, 3, 4, 4) DEFINE_SPECIAL(Floor_CrushStop, 46, 1, 1, 1) DEFINE_SPECIAL(Ceiling_MoveToValue, 47, 3, 5, 5) @@ -59,7 +59,7 @@ DEFINE_SPECIAL(Sector_SetPortal, 57, -1, -1, 5) DEFINE_SPECIAL(Sector_CopyScroller, 58, -1, -1, 2) DEFINE_SPECIAL(Polyobj_OR_MoveToSpot, 59, 3, 3, 3) DEFINE_SPECIAL(Plat_PerpetualRaise, 60, 3, 3, 3) -DEFINE_SPECIAL(Plat_Stop, 61, 1, 1, 1) +DEFINE_SPECIAL(Plat_Stop, 61, 1, 2, 2) DEFINE_SPECIAL(Plat_DownWaitUpStay, 62, 3, 3, 3) DEFINE_SPECIAL(Plat_DownByValue, 63, 4, 4, 4) DEFINE_SPECIAL(Plat_UpWaitDownStay, 64, 3, 3, 3) diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index c635d9743..888b67b6c 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -552,21 +552,31 @@ void P_ActivateInStasisCeiling (int tag) // //============================================================================ -bool EV_CeilingCrushStop (int tag) +bool EV_CeilingCrushStop (int tag, bool remove) { bool rtn = false; DCeiling *scan; TThinkerIterator iterator; - while ( (scan = iterator.Next ()) ) + scan = iterator.Next(); + while (scan != nullptr) { + DCeiling *next = iterator.Next(); if (scan->m_Tag == tag && scan->m_Direction != 0) { - SN_StopSequence (scan->m_Sector, CHAN_CEILING); - scan->m_OldDirection = scan->m_Direction; - scan->m_Direction = 0; // in-stasis; + if (!remove) + { + SN_StopSequence(scan->m_Sector, CHAN_CEILING); + scan->m_OldDirection = scan->m_Direction; + scan->m_Direction = 0; // in-stasis; + } + else + { + scan->Destroy(); + } rtn = true; } + scan = next; } return rtn; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index d0a56ee87..c8c7db74d 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -686,9 +686,22 @@ FUNC(LS_Ceiling_LowerAndCrushDist) } FUNC(LS_Ceiling_CrushStop) -// Ceiling_CrushStop (tag) +// Ceiling_CrushStop (tag, remove) { - return EV_CeilingCrushStop (arg0); + bool remove; + switch (arg3) + { + case 1: + remove = false; + break; + case 2: + remove = true; + break; + default: + remove = gameinfo.gametype == GAME_Hexen; + break; + } + return EV_CeilingCrushStop (arg0, remove); } FUNC(LS_Ceiling_CrushRaiseAndStay) @@ -890,9 +903,22 @@ FUNC(LS_Plat_PerpetualRaiseLip) } FUNC(LS_Plat_Stop) -// Plat_Stop (tag) +// Plat_Stop (tag, remove?) { - EV_StopPlat (arg0); + bool remove; + switch (arg3) + { + case 1: + remove = false; + break; + case 2: + remove = true; + break; + default: + remove = gameinfo.gametype == GAME_Hexen; + break; + } + EV_StopPlat(arg0, remove); return true; } diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 55ba39fe5..96fec71c1 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -429,15 +429,21 @@ void DPlat::Stop () m_Status = in_stasis; } -void EV_StopPlat (int tag) +void EV_StopPlat (int tag, bool remove) { DPlat *scan; TThinkerIterator iterator; - while ( (scan = iterator.Next ()) ) + scan = iterator.Next(); + while (scan != nullptr) { + DPlat *next = iterator.Next(); if (scan->m_Status != DPlat::in_stasis && scan->m_Tag == tag) - scan->Stop (); + { + if (!remove) scan->Stop(); + else scan->Destroy(); + } + scan = next; } } diff --git a/src/p_spec.h b/src/p_spec.h index 125b2374e..d7abd4b42 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -212,13 +212,13 @@ private: friend bool EV_DoPlat (int tag, line_t *line, EPlatType type, double height, double speed, int delay, int lip, int change); - friend void EV_StopPlat (int tag); + friend void EV_StopPlat (int tag, bool remove); friend void P_ActivateInStasis (int tag); }; bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, double height, double speed, int delay, int lip, int change); -void EV_StopPlat (int tag); +void EV_StopPlat (int tag, bool remove); void P_ActivateInStasis (int tag); // @@ -434,14 +434,14 @@ private: DCeiling (); friend bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush); - friend bool EV_CeilingCrushStop (int tag); + friend bool EV_CeilingCrushStop (int tag, bool remove); friend void P_ActivateInStasisCeiling (int tag); }; bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush); bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush = DCeiling::ECrushMode::crushDoom); -bool EV_CeilingCrushStop (int tag); +bool EV_CeilingCrushStop (int tag, bool remove); void P_ActivateInStasisCeiling (int tag); From b4e712ab019f13a33f718c95b7d1afcc5fb54acf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Aug 2016 20:15:13 +0200 Subject: [PATCH 17/97] - made disabling the push window check a real compatibility option. No idea why this was a hidden one, this one definitely needs to be in the menu. - set some required compatibility options for Super Sonic Doom. --- src/compatibility.cpp | 2 +- src/d_main.cpp | 3 ++- src/doomdef.h | 4 ++-- src/g_mapinfo.cpp | 1 + src/p_map.cpp | 2 +- wadsrc/static/compatibility.txt | 12 ++++++++++++ wadsrc/static/language.enu | 2 ++ wadsrc/static/menudef.txt | 2 ++ 8 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index ca5d8293c..5bb51129a 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -109,7 +109,6 @@ static FCompatOption Options[] = { "ignoreteleporttags", BCOMPATF_BADTELEPORTERS, SLOT_BCOMPAT }, { "rebuildnodes", BCOMPATF_REBUILDNODES, SLOT_BCOMPAT }, { "linkfrozenprops", BCOMPATF_LINKFROZENPROPS, SLOT_BCOMPAT }, - { "disablepushwindowcheck", BCOMPATF_NOWINDOWCHECK, SLOT_BCOMPAT }, { "floatbob", BCOMPATF_FLOATBOB, SLOT_BCOMPAT }, { "noslopeid", BCOMPATF_NOSLOPEID, SLOT_BCOMPAT }, @@ -149,6 +148,7 @@ static FCompatOption Options[] = { "pointonline", COMPATF2_POINTONLINE, SLOT_COMPAT2 }, { "multiexit", COMPATF2_MULTIEXIT, SLOT_COMPAT2 }, { "teleport", COMPATF2_TELEPORT, SLOT_COMPAT2 }, + { "disablepushwindowcheck", COMPATF2_PUSHWINDOW, SLOT_COMPAT2 }, { NULL, 0, 0 } }; diff --git a/src/d_main.cpp b/src/d_main.cpp index 4e360a38e..9f4568614 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -574,7 +574,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) case 4: // Old ZDoom compat mode v = COMPATF_SOUNDTARGET | COMPATF_LIGHT; - w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT; + w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT | COMPATF2_PUSHWINDOW; break; case 5: // MBF compat mode @@ -631,6 +631,7 @@ CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF); CVAR (Flag, compat_pointonline, compatflags2, COMPATF2_POINTONLINE); CVAR (Flag, compat_multiexit, compatflags2, COMPATF2_MULTIEXIT); CVAR (Flag, compat_teleport, compatflags2, COMPATF2_TELEPORT); +CVAR (Flag, compat_pushwindow, compatflags2, COMPATF2_PUSHWINDOW); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index a36a7a1c2..5a1d1f95f 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -342,7 +342,8 @@ enum : unsigned int COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSideCompat() COMPATF2_MULTIEXIT = 1 << 4, // Level exit can be triggered multiple times (required by Daedalus's travel tubes, thanks to a faulty script) - COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions + COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions + COMPATF2_PUSHWINDOW = 1 << 6, // Disable the window check in CheckForPushSpecial() }; // Emulate old bugs for select maps. These are not exposed by a cvar @@ -356,7 +357,6 @@ enum BCOMPATF_BADPORTALS = 1 << 4, // Restores the old unstable portal behavior BCOMPATF_REBUILDNODES = 1 << 5, // Force node rebuild BCOMPATF_LINKFROZENPROPS = 1 << 6, // Clearing PROP_TOTALLYFROZEN or PROP_FROZEN also clears the other - BCOMPATF_NOWINDOWCHECK = 1 << 7, // Disable the window check in CheckForPushSpecial() BCOMPATF_FLOATBOB = 1 << 8, // Use Hexen's original method of preventing floatbobbing items from falling down BCOMPATF_NOSLOPEID = 1 << 9, // disable line IDs on slopes. }; diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 7d3df69e0..ac1552b99 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1342,6 +1342,7 @@ MapFlagHandlers[] = { "compat_pointonline", MITYPE_COMPATFLAG, 0, COMPATF2_POINTONLINE }, { "compat_multiexit", MITYPE_COMPATFLAG, 0, COMPATF2_MULTIEXIT }, { "compat_teleport", MITYPE_COMPATFLAG, 0, COMPATF2_TELEPORT }, + { "compat_pushwindow", MITYPE_COMPATFLAG, 0, COMPATF2_PUSHWINDOW }, { "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, diff --git a/src/p_map.cpp b/src/p_map.cpp index ec9fea20a..278249a64 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1912,7 +1912,7 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, DVector2 * { if (line->special && !(mobj->flags6 & MF6_NOTRIGGER)) { - if (posforwindowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL) + if (posforwindowcheck && !(i_compatflags2 & COMPATF2_PUSHWINDOW) && line->backsector != NULL) { // Make sure this line actually blocks us and is not a window // or similar construct we are standing inside of. DVector3 pos = mobj->PosRelative(line); diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 25395dad6..d964cbf75 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -397,6 +397,7 @@ D62DCA9EC226DE49108D5DD9271F7631 // Cheogsh 2 map04 E89CCC7E155F1032F693359CC219BE6C // hexen.wad map30 B9DFF13207EACAC675C71D82624D0007 // XtheaterIII map01 +6941BDC2F80C0FEBE34EFA23D5FB72B7 // sonic.wad map10 { DisablePushWindowCheck } @@ -435,6 +436,17 @@ C98F79709BD7E0E4C19026AB9575EC6F // cc-cod.zip:codlev.wad map07 teleport } +8570AA0D6737C0A19DB66767764F157F // sonic.wad map04 +{ + noslopeid +} + +05AA32F1D2220A462DCDA245ED22B94B // sonic.wad map09 +{ + polyobj +} + + D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9 19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update { diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 03a3ffb1a..03212768e 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2069,6 +2069,8 @@ CMPTMNU_SILENTINSTANTFLOORS = "Inst. moving floors are not silent"; CMPTMNU_SECTORSOUNDS = "Sector sounds use center as source"; CMPTMNU_SOUNDCUTOFF = "Sounds stop when actor vanishes"; CMPTMNU_SOUNDTARGET = "Use original sound target handling"; +CMPTMNU_TELEPORT = "Scripted teleports don't trigger sector actions"; +CMPTMNU_PUSHWINDOW = "Non-blocking lines can be pushed"; // Sound Options SNDMNU_TITLE = "SOUND OPTIONS"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index ca36c1975..077dc0608 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1320,6 +1320,8 @@ OptionMenu "CompatibilityOptions" Option "$CMPTMNU_FLOORMOVE", "compat_floormove", "YesNo" Option "$CMPTMNU_POINTONLINE", "compat_pointonline", "YesNo" Option "$CMPTMNU_MULTIEXIT", "compat_multiexit", "YesNo" + Option "$CMPTMNU_TELEPORT", "compat_teleport", "YesNo" + Option "$CMPTMNU_PUSHWINDOW", "compat_pushwindow", "YesNo" StaticText " " StaticText "$CMPTMNU_PHYSICSBEHAVIOR",1 From 054f5c963e4cbcdfd466c4232f8fff7d1d5a4cb7 Mon Sep 17 00:00:00 2001 From: yqco Date: Thu, 11 Aug 2016 04:22:37 -0600 Subject: [PATCH 18/97] Use verbose error message with DECORATE array indices --- src/thingdef/thingdef_expression.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 4af9e33c9..61660ffa8 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3548,6 +3548,16 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) delete this; return NULL; } + if (index->isConstant()) + { + unsigned indexval = static_cast(index)->GetValue().GetInt(); + if (indexval >= arraytype->ElementCount) + { + ScriptPosition.Message(MSG_ERROR, "Array index out of bounds"); + delete this; + return NULL; + } + } ValueType = arraytype->ElementType; if (ValueType->GetRegType() != REGT_INT && ValueType->GetRegType() != REGT_FLOAT) @@ -3583,10 +3593,6 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) if (index->isConstant()) { unsigned indexval = static_cast(index)->GetValue().GetInt(); - if (indexval >= arraytype->ElementCount) - { - I_Error("Array index out of bounds"); - } indexval *= arraytype->ElementSize; if (AddressRequested) From ee7d933ed6a0477426a6f1840bdee034f7cd4810 Mon Sep 17 00:00:00 2001 From: yqco Date: Thu, 11 Aug 2016 04:47:17 -0600 Subject: [PATCH 19/97] Add assert for previous I_Error condition --- src/thingdef/thingdef_expression.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 61660ffa8..00c4b1e75 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3593,6 +3593,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) if (index->isConstant()) { unsigned indexval = static_cast(index)->GetValue().GetInt(); + assert(indexval < arraytype->ElementCount && "Array index out of bounds"); indexval *= arraytype->ElementSize; if (AddressRequested) From ec14dd94a731e17a96079f70c7cc9333ebc2a57e Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Mon, 8 Aug 2016 13:01:43 -0500 Subject: [PATCH 20/97] A_Explode now returns the number of actors damaged and can be used in expressions. - Enemies that do not take damage in any way are not counted. --- src/p_interaction.cpp | 25 +++++++++++++------------ src/p_local.h | 2 +- src/p_map.cpp | 14 ++++++++++++-- src/thingdef/thingdef_codeptr.cpp | 4 ++-- wadsrc/static/actors/actor.txt | 2 +- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 9f50c9ab5..261cfb8f3 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -948,7 +948,8 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, bool forcedPain = false; int fakeDamage = 0; int holdDamage = 0; - const int rawdamage = damage; + const int rawdamage = damage; + const bool telefragDamage = (rawdamage >= TELEFRAG_DAMAGE); if (damage < 0) damage = 0; @@ -962,7 +963,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, forcedPain = (MustForcePain(target, inflictor)); // Spectral targets only take damage from spectral projectiles. - if (target->flags4 & MF4_SPECTRAL && damage < TELEFRAG_DAMAGE) + if (target->flags4 & MF4_SPECTRAL && !telefragDamage) { if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL)) { @@ -987,7 +988,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, // different here. At any rate, invulnerable is being checked before type factoring, which is then being // checked by player cheats/invul/buddha followed by monster buddha. This is inconsistent. Don't let the // original telefrag damage CHECK (rawdamage) be influenced by outside factors when looking at cheats/invul. - if ((target->flags2 & MF2_INVULNERABLE) && (rawdamage < TELEFRAG_DAMAGE) && (!(flags & DMG_FORCED))) + if ((target->flags2 & MF2_INVULNERABLE) && !telefragDamage && (!(flags & DMG_FORCED))) { // actor is invulnerable if (target->player == NULL) { @@ -1046,7 +1047,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, return -1; } - if ((rawdamage < TELEFRAG_DAMAGE) || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect. + if (!telefragDamage || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect. { if (player && damage > 1) { @@ -1214,19 +1215,19 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, target->IsTeammate (source)) { //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it. - if (rawdamage < TELEFRAG_DAMAGE || (target->flags7 & MF7_LAXTELEFRAGDMG)) + if (!telefragDamage || (target->flags7 & MF7_LAXTELEFRAGDMG)) { // Still allow telefragging :-( damage = (int)(damage * level.teamdamage); if (damage < 0) { return damage; - } + } else if (damage == 0) { if (forcedPain) { goto dopain; - } + } else if (fakedPain) { goto fakepain; @@ -1256,7 +1257,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, if (!(flags & DMG_FORCED)) { // check the real player, not a voodoo doll here for invulnerability effects - if ((rawdamage < TELEFRAG_DAMAGE && ((player->mo->flags2 & MF2_INVULNERABLE) || + if ((!telefragDamage && ((player->mo->flags2 & MF2_INVULNERABLE) || (player->cheats & CF_GODMODE))) || (player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NODAMAGE)) //Absolutely no hurting if NODAMAGE is involved. Same for GODMODE2. @@ -1281,7 +1282,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, { player->mo->Inventory->AbsorbDamage(damage, mod, newdam); } - if ((rawdamage < TELEFRAG_DAMAGE) || (player->mo->flags7 & MF7_LAXTELEFRAGDMG)) //rawdamage is never modified. + if (!telefragDamage || (player->mo->flags7 & MF7_LAXTELEFRAGDMG)) //rawdamage is never modified. { // if we are telefragging don't let the damage value go below that magic value. Some further checks would fail otherwise. damage = newdam; @@ -1306,7 +1307,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } } - if (damage >= player->health && rawdamage < TELEFRAG_DAMAGE + if (damage >= player->health && !telefragDamage && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) && !player->morphTics) { // Try to use some inventory health @@ -1330,7 +1331,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, // but telefragging should still do enough damage to kill the player) // Ignore players that are already dead. // [MC]Buddha2 absorbs telefrag damage, and anything else thrown their way. - if (!(flags & DMG_FORCED) && (((player->cheats & CF_BUDDHA2) || (((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA)) && (rawdamage < TELEFRAG_DAMAGE))) && (player->playerstate != PST_DEAD))) + if (!(flags & DMG_FORCED) && (((player->cheats & CF_BUDDHA2) || (((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA)) && !telefragDamage)) && (player->playerstate != PST_DEAD))) { // If this is a voodoo doll we need to handle the real player as well. player->mo->health = target->health = player->health = 1; @@ -1395,7 +1396,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, if (target->health <= 0) { //[MC]Buddha flag for monsters. - if (!(flags & DMG_FORCED) && ((target->flags7 & MF7_BUDDHA) && (rawdamage < TELEFRAG_DAMAGE) && ((inflictor == NULL || !(inflictor->flags7 & MF7_FOILBUDDHA)) && !(flags & DMG_FOILBUDDHA)))) + if (!(flags & DMG_FORCED) && ((target->flags7 & MF7_BUDDHA) && !telefragDamage && ((inflictor == NULL || !(inflictor->flags7 & MF7_FOILBUDDHA)) && !(flags & DMG_FOILBUDDHA)))) { //FOILBUDDHA or Telefrag damage must kill it. target->health = 1; } diff --git a/src/p_local.h b/src/p_local.h index ebbaeace5..d759828dc 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -392,7 +392,7 @@ enum RADF_NODAMAGE = 8, RADF_THRUSTZ = 16, }; -void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, +int P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, FName damageType, int flags, int fulldamagedistance=0); void P_DelSector_List(); diff --git a/src/p_map.cpp b/src/p_map.cpp index 278249a64..7316e1c96 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5245,11 +5245,11 @@ CUSTOM_CVAR(Float, splashfactor, 1.f, CVAR_SERVERINFO) // //========================================================================== -void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bombdistance, FName bombmod, +int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bombdistance, FName bombmod, int flags, int fulldamagedistance) { if (bombdistance <= 0) - return; + return 0; fulldamagedistance = clamp(fulldamagedistance, 0, bombdistance - 1); double bombdistancefloat = 1. / (double)(bombdistance - fulldamagedistance); @@ -5264,6 +5264,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo bombsource = bombspot; } + int count = 0; while ((it.Next(&cres))) { AActor *thing = cres.thing; @@ -5359,7 +5360,12 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo int newdam = damage; if (!(flags & RADF_NODAMAGE)) + { + //[MC] Don't count actors saved by buddha if already at 1 health. + int prehealth = thing->health; newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod); + if (thing->health < prehealth) count++; + } else if (thing->player == NULL && (!(flags & RADF_NOIMPACTDAMAGE) && !(thing->flags7 & MF7_DONTTHRUST))) thing->flags2 |= MF2_BLASTED; @@ -5425,12 +5431,16 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo damage = int(damage * factor); if (damage > 0) { + //[MC] Don't count actors saved by buddha if already at 1 health. + int prehealth = thing->health; int newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod); P_TraceBleed(newdam > 0 ? newdam : damage, thing, bombspot); + if (thing->health < prehealth) count++; } } } } + return count; } //========================================================================== diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 6904a05d4..07d6f508b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1414,13 +1414,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) } } - P_RadiusAttack (self, self->target, damage, distance, self->DamageType, flags, fulldmgdistance); + int count = P_RadiusAttack (self, self->target, damage, distance, self->DamageType, flags, fulldmgdistance); P_CheckSplash(self, distance); if (alert && self->target != NULL && self->target->player != NULL) { P_NoiseAlert(self->target, self); } - return 0; + ACTION_RETURN_INT(count); } //========================================================================== diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index fa8932050..c80834fdc 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -253,7 +253,7 @@ ACTOR Actor native //: Thinker action native A_Blast(int flags = 0, float strength = 255, float radius = 255, float speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius"); action native A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0); action native A_RadiusDamageSelf(int damage = 128, float distance = 128, int flags = 0, class flashtype = "None"); - action native A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff"); + action native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff"); action native A_Stop(); action native A_Respawn(int flags = 1); action native A_BarrelDestroy(); From 7ffccd0009086f97c69a374b4e7e2ccb441af30c Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Tue, 9 Aug 2016 16:09:24 -0500 Subject: [PATCH 21/97] Fixed: RGF_KILLED was not part of the mask. - Greatly optimized DoRadiusGive by putting actor flag checking first ahead of pointer, classname and species checking. --- src/thingdef/thingdef_codeptr.cpp | 85 ++++++++++++++++++------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 07d6f508b..1acf951fe 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5888,24 +5888,64 @@ enum RadiusGiveFlags RGF_OBJECTS | RGF_VOODOO | RGF_CORPSES | + RGF_KILLED | RGF_MISSILES | RGF_ITEMS, }; static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amount, double distance, int flags, PClassActor *filter, FName species, double mindist) { - // [MC] We only want to make an exception for missiles here. Nothing else. - bool missilePass = !!((flags & RGF_MISSILES) && thing->flags & MF_MISSILE); + + bool doPass = false; + // Always allow self to give, no matter what other flags are specified. Otherwise, not at all. if (thing == self) { if (!(flags & RGF_GIVESELF)) return false; + doPass = true; } else if (thing->flags & MF_MISSILE) { - if (!missilePass) + if (!(flags & RGF_MISSILES)) return false; + doPass = true; } + else if (((flags & RGF_ITEMS) && thing->IsKindOf(RUNTIME_CLASS(AInventory))) || + ((flags & RGF_MISSILES) && thing->flags & MF_MISSILE) || + ((flags & RGF_CORPSES) && thing->flags & MF_CORPSE) || + ((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED)) + { + doPass = true; + } + else if ((flags & (RGF_MONSTERS | RGF_OBJECTS | RGF_PLAYERS | RGF_VOODOO))) + { + // Make sure it's alive as we're not looking for corpses or killed here. + if (!doPass && thing->health > 0) + { + if (thing->player != nullptr) + { + if (((flags & RGF_PLAYERS) && (thing->player->mo == thing)) || + ((flags & RGF_VOODOO) && (thing->player->mo != thing))) + { + doPass = true; + } + } + else + { + if (((flags & RGF_MONSTERS) && (thing->flags3 & MF3_ISMONSTER)) || + ((flags & RGF_OBJECTS) && (!(thing->flags3 & MF3_ISMONSTER)) && + (thing->flags & MF_SHOOTABLE || thing->flags6 & MF6_VULNERABLE))) + { + doPass = true; + } + } + } + } + + // Nothing matched up so don't bother with the rest. + if (!doPass) + return false; + //[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s). bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)), speciespass = DoCheckSpecies(thing, species, !!(flags & RGF_EXSPECIES)); @@ -5916,13 +5956,14 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo return false; } - //Check for target, master, and tracer flagging. - bool targetPass = true; - bool masterPass = true; - bool tracerPass = true; - bool ptrPass = false; if ((thing != self) && (flags & (RGF_NOTARGET | RGF_NOMASTER | RGF_NOTRACER))) { + //Check for target, master, and tracer flagging. + bool targetPass = true; + bool masterPass = true; + bool tracerPass = true; + bool ptrPass = false; + if ((thing == self->target) && (flags & RGF_NOTARGET)) targetPass = false; if ((thing == self->master) && (flags & RGF_NOMASTER)) @@ -5937,33 +5978,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo return false; } - //Next, actor flag checking. - bool selfPass = !!((flags & RGF_GIVESELF) && thing == self); - bool corpsePass = !!((flags & RGF_CORPSES) && thing->flags & MF_CORPSE); - bool killedPass = !!((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED); - bool monsterPass = !!((flags & RGF_MONSTERS) && thing->flags3 & MF3_ISMONSTER); - bool objectPass = !!((flags & RGF_OBJECTS) && (thing->player == NULL) && (!(thing->flags3 & MF3_ISMONSTER)) - && ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE))); - bool playerPass = !!((flags & RGF_PLAYERS) && (thing->player != NULL) && (thing->player->mo == thing)); - bool voodooPass = !!((flags & RGF_VOODOO) && (thing->player != NULL) && (thing->player->mo != thing)); - //Self calls priority over the rest of this. - if (!selfPass) - { - //If it's specifically a monster/object/player/voodoo... Can be either or... - if (monsterPass || objectPass || playerPass || voodooPass) - { - //...and is dead, without desire to give to the dead... - if (((thing->health <= 0) && !(corpsePass || killedPass))) - { - //Skip! - return false; - } - } - } - - bool itemPass = !!((flags & RGF_ITEMS) && thing->IsKindOf(RUNTIME_CLASS(AInventory))); - - if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass) + if (doPass) { DVector3 diff = self->Vec3To(thing); From 9dd458030e04833fb7f3500ec0a376a7aa0ca69c Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Tue, 9 Aug 2016 16:25:53 -0500 Subject: [PATCH 22/97] This isn't needed. It's already checked at this point. --- src/thingdef/thingdef_codeptr.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 1acf951fe..b0cfbeba4 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5911,7 +5911,6 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo doPass = true; } else if (((flags & RGF_ITEMS) && thing->IsKindOf(RUNTIME_CLASS(AInventory))) || - ((flags & RGF_MISSILES) && thing->flags & MF_MISSILE) || ((flags & RGF_CORPSES) && thing->flags & MF_CORPSE) || ((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED)) { @@ -5980,7 +5979,6 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo if (doPass) { - DVector3 diff = self->Vec3To(thing); diff.Z += thing->Height *0.5; if (flags & RGF_CUBE) From a0d66be6e99ded09c635806df89bffc5436f288a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 14 Aug 2016 20:52:13 +0200 Subject: [PATCH 23/97] - fixed: Terrain splashes could be generated for 3D floors that were below the sector's actual floor. --- src/p_trace.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 16fff3fbe..b82ac0f5a 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -303,9 +303,13 @@ void FTraceInfo::Setup3DFloors() { if (Check3DFloorPlane(rover, false)) { - Results->Crossed3DWater = rover; - Results->Crossed3DWaterPos = Results->HitPos; - Results->Distance = 0; + // only consider if the plane is above the actual floor. + if (rover->top.plane->ZatPoint(Results->HitPos) > bf) + { + Results->Crossed3DWater = rover; + Results->Crossed3DWaterPos = Results->HitPos; + Results->Distance = 0; + } } } @@ -766,9 +770,13 @@ bool FTraceInfo::TraceTraverse (int ptflags) { if (Check3DFloorPlane(rover, false)) { - Results->Crossed3DWater = rover; - Results->Crossed3DWaterPos = Results->HitPos; - Results->Distance = 0; + // only consider if the plane is above the actual floor. + if (rover->top.plane->ZatPoint(Results->HitPos) > CurSector->floorplane.ZatPoint(Results->HitPos)) + { + Results->Crossed3DWater = rover; + Results->Crossed3DWaterPos = Results->HitPos; + Results->Distance = 0; + } } } } From 47d2fd403c7d96ade90225fd3dbb56a848f0357b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 14 Aug 2016 21:55:20 +0200 Subject: [PATCH 24/97] - fixed typos in scroll code. --- src/p_scroll.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/p_scroll.cpp b/src/p_scroll.cpp index b7ed4fc65..d0a8f4769 100644 --- a/src/p_scroll.cpp +++ b/src/p_scroll.cpp @@ -147,8 +147,8 @@ static void RotationComp(const sector_t *sec, int which, double dx, double dy, d } else { - double ca = an.Cos(); - double sa = an.Sin(); + double ca = -an.Cos(); + double sa = -an.Sin(); tdx = dx*ca - dy*sa; tdy = dy*ca + dx*sa; } @@ -345,12 +345,16 @@ DScroller::DScroller (double dx, double dy, const line_t *l, int control, int accel, EScrollPos scrollpos) : DThinker (STAT_SCROLLER) { + if (tagManager.GetFirstLineID(l) == 300) + { + int a = 0; + } double x = fabs(l->Delta().X), y = fabs(l->Delta().Y), d; if (y > x) d = x, x = y, y = d; d = x / g_sin(g_atan2(y, x) + M_PI / 2); x = (-dy * l->Delta().Y + dx * l->Delta().X) / d; - y = (-dx * l->Delta().Y - dy * l->Delta().Y) / d; + y = (-dx * l->Delta().Y - dy * l->Delta().X) / d; m_Type = EScroll::sc_side; m_dx = x; From 6deb185b46bde9e084429b02510fecf1ebc5fa54 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 14 Aug 2016 22:10:44 +0200 Subject: [PATCH 25/97] - fixed another typo in scroller code. Now Scroll_Texture_Model is working properly again. (Note: Whoever designed this function must have been on drugs - its use of the source data in Boom is completely insane.) --- src/p_scroll.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/p_scroll.cpp b/src/p_scroll.cpp index d0a8f4769..52be13d56 100644 --- a/src/p_scroll.cpp +++ b/src/p_scroll.cpp @@ -345,16 +345,12 @@ DScroller::DScroller (double dx, double dy, const line_t *l, int control, int accel, EScrollPos scrollpos) : DThinker (STAT_SCROLLER) { - if (tagManager.GetFirstLineID(l) == 300) - { - int a = 0; - } double x = fabs(l->Delta().X), y = fabs(l->Delta().Y), d; if (y > x) d = x, x = y, y = d; d = x / g_sin(g_atan2(y, x) + M_PI / 2); - x = (-dy * l->Delta().Y + dx * l->Delta().X) / d; - y = (-dx * l->Delta().Y - dy * l->Delta().X) / d; + x = -(dy * l->Delta().Y + dx * l->Delta().X) / d; + y = -(dx * l->Delta().Y - dy * l->Delta().X) / d; m_Type = EScroll::sc_side; m_dx = x; From df0f06a5cefe7a3979c126ba5bc75862362d2137 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 14 Aug 2016 23:33:31 +0200 Subject: [PATCH 26/97] - fixed: FraggleScript's SetCamera function must call SetOrigin to set the camera's z. This needs updating of floorz and ceilingz, in case the camera is moved past a 3D floor. --- src/fragglescript/t_func.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index f02843c89..deb4907a3 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -1452,7 +1452,8 @@ void FParser::SF_SetCamera(void) newcamera->specialf1 = newcamera->Angles.Yaw.Degrees; newcamera->specialf2 = newcamera->Z(); - newcamera->SetZ(t_argc < 3 ? newcamera->Z() + 41 : floatvalue(t_argv[2])); + double z = t_argc < 3 ? newcamera->Sector->floorplane.ZatPoint(newcamera) + 41 : floatvalue(t_argv[2]); + newcamera->SetOrigin(newcamera->PosAtZ(z), false); newcamera->Angles.Yaw = angle; if (t_argc < 4) newcamera->Angles.Pitch = 0.; else newcamera->Angles.Pitch = clamp(floatvalue(t_argv[3]), -50., 50.) * (20. / 32.); From c02960e2cf91f29aae2593d10eb2fb3d29dbf7fe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 16 Aug 2016 08:58:29 +0200 Subject: [PATCH 27/97] - added error message highlighting for one overlooked DECORATE error. --- src/thingdef/thingdef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 4878adfdf..dfc960627 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -343,7 +343,7 @@ static void FinishThingdef() if (!def) { - Printf("No ActorInfo defined for class '%s'\n", ti->TypeName.GetChars()); + Printf(TEXTCOLOR_RED "No ActorInfo defined for class '%s'\n", ti->TypeName.GetChars()); errorcount++; continue; } From aa2ca7741279efdb139c6a3a45bd6a271b9bdf63 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Fri, 12 Aug 2016 12:49:55 -0500 Subject: [PATCH 28/97] Added damagetype parameter and XF_NOACTORTYPE to A_Explode. - By default, A_Explode will refer to the actor's damagetype if using none. The flag forces the function's type if used regardless of type. --- src/thingdef/thingdef_codeptr.cpp | 12 ++++++++++-- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index b0cfbeba4..888e8db8e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1373,8 +1373,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType) enum { - XF_HURTSOURCE = 1, - XF_NOTMISSILE = 4, + XF_HURTSOURCE = 1, + XF_NOTMISSILE = 4, + XF_NOACTORTYPE = 1 << 3, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) @@ -1388,6 +1389,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) PARAM_INT_OPT (nails) { nails = 0; } PARAM_INT_OPT (naildamage) { naildamage = 10; } PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } if (damage < 0) // get parameters from metadata { @@ -1415,6 +1417,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) } int count = P_RadiusAttack (self, self->target, damage, distance, self->DamageType, flags, fulldmgdistance); + if (!(flags & XF_NOACTORTYPE) && damagetype == NAME_None) + { + damagetype = self->DamageType; + } + + P_RadiusAttack (self, self->target, damage, distance, damagetype, flags, fulldmgdistance); P_CheckSplash(self, distance); if (alert && self->target != NULL && self->target->player != NULL) { diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index c80834fdc..b8bbcab14 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -253,7 +253,7 @@ ACTOR Actor native //: Thinker action native A_Blast(int flags = 0, float strength = 255, float radius = 255, float speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius"); action native A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0); action native A_RadiusDamageSelf(int damage = 128, float distance = 128, int flags = 0, class flashtype = "None"); - action native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff"); + action native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff", name damagetype = "none"); action native A_Stop(); action native A_Respawn(int flags = 1); action native A_BarrelDestroy(); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 30afd1064..a3093a2c4 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -185,6 +185,7 @@ const int MSF_DontHurt = 2; // Flags for A_Explode const int XF_HURTSOURCE = 1; const int XF_NOTMISSILE = 4; +const int XF_NOACTORTYPE = 1 << 3; // Flags for A_RadiusThrust const int RTF_AFFECTSOURCE = 1; From e93b64f249c8e4139faa2144643f334fa35aaff7 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Sun, 14 Aug 2016 19:23:28 +0200 Subject: [PATCH 29/97] Fixed: a register from a return statement's value would not be freed --- src/thingdef/thingdef_expression.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 00c4b1e75..034c304c2 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -4757,6 +4757,8 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) { + ExpEmit out(0, REGT_NIL); + // If we return nothing, use a regular RET opcode. // Otherwise just return the value we're given. if (Value == nullptr) @@ -4765,11 +4767,11 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) } else { - ExpEmit ret = Value->Emit(build); + out = Value->Emit(build); // Check if it is a function call that simplified itself // into a tail call in which case we don't emit anything. - if (!ret.Final) + if (!out.Final) { if (Value->ValueType == TypeVoid) { // Nothing is returned. @@ -4777,12 +4779,11 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) } else { - build->Emit(OP_RET, RET_FINAL, ret.RegType | (ret.Konst ? REGT_KONST : 0), ret.RegNum); + build->Emit(OP_RET, RET_FINAL, out.RegType | (out.Konst ? REGT_KONST : 0), out.RegNum); } } } - ExpEmit out; out.Final = true; return out; } From 04c4147052bac594034463213dd06d4626ca13f2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 16 Aug 2016 09:02:23 +0200 Subject: [PATCH 30/97] - renamed flag to be more descriptive. --- wadsrc/static/actors/constants.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index a3093a2c4..2a6f1c483 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -185,7 +185,7 @@ const int MSF_DontHurt = 2; // Flags for A_Explode const int XF_HURTSOURCE = 1; const int XF_NOTMISSILE = 4; -const int XF_NOACTORTYPE = 1 << 3; +const int XF_EXPLICITDAMAGETYPE = 1 << 3; // Flags for A_RadiusThrust const int RTF_AFFECTSOURCE = 1; From 314e89b84fe42c5dadce18a8833d3a03091115f6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 16 Aug 2016 10:53:30 +0200 Subject: [PATCH 31/97] - fixed what looks like a copy/paste error in A_Explode. --- src/thingdef/thingdef_codeptr.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 888e8db8e..6c8b22301 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1416,13 +1416,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) } } - int count = P_RadiusAttack (self, self->target, damage, distance, self->DamageType, flags, fulldmgdistance); if (!(flags & XF_NOACTORTYPE) && damagetype == NAME_None) { damagetype = self->DamageType; } - P_RadiusAttack (self, self->target, damage, distance, damagetype, flags, fulldmgdistance); + int count = P_RadiusAttack (self, self->target, damage, distance, damagetype, flags, fulldmgdistance); P_CheckSplash(self, distance); if (alert && self->target != NULL && self->target->player != NULL) { From ca8ef7f3f37a1fe7f49f77d96eca0ac0dc8ceec6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 16 Aug 2016 11:20:22 +0200 Subject: [PATCH 32/97] - moved bobbing menu strings into the correct file. --- wadsrc/static/language.eng | 2 -- wadsrc/static/language.enu | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/language.eng b/wadsrc/static/language.eng index ed0f95a9a..ca27bf80a 100644 --- a/wadsrc/static/language.eng +++ b/wadsrc/static/language.eng @@ -108,5 +108,3 @@ CMPTMNU_SECTORSOUNDS = "Sector sounds use centre as source"; OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colours only"; C_GRAY = "\ccgrey"; C_DARKGRAY = "\cudark grey"; -DSPLYMNU_MOVEBOB = "View bob amount while moving"; -DSPLYMNU_STILLBOB = "View bob amount while not moving"; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 03212768e..d80c048b7 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1800,6 +1800,8 @@ DSPLYMNU_QUAKEINTENSITY = "Earthquake shake intensity"; DSPLYMNU_NOMONSTERINTERPOLATION = "Interpolate monster movement"; DSPLYMNU_MENUDIM = "Menu dim"; DSPLYMNU_DIMCOLOR = "Dim color"; +DSPLYMNU_MOVEBOB = "View bob amount while moving"; +DSPLYMNU_STILLBOB = "View bob amount while not moving"; // HUD Options HUDMNU_TITLE = "HUD Options"; From 5ff0abe5681a519f05c1339c6d01e3e970178a81 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 20 Aug 2016 19:10:14 +0200 Subject: [PATCH 33/97] - removed STAT_INVENTORY. This was causing issues with sprite sorting. For this to work as intended, all actors in the world that display sprites need to remain in spawn order, including inventory items. The only thing this statnum was used for were some bot related search actions which are simply not worth breaking actual maps for some very minor performance gain. --- src/b_think.cpp | 2 +- src/g_level.cpp | 2 +- src/g_shared/a_pickups.cpp | 1 - src/statnums.h | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/b_think.cpp b/src/b_think.cpp index 0ff75722a..5a98b5c1a 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -259,7 +259,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) r = pr_botmove(); if (r < 128) { - TThinkerIterator it (STAT_INVENTORY, bglobal.firstthing); + TThinkerIterator it (MAX_STATNUM+1, bglobal.firstthing); AInventory *item = it.Next(); if (item != NULL || (item = it.Next()) != NULL) diff --git a/src/g_level.cpp b/src/g_level.cpp index e47cbb4a5..349d8f5a6 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1280,7 +1280,7 @@ void G_FinishTravel () for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory) { - inv->ChangeStatNum (STAT_INVENTORY); + inv->ChangeStatNum (STAT_DEFAULT); inv->LinkToWorld (); inv->Travelled (); } diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 6ad8e6e4a..e41a91d2f 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -572,7 +572,6 @@ bool AInventory::ShouldRespawn () void AInventory::BeginPlay () { Super::BeginPlay (); - ChangeStatNum (STAT_INVENTORY); flags |= MF_DROPPED; // [RH] Items are dropped by default } diff --git a/src/statnums.h b/src/statnums.h index 7f691e232..45bb53e65 100644 --- a/src/statnums.h +++ b/src/statnums.h @@ -53,7 +53,7 @@ enum STAT_BOSSTARGET, // A boss brain target STAT_LIGHTNING, // The lightning thinker STAT_DECALTHINKER, // An object that thinks for a decal - STAT_INVENTORY, // An inventory item + UNUSED_STAT_INVENTORY, // An inventory item (value kept for savegame compatibility.) STAT_LIGHT, // A sector light effect STAT_LIGHTTRANSFER, // A sector light transfer. These must be ticked after the light effects!!! STAT_EARTHQUAKE, // Earthquake actors From df4a8e38c5ef4a1d1bc51ae3354b411973e23aaa Mon Sep 17 00:00:00 2001 From: yqco Date: Mon, 22 Aug 2016 01:21:38 -0600 Subject: [PATCH 34/97] Add CheckActorState ACS function bool CheckActorState(int tid, str statename, bool exact = false); - Same parameter order as SetActorState - Returns true if actor has the state; else returns false --- src/p_acs.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 01953cad9..0762b3e29 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4438,8 +4438,7 @@ enum EACSFunctions ACSF_SpawnParticle, ACSF_SetMusicVolume, ACSF_CheckProximity, - // 1 more left... - + ACSF_CheckActorState, // 99 /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), -101 : PlayerIsSpectator(1), @@ -6017,6 +6016,18 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return P_Thing_CheckProximity(actor, classname, distance, count, flags, ptr); } + case ACSF_CheckActorState: + { + actor = SingleActorFromTID(args[0], activator); + const char *statename = FBehavior::StaticLookupString(args[1]); + bool exact = (argCount > 2) ? !!args[2] : false; + if (actor && statename) + { + return (actor->GetClass()->FindStateByString(statename, exact) != nullptr); + } + return false; + } + default: break; } From e22043a25b7f2d61ddcff44b6b014233022ba5eb Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Thu, 18 Aug 2016 15:05:18 -0500 Subject: [PATCH 35/97] Fixed: A_FaceMovementDirection would not adjust the angle if it was actually under the limit. --- src/thingdef/thingdef_codeptr.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 6c8b22301..1f24a35c7 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -7267,12 +7267,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) { current -= anglelimit + offset; } - else // huh??? - { - current = angle + 180. + offset; - } mobj->SetAngle(current, !!(flags & FMDF_INTERPOLATE)); } + else + mobj->SetAngle(angle + offset, !!(flags & FMDF_INTERPOLATE)); } else mobj->SetAngle(angle + offset, !!(flags & FMDF_INTERPOLATE)); From 48430d9b1a648508f068b7714b68e6cb32a8bfba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 25 Aug 2016 21:15:53 +0200 Subject: [PATCH 36/97] - don't assume that deserializing an actor will result in a valid pointer. This addresses a very strange crash I encounteded while travelling in a hub, and ended up with a NULL pointer after the 'Serialize' call which means that some code cleared the variable that is currently being deserialized. I was completely unable to find out what caused this because there is so much recursion going on in the deserializer. All actions on the deserialized actor are now being done with a local copy of that variable so that altering the actual one won't have any adverse effects. --- src/farchive.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/farchive.cpp b/src/farchive.cpp index 6697fd5b7..317abe702 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -1194,6 +1194,7 @@ FArchive &FArchive::ReadObject (DObject* &obj, PClass *wanttype) const PClass *type; BYTE playerNum; DWORD index; + DObject *newobj; operator<< (objHead); @@ -1255,11 +1256,11 @@ FArchive &FArchive::ReadObject (DObject* &obj, PClass *wanttype) case NEW_CLS_OBJ: type = ReadClass (wanttype); // Printf ("New class: %s (%u)\n", type->Name, m_File->Tell()); - obj = type->CreateNew (); + newobj = obj = type->CreateNew (); MapObject (obj); - obj->SerializeUserVars (*this); - obj->Serialize (*this); - obj->CheckIfSerialized (); + newobj->SerializeUserVars (*this); + newobj->Serialize (*this); + newobj->CheckIfSerialized (); break; case NEW_PLYR_OBJ: From 9ca6764556aa07e94d5928ae7a8ad7d0b5aaed82 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 25 Aug 2016 21:41:17 +0200 Subject: [PATCH 37/97] Revert "- removed STAT_INVENTORY." This reverts commit 5ff0abe5681a519f05c1339c6d01e3e970178a81. - use STAT_INVENTORY only for held items. Seems this was causing some strange issues with hubs, but for items placed in the world it still cannot be allowed to have them in a different statnum. --- src/g_level.cpp | 2 +- src/g_shared/a_pickups.cpp | 2 ++ src/statnums.h | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 349d8f5a6..e47cbb4a5 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1280,7 +1280,7 @@ void G_FinishTravel () for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory) { - inv->ChangeStatNum (STAT_DEFAULT); + inv->ChangeStatNum (STAT_INVENTORY); inv->LinkToWorld (); inv->Travelled (); } diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index e41a91d2f..c72366201 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -821,6 +821,7 @@ void AInventory::BecomeItem () } RemoveFromHash (); flags &= ~MF_SPECIAL; + ChangeStatNum(STAT_INVENTORY); SetState (FindState("Held")); } @@ -847,6 +848,7 @@ void AInventory::BecomePickup () } flags = (GetDefault()->flags | MF_DROPPED) & ~MF_COUNTITEM; renderflags &= ~RF_INVISIBLE; + ChangeStatNum(STAT_DEFAULT); SetState (SpawnState); } diff --git a/src/statnums.h b/src/statnums.h index 45bb53e65..7f691e232 100644 --- a/src/statnums.h +++ b/src/statnums.h @@ -53,7 +53,7 @@ enum STAT_BOSSTARGET, // A boss brain target STAT_LIGHTNING, // The lightning thinker STAT_DECALTHINKER, // An object that thinks for a decal - UNUSED_STAT_INVENTORY, // An inventory item (value kept for savegame compatibility.) + STAT_INVENTORY, // An inventory item STAT_LIGHT, // A sector light effect STAT_LIGHTTRANSFER, // A sector light transfer. These must be ticked after the light effects!!! STAT_EARTHQUAKE, // Earthquake actors From 465792df0a0243c8ae4cc3925c056d85db319891 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 26 Aug 2016 02:16:06 +0200 Subject: [PATCH 38/97] - make sure that after travelling has finished, no travelling thinkers are left in the list. Since this list is excluded from regular thinker cleaning, anything that may survive through the end of G_FinishTravel will endlessly multiply and severely break the following savegames or just simply crash on broken pointers. --- src/dthinker.h | 5 +++++ src/g_level.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/dthinker.h b/src/dthinker.h index 10a53309d..855c3c9ad 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -77,6 +77,11 @@ public: static void RunThinkers (int statnum); static void DestroyAllThinkers (); static void DestroyMostThinkers (); + static void DestroyThinkersInList(int statnum) + { + DestroyThinkersInList(Thinkers[STAT_TRAVELLING]); + DestroyThinkersInList(FreshThinkers[STAT_TRAVELLING]); + } static void SerializeAll (FArchive &arc, bool keepPlayers); static void MarkRoots(); diff --git a/src/g_level.cpp b/src/g_level.cpp index e47cbb4a5..60e9b0699 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1295,6 +1295,11 @@ void G_FinishTravel () } bglobal.FinishTravel (); + + // make sure that, after travelling has completed, no travelling thinkers are left. + // Since this list is excluded from regular thinker cleaning, anything that may survive through here + // will endlessly multiply and severely break the following savegames or just simply crash on broken pointers. + DThinker::DestroyThinkersInList(STAT_TRAVELLING); } //========================================================================== From 5303526c70138423b074d06cf794b584728f0405 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 26 Aug 2016 08:34:27 +0200 Subject: [PATCH 39/97] - actually use the parameter... --- src/dthinker.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dthinker.h b/src/dthinker.h index 855c3c9ad..ac5adc431 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -79,8 +79,8 @@ public: static void DestroyMostThinkers (); static void DestroyThinkersInList(int statnum) { - DestroyThinkersInList(Thinkers[STAT_TRAVELLING]); - DestroyThinkersInList(FreshThinkers[STAT_TRAVELLING]); + DestroyThinkersInList(Thinkers[statnum]); + DestroyThinkersInList(FreshThinkers[statnum]); } static void SerializeAll (FArchive &arc, bool keepPlayers); static void MarkRoots(); From 716fbec8eedb8ed06b8a937ffac39b062cfbf817 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 27 Aug 2016 22:14:57 -0400 Subject: [PATCH 40/97] - Added support for building with FMOD Studio Low Level API (partially based off of Emile Belanger's/Beloko Games Android work) - Use with FMOD Studio 1.06.x. 1.07 and 1.08 compile but for some reason produce a lot of noise on vanilla Doom sounds. - Crashes when used with fluidsynth provided by Ubuntu 16.04, but a self compiled version of the library works just fine. - Reverbs are mostly untested, but implemented. - Debug waveform drawing is not implemented as it requires a non-trivial amount of work. - It will still show as FMOD Ex in the menus since I'm too lazy at the moment to make it a "separate" backend. --- output_sdl/CMakeLists.txt | 18 +- src/sound/fmod_wrap.h | 9 + src/sound/fmodsound.cpp | 359 ++++++++++++++++++++++++++++++++++---- src/sound/fmodsound.h | 9 + 4 files changed, 354 insertions(+), 41 deletions(-) diff --git a/output_sdl/CMakeLists.txt b/output_sdl/CMakeLists.txt index de42f6be6..323d94149 100644 --- a/output_sdl/CMakeLists.txt +++ b/output_sdl/CMakeLists.txt @@ -1,11 +1,17 @@ cmake_minimum_required( VERSION 2.8.7 ) if( NOT NO_FMOD AND FMOD_INCLUDE_DIR ) - add_library( output_sdl MODULE output_sdl.c ) include_directories( ${FMOD_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} ) - target_link_libraries( output_sdl ${SDL2_LIBRARY} ) + check_library_exists(${FMOD_LIBRARY} "FMOD_System_GetDriverCaps" "fmod.h" FMOD_IS_EX) - FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so ]; then ln -sf output_sdl/liboutput_sdl.so ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so; fi" ) - add_custom_command( TARGET output_sdl POST_BUILD - COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make - COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make ) + # Only usable with FMOD Ex + if( FMOD_IS_EX ) + include_directories( ${FMOD_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} ) + add_library( output_sdl MODULE output_sdl.c ) + target_link_libraries( output_sdl ${SDL2_LIBRARY} ) + + FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so ]; then ln -sf output_sdl/liboutput_sdl.so ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so; fi" ) + add_custom_command( TARGET output_sdl POST_BUILD + COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make + COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make ) + endif() endif() diff --git a/src/sound/fmod_wrap.h b/src/sound/fmod_wrap.h index 6734ba85b..02d6a56ae 100644 --- a/src/sound/fmod_wrap.h +++ b/src/sound/fmod_wrap.h @@ -611,5 +611,14 @@ namespace FMOD } #endif + +// FMOD Ex vs FMOD Studio +#if FMOD_VERSION >= 0x00040000 && FMOD_VERSION <= 0x0004FFFF +#define FMOD_STUDIO 0 +#else +#define FMOD_STUDIO 1 +#define FMOD_SOFTWARE 0 +#endif + #endif #endif diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 1088818ce..465aade9b 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -122,10 +122,14 @@ CUSTOM_CVAR (Int, snd_streambuffersize, 64, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } #ifndef NO_FMOD -#if FMOD_VERSION < 0x43400 +#if !FMOD_STUDIO && FMOD_VERSION < 0x43400 #define FMOD_OPENSTATE_PLAYING FMOD_OPENSTATE_STREAMING #endif +#if !FMOD_STUDIO +#define setParameterFloat setParameter +#endif + // TYPES ------------------------------------------------------------------- struct FEnumList @@ -183,15 +187,28 @@ static const FEnumList OutputNames[] = { "WASAPI", FMOD_OUTPUTTYPE_WASAPI }, { "ASIO", FMOD_OUTPUTTYPE_ASIO }, +#if FMOD_STUDIO + //Android + + { "OPENSL", FMOD_OUTPUTTYPE_OPENSL }, + { "Android Audio Track", FMOD_OUTPUTTYPE_AUDIOTRACK }, +#endif + // Linux +#if !FMOD_STUDIO { "OSS", FMOD_OUTPUTTYPE_OSS }, +#endif { "ALSA", FMOD_OUTPUTTYPE_ALSA }, +#if !FMOD_STUDIO { "ESD", FMOD_OUTPUTTYPE_ESD }, -#if FMOD_VERSION >= 0x43400 +#endif +#if FMOD_STUDIO || FMOD_VERSION >= 0x43400 { "PulseAudio", FMOD_OUTPUTTYPE_PULSEAUDIO }, { "Pulse", FMOD_OUTPUTTYPE_PULSEAUDIO }, #endif +#if !FMOD_STUDIO { "SDL", 666 }, +#endif // Mac { "Core Audio", FMOD_OUTPUTTYPE_COREAUDIO }, @@ -207,7 +224,7 @@ static const FEnumList SpeakerModeNames[] = { "Surround", FMOD_SPEAKERMODE_SURROUND }, { "5.1", FMOD_SPEAKERMODE_5POINT1 }, { "7.1", FMOD_SPEAKERMODE_7POINT1 }, -#if FMOD_VERSION < 0x44000 +#if !FMOD_STUDIO && FMOD_VERSION < 0x44000 { "Prologic", FMOD_SPEAKERMODE_PROLOGIC }, #endif { "1", FMOD_SPEAKERMODE_MONO }, @@ -222,7 +239,7 @@ static const FEnumList ResamplerNames[] = { "NoInterp", FMOD_DSP_RESAMPLER_NOINTERP }, { "Linear", FMOD_DSP_RESAMPLER_LINEAR }, // [BL] 64-bit version of FMOD Ex 4.26 crashes with these resamplers. -#if !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42600 && FMOD_VERSION <= 0x426FF) +#if FMOD_STUDIO || !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42600 && FMOD_VERSION <= 0x426FF) { "Cubic", FMOD_DSP_RESAMPLER_CUBIC }, { "Spline", FMOD_DSP_RESAMPLER_SPLINE }, #endif @@ -237,11 +254,13 @@ static const FEnumList SoundFormatNames[] = { "PCM-24", FMOD_SOUND_FORMAT_PCM24 }, { "PCM-32", FMOD_SOUND_FORMAT_PCM32 }, { "PCM-Float", FMOD_SOUND_FORMAT_PCMFLOAT }, +#if FMOD_STUDIO && FMOD_VERSION < 0x10700 { "GCADPCM", FMOD_SOUND_FORMAT_GCADPCM }, { "IMAADPCM", FMOD_SOUND_FORMAT_IMAADPCM }, { "VAG", FMOD_SOUND_FORMAT_VAG }, { "XMA", FMOD_SOUND_FORMAT_XMA }, { "MPEG", FMOD_SOUND_FORMAT_MPEG }, +#endif { NULL, 0 } }; @@ -356,10 +375,13 @@ public: Stream = stream; // As this interface is for music, make it super-high priority. +#if FMOD_STUDIO + if (FMOD_OK == stream->getDefaults(&frequency, NULL)) + stream->setDefaults(frequency, 1); +#else if (FMOD_OK == stream->getDefaults(&frequency, NULL, NULL, NULL)) - { stream->setDefaults(frequency, 1, 0, 0); - } +#endif } bool Play(bool looping, float volume) @@ -371,21 +393,33 @@ public: looping = false; } Stream->setMode((looping ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF) | FMOD_SOFTWARE | FMOD_2D); +#if FMOD_STUDIO + result = Owner->Sys->playSound(Stream,0, true, &Channel); +#else result = Owner->Sys->playSound(FMOD_CHANNEL_FREE, Stream, true, &Channel); +#endif if (result != FMOD_OK) { return false; } Channel->setChannelGroup(Owner->MusicGroup); +#if FMOD_STUDIO + Channel->setMixLevelsOutput(1, 1, 1, 1, 1, 1, 1, 1); +#else Channel->setSpeakerMix(1, 1, 1, 1, 1, 1, 1, 1); +#endif Channel->setVolume(volume); // Ensure reverb is disabled. +#if FMOD_STUDIO + Channel->setReverbProperties(0,0.f); +#else FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, }; if (FMOD_OK == Channel->getReverbProperties(&reverb)) { reverb.Room = -10000; Channel->setReverbProperties(&reverb); } +#endif Channel->setPaused(false); Ended = false; JustStarted = true; @@ -429,7 +463,7 @@ public: bool is; FMOD_OPENSTATE openstate = FMOD_OPENSTATE_MAX; bool starving; -#if FMOD_VERSION >= 0x43400 +#if FMOD_STUDIO || FMOD_VERSION >= 0x43400 bool diskbusy; #endif @@ -437,7 +471,7 @@ public: { return true; } -#if FMOD_VERSION < 0x43400 +#if !FMOD_STUDIO && FMOD_VERSION < 0x43400 if (FMOD_OK != Stream->getOpenState(&openstate, NULL, &starving)) #else if (FMOD_OK != Stream->getOpenState(&openstate, NULL, &starving, &diskbusy)) @@ -526,7 +560,7 @@ public: unsigned int percentbuffered; unsigned int position; bool starving; -#if FMOD_VERSION >= 0x43400 +#if FMOD_STUDIO || FMOD_VERSION >= 0x43400 bool diskbusy; #endif float volume; @@ -534,7 +568,7 @@ public: bool paused; bool isplaying; -#if FMOD_VERSION < 0x43400 +#if !FMOD_STUDIO && FMOD_VERSION < 0x43400 if (FMOD_OK == Stream->getOpenState(&openstate, &percentbuffered, &starving)) #else if (FMOD_OK == Stream->getOpenState(&openstate, &percentbuffered, &starving, &diskbusy)) @@ -710,7 +744,9 @@ bool FMODSoundRenderer::Init() } const char *wrongver = NULL; -#if FMOD_VERSION >= 0x43600 +#if FMOD_STUDIO + if (version < (FMOD_VERSION & 0xFFFF00)) +#elif FMOD_VERSION >= 0x43600 if (version < 0x43600) #else if (version < 0x42000) @@ -718,7 +754,7 @@ bool FMODSoundRenderer::Init() { wrongver = "an old"; } -#if FMOD_VERSION < 0x42700 +#if !FMOD_STUDIO && FMOD_VERSION < 0x42700 else if ((version & 0xFFFF00) > 0x42600) #else else if ((version & 0xFFFF00) > (FMOD_VERSION & 0xFFFF00)) @@ -744,7 +780,7 @@ bool FMODSoundRenderer::Init() Printf("Loaded FMOD version %x.%02x.%02x\n", version >> 16, (version >> 8) & 255, version & 255); ShowedBanner = true; } -#ifdef _WIN32 +#if defined(_WIN32) && !FMOD_STUDIO if (OSPlatform == os_WinNT4) { // The following was true as of FMOD 3. I don't know if it still @@ -781,7 +817,7 @@ bool FMODSoundRenderer::Init() } #endif -#if !defined _WIN32 && !defined __APPLE__ +#if !defined _WIN32 && !defined __APPLE__ && !FMOD_STUDIO // Try to load SDL output plugin result = Sys->setPluginPath(progdir); // Should we really look for it in the program directory? result = Sys->loadPlugin("liboutput_sdl.so", &OutputPlugin); @@ -812,7 +848,7 @@ bool FMODSoundRenderer::Init() } result = Sys->getNumDrivers(&driver); -#ifdef __unix__ +#if defined(__unix__) && !FMOD_STUDIO if (result == FMOD_OK) { // On Linux, FMOD defaults to OSS. If OSS is not present, it doesn't @@ -852,7 +888,11 @@ bool FMODSoundRenderer::Init() result = Sys->setDriver(driver); } result = Sys->getDriver(&driver); -#if FMOD_VERSION >= 0x43600 +#if FMOD_STUDIO + // We were built with an FMOD Studio that only returns the control panel frequency + result = Sys->getDriverInfo(driver, nullptr, 0, nullptr, &Driver_MinFrequency, &speakermode, nullptr); + Driver_MaxFrequency = Driver_MinFrequency; +#elif FMOD_VERSION >= 0x43600 // We were built with an FMOD that only returns the control panel frequency result = Sys->getDriverCaps(driver, &Driver_Caps, &Driver_MinFrequency, &speakermode); Driver_MaxFrequency = Driver_MinFrequency; @@ -865,7 +905,9 @@ bool FMODSoundRenderer::Init() Printf(TEXTCOLOR_BLUE"Could not ascertain driver capabilities. Some things may be weird. (Error %d)\n", result); // Fill in some default to pretend it worked. (But as long as we specify a valid driver, // can this call actually fail?) +#if !FMOD_STUDIO Driver_Caps = 0; +#endif Driver_MinFrequency = 4000; Driver_MaxFrequency = 48000; speakermode = FMOD_SPEAKERMODE_STEREO; @@ -877,11 +919,13 @@ bool FMODSoundRenderer::Init() { speakermode = FMOD_SPEAKERMODE(eval); } +#if !FMOD_STUDIO result = Sys->setSpeakerMode(speakermode); if (result != FMOD_OK) { Printf(TEXTCOLOR_BLUE"Could not set speaker mode to '%s'. (Error %d)\n", *snd_speakermode, result); } +#endif // Set software format eval = Enum_NumForName(SoundFormatNames, snd_output_format); @@ -902,7 +946,11 @@ bool FMODSoundRenderer::Init() samplerate = snd_samplerate; if (samplerate == 0 || snd_samplerate == 0) { // Creative's ASIO drivers report the only supported frequency as 0! +#if FMOD_STUDIO + if (FMOD_OK != Sys->getSoftwareFormat(&samplerate, NULL, NULL)) +#else if (FMOD_OK != Sys->getSoftwareFormat(&samplerate, NULL, NULL, NULL, NULL, NULL)) +#endif { samplerate = 48000; } @@ -911,12 +959,26 @@ bool FMODSoundRenderer::Init() { Printf(TEXTCOLOR_BLUE"Sample rate %d is unsupported. Trying %d.\n", *snd_samplerate, samplerate); } +#if FMOD_STUDIO + result = Sys->setSoftwareFormat(samplerate, speakermode, 0); +#else result = Sys->setSoftwareFormat(samplerate, format, 0, 0, resampler); +#endif if (result != FMOD_OK) { Printf(TEXTCOLOR_BLUE"Could not set mixing format. Defaults will be used. (Error %d)\n", result); } +#if FMOD_STUDIO + FMOD_ADVANCEDSETTINGS advSettings = {}; + advSettings.resamplerMethod = resampler; + result = Sys->setAdvancedSettings(&advSettings); + if (result != FMOD_OK) + { + Printf(TEXTCOLOR_BLUE"Could not set resampler method. Defaults will be used. (Error %d)\n", result); + } +#endif + // Set software channels according to snd_channels result = Sys->setSoftwareChannels(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS); if (result != FMOD_OK) @@ -924,6 +986,7 @@ bool FMODSoundRenderer::Init() Printf(TEXTCOLOR_BLUE"Failed to set the preferred number of channels. (Error %d)\n", result); } +#if !FMOD_STUDIO if (Driver_Caps & FMOD_CAPS_HARDWARE_EMULATED) { // The user has the 'Acceleration' slider set to off! // This is really bad for latency! @@ -931,7 +994,9 @@ bool FMODSoundRenderer::Init() Printf (TEXTCOLOR_BLUE"Please turn it back on if you want decent sound.\n"); result = Sys->setDSPBufferSize(1024, 10); // At 48khz, the latency between issuing an fmod command and hearing it will now be about 213ms. } - else if (snd_buffersize != 0 || snd_buffercount != 0) + else +#endif + if (snd_buffersize != 0 || snd_buffercount != 0) { int buffersize = snd_buffersize ? snd_buffersize : 1024; int buffercount = snd_buffercount ? snd_buffercount : 4; @@ -951,7 +1016,9 @@ bool FMODSoundRenderer::Init() if (snd_hrtf) { // These flags are the same thing, just with different names. -#ifdef FMOD_INIT_SOFTWARE_HRTF +#ifdef FMOD_INIT_CHANNEL_LOWPASS + initflags |= FMOD_INIT_CHANNEL_LOWPASS; +#elif defined(FMOD_INIT_SOFTWARE_HRTF) initflags |= FMOD_INIT_SOFTWARE_HRTF; #else initflags |= FMOD_INIT_HRTF_LOWPASS; @@ -959,7 +1026,11 @@ bool FMODSoundRenderer::Init() } if (snd_profile) { +#ifdef FMOD_INIT_PROFILE_ENABLE + initflags |= FMOD_INIT_PROFILE_ENABLE; +#else initflags |= FMOD_INIT_ENABLE_PROFILE; +#endif } for (;;) { @@ -970,14 +1041,23 @@ bool FMODSoundRenderer::Init() // 1. The speaker mode selected isn't supported by this soundcard. Force it to stereo. // 2. The output format is unsupported. Force it to 16-bit PCM. // 3. ??? +#if FMOD_STUDIO + result = Sys->getSoftwareFormat(nullptr, &speakermode, nullptr); +#else result = Sys->getSpeakerMode(&speakermode); +#endif if (result == FMOD_OK && speakermode != FMOD_SPEAKERMODE_STEREO && +#if FMOD_STUDIO + FMOD_OK == Sys->setSoftwareFormat(samplerate, FMOD_SPEAKERMODE_STEREO, 0)) +#else FMOD_OK == Sys->setSpeakerMode(FMOD_SPEAKERMODE_STEREO)) +#endif { Printf(TEXTCOLOR_RED" Buffer creation failed. Retrying with stereo output.\n"); continue; } +#if !FMOD_STUDIO result = Sys->getSoftwareFormat(&samplerate, &format, NULL, NULL, &resampler, NULL); if (result == FMOD_OK && format != FMOD_SOUND_FORMAT_PCM16 && @@ -986,11 +1066,21 @@ bool FMODSoundRenderer::Init() Printf(TEXTCOLOR_RED" Buffer creation failed. Retrying with PCM-16 output.\n"); continue; } +#endif } - else if (result == FMOD_ERR_NET_SOCKET_ERROR && (initflags & FMOD_INIT_ENABLE_PROFILE)) + else if (result == FMOD_ERR_NET_SOCKET_ERROR && +#ifdef FMOD_INIT_PROFILE_ENABLE + (initflags & FMOD_INIT_PROFILE_ENABLE)) +#else + (initflags & FMOD_INIT_ENABLE_PROFILE)) +#endif { Printf(TEXTCOLOR_RED" Could not create socket. Retrying without profiling.\n"); +#ifdef FMOD_INIT_PROFILE_ENABLE + initflags &= ~FMOD_INIT_PROFILE_ENABLE; +#else initflags &= ~FMOD_INIT_ENABLE_PROFILE; +#endif continue; } #ifdef _WIN32 @@ -1066,7 +1156,11 @@ bool FMODSoundRenderer::Init() { FMOD::DSP *sfx_head, *pausable_head; +#if FMOD_STUDIO + result = SfxGroup->getDSP(FMOD_CHANNELCONTROL_DSP_HEAD, &sfx_head); +#else result = SfxGroup->getDSPHead(&sfx_head); +#endif if (result == FMOD_OK) { result = sfx_head->getInput(0, &pausable_head, &SfxConnection); @@ -1103,8 +1197,8 @@ bool FMODSoundRenderer::Init() } result = WaterLP->addInput(pausable_head, NULL); WaterLP->setActive(false); - WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp); - WaterLP->setParameter(FMOD_DSP_LOWPASS_RESONANCE, 2); + WaterLP->setParameterFloat(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp); + WaterLP->setParameterFloat(FMOD_DSP_LOWPASS_RESONANCE, 2); if (WaterReverb != NULL) { @@ -1120,15 +1214,25 @@ bool FMODSoundRenderer::Init() // These parameters are entirely empirical and can probably // stand some improvement, but it sounds remarkably close // to the old reverb unit's output. - WaterReverb->setParameter(FMOD_DSP_SFXREVERB_LFREFERENCE, 150); - WaterReverb->setParameter(FMOD_DSP_SFXREVERB_HFREFERENCE, 10000); - WaterReverb->setParameter(FMOD_DSP_SFXREVERB_ROOM, 0); - WaterReverb->setParameter(FMOD_DSP_SFXREVERB_ROOMHF, -5000); - WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DRYLEVEL, 0); - WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DECAYHFRATIO, 1); - WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DECAYTIME, 0.25f); - WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DENSITY, 100); - WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DIFFUSION, 100); +#if FMOD_STUDIO + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_LOWSHELFFREQUENCY, 150); +#else + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_LFREFERENCE, 150); +#endif + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_HFREFERENCE, 10000); +#if !FMOD_STUDIO + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_ROOM, 0); + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_ROOMHF, -5000); +#endif + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DRYLEVEL, 0); +#if FMOD_STUDIO + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_HFDECAYRATIO, 100); +#else + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DECAYHFRATIO, 1); +#endif + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DECAYTIME, 0.25f); + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DENSITY, 100); + WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DIFFUSION, 100); WaterReverb->setActive(false); } } @@ -1154,7 +1258,11 @@ bool FMODSoundRenderer::Init() { FMOD::DSP *master_head; +#if FMOD_STUDIO + result = master_group->getDSP(FMOD_CHANNELCONTROL_DSP_HEAD, &master_head); +#else result = master_group->getDSPHead(&master_head); +#endif if (result == FMOD_OK) { result = master_head->getOutput(0, &ChannelGroupTargetUnit, NULL); @@ -1174,7 +1282,11 @@ bool FMODSoundRenderer::Init() } } +#if FMOD_STUDIO + if (FMOD_OK != Sys->getSoftwareFormat(&OutputRate, NULL, NULL)) +#else if (FMOD_OK != Sys->getSoftwareFormat(&OutputRate, NULL, NULL, NULL, NULL, NULL)) +#endif { OutputRate = 48000; // Guess, but this should never happen. } @@ -1272,20 +1384,35 @@ void FMODSoundRenderer::PrintStatus() { Printf ("Output type: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(OutputNames, output)); } +#if FMOD_STUDIO + if (FMOD_OK == Sys->getSoftwareFormat(&samplerate, &speakermode, nullptr)) + { + Printf ("Speaker mode: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(SpeakerModeNames, speakermode)); + Printf (TEXTCOLOR_LIGHTBLUE "Software mixer sample rate: " TEXTCOLOR_GREEN "%d\n", samplerate); + } +#else if (FMOD_OK == Sys->getSpeakerMode(&speakermode)) { Printf ("Speaker mode: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(SpeakerModeNames, speakermode)); } +#endif if (FMOD_OK == Sys->getDriver(&driver)) { char name[256]; +#if FMOD_STUDIO + if (FMOD_OK != Sys->getDriverInfo(driver, name, sizeof(name), nullptr, nullptr, nullptr, nullptr)) +#else if (FMOD_OK != Sys->getDriverInfo(driver, name, sizeof(name), NULL)) +#endif { strcpy(name, "Unknown"); } Printf ("Driver: " TEXTCOLOR_GREEN "%d" TEXTCOLOR_NORMAL " (" TEXTCOLOR_ORANGE "%s" TEXTCOLOR_NORMAL ")\n", driver, name); +#if !FMOD_STUDIO DumpDriverCaps(Driver_Caps, Driver_MinFrequency, Driver_MaxFrequency); +#endif } +#if !FMOD_STUDIO if (FMOD_OK == Sys->getSoftwareFormat(&samplerate, &format, &numoutputchannels, NULL, &resampler, NULL)) { Printf (TEXTCOLOR_LIGHTBLUE "Software mixer sample rate: " TEXTCOLOR_GREEN "%d\n", samplerate); @@ -1293,6 +1420,7 @@ void FMODSoundRenderer::PrintStatus() Printf (TEXTCOLOR_LIGHTBLUE "Software mixer channels: " TEXTCOLOR_GREEN "%d\n", numoutputchannels); Printf (TEXTCOLOR_LIGHTBLUE "Software mixer resampler: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(ResamplerNames, resampler)); } +#endif if (FMOD_OK == Sys->getDSPBufferSize(&bufferlength, &numbuffers)) { Printf (TEXTCOLOR_LIGHTBLUE "DSP buffers: " TEXTCOLOR_GREEN "%u samples x %d\n", bufferlength, numbuffers); @@ -1305,6 +1433,7 @@ void FMODSoundRenderer::PrintStatus() // //========================================================================== +#if !FMOD_STUDIO void FMODSoundRenderer::DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int maxfrequency) { Printf (TEXTCOLOR_OLIVE " Min. frequency: " TEXTCOLOR_GREEN "%d\n", minfrequency); @@ -1325,6 +1454,7 @@ void FMODSoundRenderer::DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int max } if (caps & FMOD_CAPS_REVERB_LIMITED) Printf(TEXTCOLOR_OLIVE " Limited reverb\n"); } +#endif //========================================================================== // @@ -1342,7 +1472,11 @@ void FMODSoundRenderer::PrintDriversList() { for (i = 0; i < numdrivers; ++i) { +#if FMOD_STUDIO + if (FMOD_OK == Sys->getDriverInfo(i, name, sizeof(name), nullptr, nullptr, nullptr, nullptr)) +#else if (FMOD_OK == Sys->getDriverInfo(i, name, sizeof(name), NULL)) +#endif { Printf("%d. %s\n", i, name); } @@ -1365,7 +1499,7 @@ FString FMODSoundRenderer::GatherStats() channels = 0; total = update = geometry = stream = dsp = 0; Sys->getChannelsPlaying(&channels); -#if FMOD_VERSION >= 0x42501 +#if FMOD_STUDIO || FMOD_VERSION >= 0x42501 // We were built with an FMOD with the geometry parameter. if (ActiveFMODVersion >= 0x42501) { // And we are running with an FMOD that includes it. @@ -1612,7 +1746,11 @@ static void SetCustomLoopPts(FMOD::Sound *sound) // //========================================================================== +#if FMOD_STUDIO +static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, unsigned int *filesize, void **handle, void *userdata) +#else static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata) +#endif { FileReader *reader = NULL; if(sscanf(name, "_FileReader_%p", &reader) != 1) @@ -1623,7 +1761,9 @@ static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, int unicode *filesize = reader->GetLength(); *handle = reader; +#if !FMOD_STUDIO *userdata = reader; +#endif return FMOD_OK; } @@ -1667,10 +1807,17 @@ SoundStream *FMODSoundRenderer::OpenStream(FileReader *reader, int flags) FString name; InitCreateSoundExInfo(&exinfo); +#if FMOD_STUDIO + exinfo.fileuseropen = open_reader_callback; + exinfo.fileuserclose = close_reader_callback; + exinfo.fileuserread = read_reader_callback; + exinfo.fileuserseek = seek_reader_callback; +#else exinfo.useropen = open_reader_callback; exinfo.userclose = close_reader_callback; exinfo.userread = read_reader_callback; exinfo.userseek = seek_reader_callback; +#endif mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM; if(flags & SoundStream::Loop) @@ -1775,7 +1922,11 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi FMOD::Channel *chan; float freq; +#if FMOD_STUDIO + if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&freq, NULL)) +#else if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&freq, NULL, NULL, NULL)) +#endif { freq = PITCH(freq, pitch); } @@ -1785,7 +1936,11 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi } GRolloff = NULL; // Do 2D sounds need rolloff? +#if FMOD_STUDIO + result = Sys->playSound((FMOD::Sound *)sfx.data, (flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx, true, &chan); +#else result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx.data, true, &chan); +#endif if (FMOD_OK == result) { result = chan->getMode(&mode); @@ -1809,7 +1964,9 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi mode |= FMOD_LOOP_OFF; } chan->setMode(mode); +#if !FMOD_STUDIO chan->setChannelGroup((flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx); +#endif if (freq != 0) { chan->setFrequency(freq); @@ -1822,12 +1979,16 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi } if (flags & SNDF_NOREVERB) { +#if FMOD_STUDIO + chan->setReverbProperties(0,0.f); +#else FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, }; if (FMOD_OK == chan->getReverbProperties(&reverb)) { reverb.Room = -10000; chan->setReverbProperties(&reverb); } +#endif } chan->setPaused(false); return CommonChannelSetup(chan, reuse_chan); @@ -1852,15 +2013,26 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * FMOD_MODE mode; FMOD::Channel *chan; float freq; - float def_freq, def_vol, def_pan; + float def_freq; +#if !FMOD_STUDIO + float def_vol, def_pan; +#endif int numchans; int def_priority; +#if FMOD_STUDIO + if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&def_freq, &def_priority)) +#else if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&def_freq, &def_vol, &def_pan, &def_priority)) +#endif { freq = PITCH(def_freq, pitch); // Change the sound's default priority before playing it. +#if FMOD_STUDIO + ((FMOD::Sound *)sfx.data)->setDefaults(def_freq, clamp(def_priority - priority, 1, 256)); +#else ((FMOD::Sound *)sfx.data)->setDefaults(def_freq, def_vol, def_pan, clamp(def_priority - priority, 1, 256)); +#endif } else { @@ -1876,12 +2048,20 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * // as long as the parameters are set properly. It will first try to kick out sounds // with the same priority level but has no problem with kicking out sounds at // higher priority levels if it needs to. +#if FMOD_STUDIO + result = Sys->playSound((FMOD::Sound *)sfx.data, (flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx, true, &chan); +#else result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx.data, true, &chan); +#endif // Then set the priority back. if (def_priority >= 0) { +#if FMOD_STUDIO + ((FMOD::Sound *)sfx.data)->setDefaults(def_freq, def_priority); +#else ((FMOD::Sound *)sfx.data)->setDefaults(def_freq, def_vol, def_pan, def_priority); +#endif } if (FMOD_OK == result) @@ -1906,7 +2086,9 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * } mode = SetChanHeadSettings(listener, chan, pos, !!(flags & SNDF_AREA), mode); chan->setMode(mode); +#if !FMOD_STUDIO chan->setChannelGroup((flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx); +#endif if (mode & FMOD_3D) { @@ -1941,12 +2123,16 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * } if (flags & SNDF_NOREVERB) { +#if FMOD_STUDIO + chan->setReverbProperties(0,0.f); +#else FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, }; if (FMOD_OK == chan->getReverbProperties(&reverb)) { reverb.Room = -10000; chan->setReverbProperties(&reverb); } +#endif } chan->setPaused(false); chan->getPriority(&def_priority); @@ -1970,7 +2156,14 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * void FMODSoundRenderer::MarkStartTime(FISoundChannel *chan) { +#if FMOD_STUDIO + unsigned long long int dsp_time; + ((FMOD::Channel *)chan->SysChannel)->getDSPClock(&dsp_time,NULL); + chan->StartTime.Lo = dsp_time & 0xFFFFFFFF; + chan->StartTime.Hi = dsp_time >> 32; +#else Sys->getDSPClock(&chan->StartTime.Hi, &chan->StartTime.Lo); +#endif } //========================================================================== @@ -1990,7 +2183,14 @@ bool FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FISoundChannel * { // Sound is being restarted, so seek it to the position // it would be in now if it had never been evicted. QWORD_UNION nowtime; +#if FMOD_STUDIO + unsigned long long int delay; + chan->getDelay(&delay,NULL,NULL); + nowtime.Lo = delay & 0xFFFFFFFF; + nowtime.Hi = delay >> 32; +#else chan->getDelay(FMOD_DELAYTYPE_DSPCLOCK_START, &nowtime.Hi, &nowtime.Lo); +#endif // If abstime is set, the sound is being restored, and // the channel's start time is actually its seek position. @@ -2078,14 +2278,24 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(SoundListener *listener, FMOD:: { // Beyond interp_range: Normal 3D panning. level = 1; } +#if FMOD_STUDIO + if (chan->get3DLevel(&old_level) == FMOD_OK && old_level != level) + { // Only set it if it's different. + chan->set3DLevel(level); +#else if (chan->get3DPanLevel(&old_level) == FMOD_OK && old_level != level) { // Only set it if it's different. chan->set3DPanLevel(level); +#endif if (level < 1) { // Let the noise come from all speakers, not just the front ones. // A centered 3D sound does not play at full volume, so neither should the 2D-panned one. // This is sqrt(0.5), which is the result for a centered equal power panning. +#if FMOD_STUDIO + chan->setMixLevelsOutput(0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f); +#else chan->setSpeakerMix(0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f); +#endif } } return oldmode; @@ -2119,7 +2329,14 @@ FISoundChannel *FMODSoundRenderer::CommonChannelSetup(FMOD::Channel *chan, FISou else { schan = S_GetChannel(chan); +#if FMOD_STUDIO + unsigned long long int time; + chan->getDelay(&time,NULL,NULL); + schan->StartTime.Lo = time & 0xFFFFFFFF; + schan->StartTime.Hi = time >> 32; +#else chan->getDelay(FMOD_DELAYTYPE_DSPCLOCK_START, &schan->StartTime.Hi, &schan->StartTime.Lo); +#endif } chan->setUserData(schan); chan->setCallback(ChannelCallback); @@ -2369,7 +2586,7 @@ void FMODSoundRenderer::UpdateListener(SoundListener *listener) if (LastWaterLP != snd_waterlp) { LastWaterLP = snd_waterlp; - WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp); + WaterLP->setParameterFloat(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp); } WaterLP->setActive(true); if (WaterReverb != NULL && snd_waterreverb) @@ -2481,7 +2698,14 @@ void FMODSoundRenderer::Sync(bool sync) if (sync) { Sys->lockDSP(); +#if FMOD_STUDIO + unsigned long long int clock; + SfxGroup->getDSPClock(&clock,NULL); + DSPClock.Lo = clock & 0xFFFFFFFF; + DSPClock.Hi = clock >> 32; +#else Sys->getDSPClock(&DSPClock.Hi, &DSPClock.Lo); +#endif } else { @@ -2499,7 +2723,14 @@ void FMODSoundRenderer::UpdateSounds() { // Any sounds played between now and the next call to this function // will start exactly one tic from now. +#if FMOD_STUDIO + unsigned long long int clock; + SfxGroup->getDSPClock(&clock,NULL); + DSPClock.Lo = clock & 0xFFFFFFFF; + DSPClock.Hi = clock >> 32; +#else Sys->getDSPClock(&DSPClock.Hi, &DSPClock.Lo); +#endif DSPClock.AsOne += OutputRate / TICRATE; Sys->update(); } @@ -2673,18 +2904,34 @@ unsigned int FMODSoundRenderer::GetSampleLength(SoundHandle sfx) //========================================================================== FMOD_RESULT F_CALLBACK FMODSoundRenderer::ChannelCallback +#if FMOD_STUDIO + (FMOD_CHANNELCONTROL *channel, FMOD_CHANNELCONTROL_TYPE controltype, FMOD_CHANNELCONTROL_CALLBACK_TYPE type, void *data1, void *data2) +#else (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *data1, void *data2) +#endif { +#if FMOD_STUDIO + FMOD::ChannelControl *chan = (FMOD::ChannelControl *)channel; +#else FMOD::Channel *chan = (FMOD::Channel *)channel; +#endif FISoundChannel *schan; if (chan->getUserData((void **)&schan) == FMOD_OK && schan != NULL) { +#if FMOD_STUDIO + if (type == FMOD_CHANNELCONTROL_CALLBACK_END) +#else if (type == FMOD_CHANNEL_CALLBACKTYPE_END) +#endif { S_ChannelEnded(schan); } +#if FMOD_STUDIO + else if (type == FMOD_CHANNELCONTROL_CALLBACK_VIRTUALVOICE) +#else else if (type == FMOD_CHANNEL_CALLBACKTYPE_VIRTUALVOICE) +#endif { S_ChannelVirtualChanged(schan, data1 != 0); } @@ -2701,9 +2948,17 @@ FMOD_RESULT F_CALLBACK FMODSoundRenderer::ChannelCallback // //========================================================================== +#if FMOD_STUDIO +float F_CALLBACK FMODSoundRenderer::RolloffCallback(FMOD_CHANNELCONTROL *channel, float distance) +#else float F_CALLBACK FMODSoundRenderer::RolloffCallback(FMOD_CHANNEL *channel, float distance) +#endif { +#if FMOD_STUDIO + FMOD::ChannelControl *chan = (FMOD::ChannelControl *)channel; +#else FMOD::Channel *chan = (FMOD::Channel *)channel; +#endif FISoundChannel *schan; if (GRolloff != NULL) @@ -2742,7 +2997,11 @@ void FMODSoundRenderer::DrawWaveDebug(int mode) const spk *labels; int labelcount; +#if FMOD_STUDIO + if (FMOD_OK != Sys->getSoftwareFormat(NULL, NULL, &numoutchans)) +#else if (FMOD_OK != Sys->getSoftwareFormat(NULL, NULL, &numoutchans, NULL, NULL, NULL)) +#endif { return; } @@ -2866,12 +3125,14 @@ int FMODSoundRenderer::DrawChannelGroupWaveData(FMOD::ChannelGroup *group, float int drawn = 0; int x = 16; +#if !FMOD_STUDIO while (FMOD_OK == group->getWaveData(wavearray, width, drawn)) { drawn++; DrawWave(wavearray, x, y, width, height); x += (width + 16) << int(skip); } +#endif if (drawn) { y += height + 16; @@ -2893,12 +3154,14 @@ int FMODSoundRenderer::DrawSystemWaveData(float *wavearray, int width, int heigh int drawn = 0; int x = 16; +#if !FMOD_STUDIO while (FMOD_OK == Sys->getWaveData(wavearray, width, drawn)) { drawn++; DrawWave(wavearray, x, y, width, height); x += (width + 16) << int(skip); } +#endif if (drawn) { y += height + 16; @@ -2970,12 +3233,15 @@ int FMODSoundRenderer::DrawChannelGroupSpectrum(FMOD::ChannelGroup *group, float { x += width + 16; } + // TODO: FMOD Studio: Grab from DSP +#if !FMOD_STUDIO while (FMOD_OK == group->getSpectrum(spectrumarray, SPECTRUM_SIZE, drawn, FMOD_DSP_FFT_WINDOW_TRIANGLE)) { drawn++; DrawSpectrum(spectrumarray, x, y, width, height); x += (width + 16) << int(skip); } +#endif if (drawn) { y += height + 16; @@ -3001,12 +3267,15 @@ int FMODSoundRenderer::DrawSystemSpectrum(float *spectrumarray, int width, int h { x += width + 16; } + // TODO: FMOD Studio: Grab from DSP +#if !FMOD_STUDIO while (FMOD_OK == Sys->getSpectrum(spectrumarray, SPECTRUM_SIZE, drawn, FMOD_DSP_FFT_WINDOW_TRIANGLE)) { drawn++; DrawSpectrum(spectrumarray, x, y, width, height); x += (width + 16) << int(skip); } +#endif if (drawn) { y += height + 16; @@ -3121,7 +3390,7 @@ short *FMODSoundRenderer::DecodeSample(int outlen, const void *coded, int sizeby void FMODSoundRenderer::InitCreateSoundExInfo(FMOD_CREATESOUNDEXINFO *exinfo) const { memset(exinfo, 0, sizeof(*exinfo)); -#if FMOD_VERSION >= 0x42600 && FMOD_VERSION < 0x43800 +#if !FMOD_STUDIO && FMOD_VERSION >= 0x42600 && FMOD_VERSION < 0x43800 if (ActiveFMODVersion < 0x42600) { // This parameter was added for 4.26.00, and trying to pass it to older @@ -3145,13 +3414,32 @@ void FMODSoundRenderer::InitCreateSoundExInfo(FMOD_CREATESOUNDEXINFO *exinfo) co FMOD_RESULT FMODSoundRenderer::SetSystemReverbProperties(const REVERB_PROPERTIES *props) { -#if FMOD_VERSION < 0x43600 +#if !FMOD_STUDIO && FMOD_VERSION < 0x43600 return Sys->setReverbProperties((const FMOD_REVERB_PROPERTIES *)props); #else // The reverb format changed when hardware mixing support was dropped, because // all EAX-only properties were removed from the structure. FMOD_REVERB_PROPERTIES fr; +#if FMOD_STUDIO + const float LateEarlyRatio = powf(10.f, (props->Reverb - props->Reflections)/2000.f); + const float EarlyAndLatePower = powf(10.f, props->Reflections/1000.f) + powf(10, props->Reverb/1000.f); + const float HFGain = powf(10.f, props->RoomHF/2000.f); + fr.DecayTime = props->DecayTime*1000.f; + fr.EarlyDelay = props->ReflectionsDelay*1000.f; + fr.LateDelay = props->ReverbDelay*1000.f; + fr.HFReference = props->HFReference; + fr.HFDecayRatio = clamp(props->DecayHFRatio*100.f, 0.f, 100.f); + fr.Diffusion = props->Diffusion; + fr.Density = props->Density; + fr.LowShelfFrequency = props->DecayLFRatio; + fr.LowShelfGain = clamp(props->RoomLF/100.f, -48.f, 12.f); + fr.HighCut = clamp(props->RoomLF < 0 ? props->HFReference/sqrtf((1.f-HFGain)/HFGain) : 20000.f, 20.f, 20000.f); + fr.EarlyLateMix = props->Reflections > -10000.f ? LateEarlyRatio/(LateEarlyRatio + 1)*100.f : 100.f; + fr.WetLevel = clamp(10*log10f(EarlyAndLatePower)+props->Room/100.f, -80.f, 20.f); + + return Sys->setReverbProperties(0, &fr); +#else fr.Instance = props->Instance; fr.Environment = props->Environment; fr.EnvDiffusion = props->EnvDiffusion; @@ -3175,6 +3463,7 @@ FMOD_RESULT FMODSoundRenderer::SetSystemReverbProperties(const REVERB_PROPERTIES return Sys->setReverbProperties(&fr); #endif +#endif } #endif // NO_FMOD diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 33b1f4bf7..e85a993c5 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -76,8 +76,13 @@ private: QWORD_UNION DSPClock; int OutputRate; +#if FMOD_STUDIO + static FMOD_RESULT F_CALLBACK ChannelCallback(FMOD_CHANNELCONTROL *channel, FMOD_CHANNELCONTROL_TYPE controltype, FMOD_CHANNELCONTROL_CALLBACK_TYPE type, void *data1, void *data2); + static float F_CALLBACK RolloffCallback(FMOD_CHANNELCONTROL *channel, float distance); +#else static FMOD_RESULT F_CALLBACK ChannelCallback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *data1, void *data2); static float F_CALLBACK RolloffCallback(FMOD_CHANNEL *channel, float distance); +#endif bool HandleChannelDelay(FMOD::Channel *chan, FISoundChannel *reuse_chan, int flags, float freq) const; FISoundChannel *CommonChannelSetup(FMOD::Channel *chan, FISoundChannel *reuse_chan) const; @@ -89,7 +94,9 @@ private: bool Init (); void Shutdown (); +#if !FMOD_STUDIO void DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int maxfrequency); +#endif int DrawChannelGroupOutput(FMOD::ChannelGroup *group, float *wavearray, int width, int height, int y, int mode); int DrawSystemOutput(float *wavearray, int width, int height, int y, int mode); @@ -121,7 +128,9 @@ private: // Just for snd_status display int Driver_MinFrequency; int Driver_MaxFrequency; +#if !FMOD_STUDIO FMOD_CAPS Driver_Caps; +#endif friend class FMODStreamCapsule; }; From e04055dbb2e733b747fddbb90b46b39a4cc567e9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 28 Aug 2016 09:55:04 +0200 Subject: [PATCH 41/97] - added multiple message levels for 'developer' CVAR so that the important stuff won't get drowned in pointless notification spam that's of no use to anyone. - made 'developer' CVAR persist across launches and added some menu entries for it. - added checks for 'developer' to ACS's CheckInventory function. --- src/b_game.cpp | 2 +- src/c_console.cpp | 4 +- src/compatibility.cpp | 2 +- src/d_dehacked.cpp | 54 +++++++++++------------ src/d_net.cpp | 2 +- src/dobjtype.cpp | 12 ++--- src/doomstat.cpp | 2 +- src/doomstat.h | 2 +- src/doomtype.h | 22 +++++---- src/farchive.cpp | 6 +-- src/g_shared/a_decals.cpp | 4 +- src/i_net.cpp | 2 +- src/p_acs.cpp | 22 ++++----- src/p_conversation.cpp | 6 +-- src/p_glnodes.cpp | 6 +-- src/p_maputl.cpp | 2 +- src/p_setup.cpp | 12 ++--- src/p_spec.cpp | 4 +- src/p_tick.cpp | 2 +- src/p_udmf.cpp | 2 +- src/p_user.cpp | 6 +-- src/posix/sdl/hardware.cpp | 8 ++-- src/r_segs.cpp | 4 +- src/r_things.cpp | 12 +++-- src/resourcefiles/file_wad.cpp | 6 +-- src/s_playlist.cpp | 6 +-- src/s_sound.cpp | 8 ++-- src/sc_man.cpp | 2 +- src/sound/fmodsound.cpp | 10 ++--- src/sound/i_sound.cpp | 4 +- src/sound/music_fluidsynth_mididevice.cpp | 4 +- src/sound/music_midi_timidity.cpp | 2 +- src/sound/music_xmi_midiout.cpp | 2 +- src/sound/oalsound.cpp | 26 +++++------ src/v_video.cpp | 5 ++- src/win32/win32video.cpp | 6 +-- wadsrc/static/language.enu | 5 +++ wadsrc/static/menudef.txt | 10 +++++ 38 files changed, 157 insertions(+), 139 deletions(-) diff --git a/src/b_game.cpp b/src/b_game.cpp index 9681aa7a8..9d6419787 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -494,7 +494,7 @@ bool FCajunMaster::LoadBots () tmp = M_GetCajunPath(BOTFILENAME); if (tmp.IsEmpty()) { - DPrintf ("No " BOTFILENAME ", so no bots\n"); + DPrintf (DMSG_ERROR, "No " BOTFILENAME ", so no bots\n"); return false; } try diff --git a/src/c_console.cpp b/src/c_console.cpp index 9a9274aa1..850a29455 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -612,12 +612,12 @@ int Printf (const char *format, ...) return count; } -int DPrintf (const char *format, ...) +int DPrintf (int level, const char *format, ...) { va_list argptr; int count; - if (developer) + if (developer >= level) { va_start (argptr, format); count = VPrintf (PRINT_HIGH, format, argptr); diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 5bb51129a..24897ac27 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -399,7 +399,7 @@ void CheckCompatibility(MapData *map) flags = BCompatMap.CheckKey(md5); - if (developer) + if (developer >= DMSG_NOTIFY) { Printf("MD5 = "); for (size_t j = 0; j < sizeof(md5.Bytes); ++j) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 29a087fac..4beb5c25a 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -450,7 +450,7 @@ int FindStyle (const char *namestr) { if (!stricmp(StyleNames[i].Name, namestr)) return StyleNames[i].Num; } - DPrintf("Unknown render style %s\n", namestr); + DPrintf(DMSG_ERROR, "Unknown render style %s\n", namestr); return -1; } @@ -861,7 +861,7 @@ static int PatchThing (int thingy) } else { - DPrintf ("Thing %d\n", thingy); + DPrintf (DMSG_SPAMMY, "Thing %d\n", thingy); if (thingy > 0) { type = InfoNames[thingy - 1]; @@ -1086,7 +1086,7 @@ static int PatchThing (int thingy) } if (i == BitNames.Size()) { - DPrintf("Unknown bit mnemonic %s\n", strval); + DPrintf(DMSG_ERROR, "Unknown bit mnemonic %s\n", strval); } } } @@ -1242,7 +1242,7 @@ static int PatchThing (int thingy) else info->renderflags &= ~RF_INVISIBLE; } - DPrintf ("Bits: %d,%d (0x%08x,0x%08x)\n", info->flags.GetValue(), info->flags2.GetValue(), + DPrintf (DMSG_SPAMMY, "Bits: %d,%d (0x%08x,0x%08x)\n", info->flags.GetValue(), info->flags2.GetValue(), info->flags.GetValue(), info->flags2.GetValue()); } else if (stricmp (Line1, "ID #") == 0) @@ -1328,7 +1328,7 @@ static int PatchSound (int soundNum) { int result; - DPrintf ("Sound %d (no longer supported)\n", soundNum); + //DPrintf ("Sound %d (no longer supported)\n", soundNum); /* sfxinfo_t *info, dummy; int offset = 0; @@ -1385,7 +1385,7 @@ static int PatchFrame (int frameNum) info = FindState (frameNum); if (info) { - DPrintf ("Frame %d\n", frameNum); + DPrintf (DMSG_SPAMMY, "Frame %d\n", frameNum); if (frameNum == 47) { // Use original tics for S_DSGUNFLASH1 tics = 5; @@ -1487,7 +1487,7 @@ static int PatchSprite (int sprNum) if ((unsigned)sprNum < OrgSprNames.Size()) { - DPrintf ("Sprite %d\n", sprNum); + DPrintf (DMSG_SPAMMY, "Sprite %d\n", sprNum); } else { @@ -1534,7 +1534,7 @@ static int PatchAmmo (int ammoNum) if (ammoNum >= 0 && ammoNum < 4 && (unsigned)ammoNum <= AmmoNames.Size()) { - DPrintf ("Ammo %d.\n", ammoNum); + DPrintf (DMSG_SPAMMY, "Ammo %d.\n", ammoNum); ammoType = AmmoNames[ammoNum]; if (ammoType != NULL) { @@ -1617,7 +1617,7 @@ static int PatchWeapon (int weapNum) if (type != NULL) { info = (AWeapon *)GetDefaultByType (type); - DPrintf ("Weapon %d\n", weapNum); + DPrintf (DMSG_SPAMMY, "Weapon %d\n", weapNum); } } @@ -1757,7 +1757,7 @@ static int PatchPointer (int ptrNum) { if (CodePConv[ptrNum] == indexnum) break; } - DPrintf("Final ptrNum: %i\n", ptrNum); + DPrintf(DMSG_SPAMMY, "Final ptrNum: %i\n", ptrNum); } // End of hack. @@ -1765,7 +1765,7 @@ static int PatchPointer (int ptrNum) // Better to just use the size of the array rather than a hardcoded value. if (ptrNum >= 0 && (unsigned int) ptrNum < CodePConv.Size()) { - DPrintf ("Pointer %d\n", ptrNum); + DPrintf (DMSG_SPAMMY, "Pointer %d\n", ptrNum); } else { @@ -1789,7 +1789,7 @@ static int PatchPointer (int ptrNum) { SetPointer(state, Actions[index], CodePConv[ptrNum]); } - DPrintf("%s has a hacked state for pointer num %i with index %i\nLine1=%s, Line2=%s\n", + DPrintf(DMSG_SPAMMY, "%s has a hacked state for pointer num %i with index %i\nLine1=%s, Line2=%s\n", state->StaticFindStateOwner(state)->TypeName.GetChars(), ptrNum, index, Line1, Line2); } else @@ -1806,7 +1806,7 @@ static int PatchCheats (int dummy) { int result; - DPrintf ("Cheats (support removed by request)\n"); + DPrintf (DMSG_NOTIFY, "Dehacked cheats support removed by request\n"); while ((result = GetLine ()) == 1) { @@ -1836,7 +1836,7 @@ static int PatchMisc (int dummy) }; int result; - DPrintf ("Misc\n"); + DPrintf (DMSG_SPAMMY, "Misc\n"); while ((result = GetLine()) == 1) { @@ -2017,7 +2017,7 @@ static int PatchPars (int dummy) level_info_t *info; int result, par; - DPrintf ("[Pars]\n"); + DPrintf (DMSG_SPAMMY, "[Pars]\n"); while ( (result = GetLine()) ) { // Argh! .bex doesn't follow the same rules as .deh @@ -2058,7 +2058,7 @@ static int PatchPars (int dummy) } info->partime = par; - DPrintf ("Par for %s changed to %d\n", mapname, par); + DPrintf (DMSG_SPAMMY, "Par for %s changed to %d\n", mapname, par); } return result; } @@ -2067,7 +2067,7 @@ static int PatchCodePtrs (int dummy) { int result; - DPrintf ("[CodePtr]\n"); + DPrintf (DMSG_SPAMMY, "[CodePtr]\n"); while ((result = GetLine()) == 1) { @@ -2132,7 +2132,7 @@ static int PatchMusic (int dummy) { int result; - DPrintf ("[Music]\n"); + DPrintf (DMSG_SPAMMY, "[Music]\n"); while ((result = GetLine()) == 1) { @@ -2142,7 +2142,7 @@ static int PatchMusic (int dummy) keystring << "MUSIC_" << Line1; GStrings.SetString (keystring, newname); - DPrintf ("Music %s set to:\n%s\n", keystring.GetChars(), newname); + DPrintf (DMSG_SPAMMY, "Music %s set to:\n%s\n", keystring.GetChars(), newname); } return result; @@ -2198,7 +2198,7 @@ static int PatchText (int oldSize) goto donewithtext; } - DPrintf ("Searching for text:\n%s\n", oldStr); + DPrintf (DMSG_SPAMMY, "Searching for text:\n%s\n", oldStr); good = false; // Search through sprite names; they are always 4 chars @@ -2264,7 +2264,7 @@ static int PatchText (int oldSize) if (!good) { - DPrintf (" (Unmatched)\n"); + DPrintf (DMSG_SPAMMY, " (Unmatched)\n"); } donewithtext: @@ -2284,7 +2284,7 @@ static int PatchStrings (int dummy) { int result; - DPrintf ("[Strings]\n"); + DPrintf (DMSG_SPAMMY, "[Strings]\n"); while ((result = GetLine()) == 1) { @@ -2310,7 +2310,7 @@ static int PatchStrings (int dummy) const char *ll = Line1; if (!stricmp(ll, "GOTREDSKULL")) ll = "GOTREDSKUL"; GStrings.SetString (ll, holdstring); - DPrintf ("%s set to:\n%s\n", Line1, holdstring.GetChars()); + DPrintf (DMSG_SPAMMY, "%s set to:\n%s\n", Line1, holdstring.GetChars()); } return result; @@ -2350,7 +2350,7 @@ static int DoInclude (int dummy) else { data = Line2; - DPrintf ("Including %s\n", data); + DPrintf (DMSG_SPAMMY, "Including %s\n", data); savepatchname = PatchName; savepatchfile = PatchFile; savepatchpt = PatchPt; @@ -2384,7 +2384,7 @@ static int DoInclude (int dummy) delete[] path; } - DPrintf ("Done with include\n"); + DPrintf (DMSG_SPAMMY, "Done with include\n"); PatchName = savepatchname; PatchFile = savepatchfile; PatchPt = savepatchpt; @@ -2536,7 +2536,7 @@ static bool DoDehPatch() } else { - DPrintf ("Patch does not have DeHackEd signature. Assuming .bex\n"); + DPrintf (DMSG_WARNING, "Patch does not have DeHackEd signature. Assuming .bex\n"); dversion = 19; pversion = 6; PatchPt = PatchFile; @@ -3027,7 +3027,7 @@ void FinishDehPatch () subclass->Replacement = old_replacement; } - DPrintf ("%s replaces %s\n", subclass->TypeName.GetChars(), type->TypeName.GetChars()); + DPrintf (DMSG_NOTIFY, "%s replaces %s\n", subclass->TypeName.GetChars(), type->TypeName.GetChars()); } // Now that all Dehacked patches have been processed, it's okay to free StateMap. diff --git a/src/d_net.cpp b/src/d_net.cpp index eadd47d96..261133867 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -231,7 +231,7 @@ static struct TicSpecial specialsize = MAX(specialsize * 2, needed + 30); - DPrintf ("Expanding special size to %zu\n", specialsize); + DPrintf (DMSG_NOTIFY, "Expanding special size to %zu\n", specialsize); for (i = 0; i < BACKUPTICS; i++) streams[i] = (BYTE *)M_Realloc (streams[i], specialsize); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index a7f07247f..7a593c5fe 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2134,7 +2134,7 @@ bool PArray::ReadValue(FArchive &ar, void *addr) const } if (i < ElementCount) { - DPrintf("Array on disk (%u) is bigger than in memory (%u)\n", + DPrintf(DMSG_WARNING, "Array on disk (%u) is bigger than in memory (%u)\n", count, ElementCount); for (; i < ElementCount; ++i) { @@ -2501,13 +2501,13 @@ bool PStruct::ReadFields(FArchive &ar, void *addr) const const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true); if (sym == NULL) { - DPrintf("Cannot find field %s in %s\n", + DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", label, TypeName.GetChars()); SkipValue(ar); } else if (!sym->IsKindOf(RUNTIME_CLASS(PField))) { - DPrintf("Symbol %s in %s is not a field\n", + DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n", label, TypeName.GetChars()); SkipValue(ar); } @@ -2806,7 +2806,7 @@ bool PClass::ReadValue(FArchive &ar, void *addr) const } else { - DPrintf("Unknown superclass %s of class %s\n", + DPrintf(DMSG_ERROR, "Unknown superclass %s of class %s\n", type->TypeName.GetChars(), TypeName.GetChars()); SkipValue(ar, VAL_Struct); } @@ -3243,7 +3243,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); } - DPrintf("Defining placeholder class %s\n", name.GetChars()); + DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); notnew = true; } else @@ -3327,7 +3327,7 @@ PClass *PClass::FindClassTentative(FName name, bool fatal) return static_cast(found); } PClass *type = static_cast(GetClass()->CreateNew()); - DPrintf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); + DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); type->TypeName = name; type->ParentClass = this; diff --git a/src/doomstat.cpp b/src/doomstat.cpp index d693aae1b..87ca50a16 100644 --- a/src/doomstat.cpp +++ b/src/doomstat.cpp @@ -39,7 +39,7 @@ FStringTable GStrings; EGameSpeed GameSpeed = SPEED_Normal; // Show developer messages if true. -CVAR (Bool, developer, false, 0) +CVAR (Int, developer, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // [RH] Feature control cvars CVAR (Bool, var_friction, true, CVAR_SERVERINFO); diff --git a/src/doomstat.h b/src/doomstat.h index cfdca5e5a..bbb323c7e 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -204,7 +204,7 @@ extern int bodyqueslot; // ---- [RH] ---- -EXTERN_CVAR (Bool, developer) +EXTERN_CVAR (Int, developer) extern bool ToggleFullscreen; diff --git a/src/doomtype.h b/src/doomtype.h index 39c59751d..34f750313 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -147,7 +147,7 @@ int Printf (int printlevel, const char *, ...) GCCPRINTF(2,3); int Printf (const char *, ...) GCCPRINTF(1,2); // [RH] Same here: -int DPrintf (const char *, ...) GCCPRINTF(1,2); +int DPrintf (int level, const char *, ...) GCCPRINTF(2,3); extern "C" int mysnprintf(char *buffer, size_t count, const char *format, ...) GCCPRINTF(3,4); extern "C" int myvsnprintf(char *buffer, size_t count, const char *format, va_list argptr) GCCFORMAT(3); @@ -160,15 +160,19 @@ enum PRINT_MEDIUM, // death messages PRINT_HIGH, // critical messages PRINT_CHAT, // chat messages - PRINT_TEAMCHAT // chat messages from a teammate + PRINT_TEAMCHAT, // chat messages from a teammate + PRINT_LOG, // only to logfile + PRINT_BOLD = 200 // What Printf_Bold used +}; + +enum +{ + DMSG_OFF, // no developer messages. + DMSG_ERROR, // general notification messages + DMSG_WARNING, // warnings + DMSG_NOTIFY, // general notification messages + DMSG_SPAMMY, // for those who want to see everything, regardless of its usefulness. }; -#define PRINT_LOW 0 // pickup messages -#define PRINT_MEDIUM 1 // death messages -#define PRINT_HIGH 2 // critical messages -#define PRINT_CHAT 3 // chat messages -#define PRINT_TEAMCHAT 4 // chat messages from a teammate -#define PRINT_LOG 5 // only to logfile -#define PRINT_BOLD 200 // What Printf_Bold used struct PalEntry { diff --git a/src/farchive.cpp b/src/farchive.cpp index 317abe702..de3e248a4 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -354,12 +354,12 @@ void FCompressedFile::Implode () // If the data could not be compressed, store it as-is. if (r != Z_OK || outlen >= len) { - DPrintf ("cfile could not be compressed\n"); + DPrintf (DMSG_SPAMMY, "cfile could not be compressed\n"); outlen = 0; } else { - DPrintf ("cfile shrank from %lu to %lu bytes\n", len, outlen); + DPrintf (DMSG_SPAMMY, "cfile shrank from %lu to %lu bytes\n", len, outlen); } } else @@ -717,7 +717,7 @@ void FArchive::Close () { m_File->Close (); m_File = NULL; - DPrintf ("Processed %u objects\n", ArchiveToObject.Size()); + DPrintf (DMSG_SPAMMY, "Processed %u objects\n", ArchiveToObject.Size()); } } diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index c37c1065a..94e92e725 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -825,13 +825,13 @@ void ADecal::BeginPlay () // without effectively doing anything. if (NULL == ShootDecal(tpl, this, Sector, X(), Y(), Z(), Angles.Yaw + 180, 64., true)) { - DPrintf ("Could not find a wall to stick decal to at (%f,%f)\n", X(), Y()); + DPrintf (DMSG_WARNING, "Could not find a wall to stick decal to at (%f,%f)\n", X(), Y()); } } } else { - DPrintf ("Decal actor at (%f,%f) does not have a good template\n", X(), Y()); + DPrintf (DMSG_ERROR, "Decal actor at (%f,%f) does not have a good template\n", X(), Y()); } // This actor doesn't need to stick around anymore. Destroy(); diff --git a/src/i_net.cpp b/src/i_net.cpp index 5957846d2..e03f50a6b 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -322,7 +322,7 @@ void PacketGet (void) // Don't show the message for disconnect notifications. if (c != 2 || TransmitBuffer[0] != PRE_FAKE || TransmitBuffer[1] != PRE_DISCONNECT) { - DPrintf("Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port); + DPrintf(DMSG_WARNING, "Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port); } doomcom.remotenode = -1; return; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 0762b3e29..5f08f0152 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1331,12 +1331,12 @@ static int CheckInventory (AActor *activator, const char *type, bool max) if (info == NULL) { - Printf ("ACS: I don't know what '%s' is.\n", type); + DPrintf (DMSG_ERROR, "ACS: '%s': Unknown actor class.\n", type); return 0; } else if (!info->IsDescendantOf(RUNTIME_CLASS(AInventory))) { - Printf ("ACS: '%s' is not an inventory item.\n", type); + DPrintf(DMSG_ERROR, "ACS: '%s' is not an inventory item.\n", type); return 0; } @@ -2237,7 +2237,7 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len) } } - DPrintf ("Loaded %d scripts, %d functions\n", NumScripts, NumFunctions); + DPrintf (DMSG_NOTIFY, "Loaded %d scripts, %d functions\n", NumScripts, NumFunctions); return true; } @@ -2824,7 +2824,7 @@ void FBehavior::StaticStartTypedScripts (WORD type, AActor *activator, bool alwa "Disconnect", "Return" }; - DPrintf("Starting all scripts of type %d (%s)\n", type, + DPrintf(DMSG_NOTIFY, "Starting all scripts of type %d (%s)\n", type, type < countof(TypeNames) ? TypeNames[type] : TypeNames[SCRIPT_Lightning - 1]); for (unsigned int i = 0; i < StaticModules.Size(); ++i) { @@ -6209,7 +6209,7 @@ int DLevelScript::RunScript () activeBehavior = savedActiveBehavior; // fall through case PCD_TERMINATE: - DPrintf ("%s finished\n", ScriptPresentation(script).GetChars()); + DPrintf (DMSG_NOTIFY, "%s finished\n", ScriptPresentation(script).GetChars()); state = SCRIPT_PleaseRemove; break; @@ -7646,7 +7646,7 @@ scriptwait: if (activationline != NULL) { activationline->special = 0; - DPrintf("Cleared line special on line %d\n", (int)(activationline - lines)); + DPrintf(DMSG_SPAMMY, "Cleared line special on line %d\n", (int)(activationline - lines)); } break; @@ -8285,7 +8285,7 @@ scriptwait: line->args[2] = STACK(3); line->args[3] = STACK(2); line->args[4] = STACK(1); - DPrintf("Set special on line %d (id %d) to %d(%d,%d,%d,%d,%d)\n", + DPrintf(DMSG_SPAMMY, "Set special on line %d (id %d) to %d(%d,%d,%d,%d,%d)\n", linenum, STACK(7), specnum, arg0, STACK(4), STACK(3), STACK(2), STACK(1)); } sp -= 7; @@ -9663,7 +9663,7 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr PutLast(); } - DPrintf("%s started.\n", ScriptPresentation(num).GetChars()); + DPrintf(DMSG_SPAMMY, "%s started.\n", ScriptPresentation(num).GetChars()); } static void SetScriptState (int script, DLevelScript::EScriptState state) @@ -9710,12 +9710,12 @@ void P_DoDeferedScripts () case acsdefered_t::defsuspend: SetScriptState (def->script, DLevelScript::SCRIPT_Suspended); - DPrintf ("Deferred suspend of %s\n", ScriptPresentation(def->script).GetChars()); + DPrintf (DMSG_SPAMMY, "Deferred suspend of %s\n", ScriptPresentation(def->script).GetChars()); break; case acsdefered_t::defterminate: SetScriptState (def->script, DLevelScript::SCRIPT_PleaseRemove); - DPrintf ("Deferred terminate of %s\n", ScriptPresentation(def->script).GetChars()); + DPrintf (DMSG_SPAMMY, "Deferred terminate of %s\n", ScriptPresentation(def->script).GetChars()); break; } delete def; @@ -9751,7 +9751,7 @@ static void addDefered (level_info_t *i, acsdefered_t::EType type, int script, c def->playernum = -1; } i->defered = def; - DPrintf ("%s on map %s deferred\n", ScriptPresentation(script).GetChars(), i->MapName.GetChars()); + DPrintf (DMSG_SPAMMY, "%s on map %s deferred\n", ScriptPresentation(script).GetChars(), i->MapName.GetChars()); } } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 64fe2cbab..545603368 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -253,7 +253,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc if ((type == 1 && !isbinary) || (type == 2 && isbinary)) { - DPrintf("Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); return false; } @@ -273,7 +273,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // is exactly 1516 bytes long. if (numnodes % 1516 != 0) { - DPrintf("Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1516; @@ -283,7 +283,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // And the teaser version has 1488-byte entries. if (numnodes % 1488 != 0) { - DPrintf("Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1488; diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 0fe4cd9c0..39c8f8e0d 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -1013,7 +1013,7 @@ bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime) subsectors, numsubsectors, vertexes, numvertexes); endTime = I_FPSTime (); - DPrintf ("BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs); + DPrintf (DMSG_NOTIFY, "BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs); buildtime = endTime - startTime; } } @@ -1026,12 +1026,12 @@ bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime) #endif if (level.maptype != MAPTYPE_BUILD && gl_cachenodes && buildtime/1000.f >= gl_cachetime) { - DPrintf("Caching nodes\n"); + DPrintf(DMSG_NOTIFY, "Caching nodes\n"); CreateCachedNodes(map); } else { - DPrintf("Not caching nodes (time = %f)\n", buildtime/1000.f); + DPrintf(DMSG_NOTIFY, "Not caching nodes (time = %f)\n", buildtime/1000.f); } } diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 5fa8aa2f2..a3d4d0e9e 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -361,7 +361,7 @@ bool AActor::FixMapthingPos() if (distance < radius) { - DPrintf("%s at (%f,%f) lies on %s line %td, distance = %f\n", + DPrintf(DMSG_NOTIFY, "%s at (%f,%f) lies on %s line %td, distance = %f\n", this->GetClass()->TypeName.GetChars(), X(), Y(), ldef->Delta().X == 0 ? "vertical" : ldef->Delta().Y == 0 ? "horizontal" : "diagonal", ldef - lines, distance); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 92636fb0c..d8d95d277 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1689,7 +1689,7 @@ static void SetMapThingUserData(AActor *actor, unsigned udi) if (var == NULL || (var->Flags & VARF_Native) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) { - DPrintf("%s is not a user variable in class %s\n", varname.GetChars(), + DPrintf(DMSG_WARNING, "%s is not a user variable in class %s\n", varname.GetChars(), actor->GetClass()->TypeName.GetChars()); } else @@ -2477,7 +2477,7 @@ int P_DetermineTranslucency (int lumpnum) if (newcolor2.r == 255) // if black on white results in white it's either // fully transparent or additive { - if (developer) + if (developer >= DMSG_NOTIFY) { char lumpname[9]; lumpname[8] = 0; @@ -2488,7 +2488,7 @@ int P_DetermineTranslucency (int lumpnum) return -newcolor.r; } - if (developer) + if (developer >= DMSG_NOTIFY) { char lumpname[9]; lumpname[8] = 0; @@ -3028,7 +3028,7 @@ void P_LoadBlockMap (MapData * map) Args->CheckParm("-blockmap") ) { - DPrintf ("Generating BLOCKMAP\n"); + DPrintf (DMSG_SPAMMY, "Generating BLOCKMAP\n"); P_CreateBlockMap (); } else @@ -3060,7 +3060,7 @@ void P_LoadBlockMap (MapData * map) if (!P_VerifyBlockMap(count)) { - DPrintf ("Generating BLOCKMAP\n"); + DPrintf (DMSG_SPAMMY, "Generating BLOCKMAP\n"); P_CreateBlockMap(); } @@ -3957,7 +3957,7 @@ void P_SetupLevel (const char *lumpname, int position) subsectors, numsubsectors, vertexes, numvertexes); endTime = I_FPSTime (); - DPrintf ("BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs); + DPrintf (DMSG_NOTIFY, "BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs); oldvertextable = builder.GetOldVertexTable(); reloop = true; } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 67bb4de73..4c3bdb488 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -186,7 +186,7 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType, DVe line->special = 0; } // end of changed code - if (developer && buttonSuccess) + if (developer >= DMSG_SPAMMY && buttonSuccess) { Printf ("Line special %d activated on line %i\n", special, int(line - lines)); } @@ -358,7 +358,7 @@ bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType) special = line->special; // end of changed code - if (developer && buttonSuccess) + if (developer >= DMSG_SPAMMY && buttonSuccess) { Printf("Line special %d predicted on line %i\n", special, int(line - lines)); } diff --git a/src/p_tick.cpp b/src/p_tick.cpp index 978c2c7ef..332b7af81 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -42,7 +42,7 @@ extern gamestate_t wipegamestate; // // P_CheckTickerPaused // -// Returns true if the ticker should be paused. In that cause, it also +// Returns true if the ticker should be paused. In that case, it also // pauses sound effects and possibly music. If the ticker should not be // paused, then it returns false but does not unpause anything. // diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 86116f881..0b054247e 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -147,7 +147,7 @@ extern TArray linemap; void UDMFParserBase::Skip() { - if (developer) sc.ScriptMessage("Ignoring unknown key \"%s\".", sc.String); + if (developer >= DMSG_WARNING) sc.ScriptMessage("Ignoring unknown UDMF key \"%s\".", sc.String); if(sc.CheckToken('{')) { int level = 1; diff --git a/src/p_user.cpp b/src/p_user.cpp index e4b6ec6bd..b602432b3 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2441,7 +2441,7 @@ void P_PlayerThink (player_t *player) S_ChangeMusic("*"); } } - DPrintf("MUSINFO change for player %d to %d\n", (int)(player - players), player->MUSINFOactor->args[0]); + DPrintf(DMSG_NOTIFY, "MUSINFO change for player %d to %d\n", (int)(player - players), player->MUSINFOactor->args[0]); } } @@ -2828,9 +2828,9 @@ void P_PredictPlayer (player_t *player) DoLerp = (int)PredictionLast.pos.X != (int)player->mo->X() || (int)PredictionLast.pos.Y != (int)player->mo->Y(); // Aditional Debug information - if (developer && DoLerp) + if (developer >= DMSG_NOTIFY && DoLerp) { - DPrintf("Lerp! Ltic (%d) && Ptic (%d) | Lx (%f) && Px (%f) | Ly (%f) && Py (%f)\n", + DPrintf(DMSG_NOTIFY, "Lerp! Ltic (%d) && Ptic (%d) | Lx (%f) && Px (%f) | Ly (%f) && Py (%f)\n", PredictionLast.gametic, i, (PredictionLast.pos.X), (player->mo->X()), (PredictionLast.pos.Y), (player->mo->Y())); diff --git a/src/posix/sdl/hardware.cpp b/src/posix/sdl/hardware.cpp index 6142eb1d8..8bae3f900 100644 --- a/src/posix/sdl/hardware.cpp +++ b/src/posix/sdl/hardware.cpp @@ -242,18 +242,18 @@ void I_SetFPSLimit(int limit) } if (limit == 0) { // no limit - DPrintf("FPS timer disabled\n"); + DPrintf(DMSG_NOTIFY, "FPS timer disabled\n"); } else { FPSLimitTimerEnabled = true; if(timer_create(CLOCK_REALTIME, &FPSLimitEvent, &FPSLimitTimer) == -1) - Printf("Failed to create FPS limitter event\n"); + Printf(DMSG_WARNING, "Failed to create FPS limitter event\n"); itimerspec period = { {0, 0}, {0, 0} }; period.it_value.tv_nsec = period.it_interval.tv_nsec = 1000000000 / limit; if(timer_settime(FPSLimitTimer, 0, &period, NULL) == -1) - Printf("Failed to set FPS limitter timer\n"); - DPrintf("FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000); + Printf(DMSG_WARNING, "Failed to set FPS limitter timer\n"); + DPrintf(DMSG_NOTIFY, "FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000); } } #else diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 4eb3cb440..edb1949b6 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2341,7 +2341,7 @@ void R_CheckDrawSegs () firstdrawseg = drawsegs + firstofs; ds_p = drawsegs + MaxDrawSegs; MaxDrawSegs = newdrawsegs; - DPrintf ("MaxDrawSegs increased to %zu\n", MaxDrawSegs); + DPrintf (DMSG_NOTIFY, "MaxDrawSegs increased to %zu\n", MaxDrawSegs); } } @@ -2360,7 +2360,7 @@ ptrdiff_t R_NewOpening (ptrdiff_t len) maxopenings = maxopenings ? maxopenings*2 : 16384; while ((size_t)lastopening > maxopenings); openings = (short *)M_Realloc (openings, maxopenings * sizeof(*openings)); - DPrintf ("MaxOpenings increased to %zu\n", maxopenings); + DPrintf (DMSG_NOTIFY, "MaxOpenings increased to %zu\n", maxopenings); } return res; } diff --git a/src/r_things.cpp b/src/r_things.cpp index aad8fb501..28b52129b 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -222,7 +222,7 @@ vissprite_t *R_NewVisSprite (void) lastvissprite = &vissprites[MaxVisSprites]; firstvissprite = &vissprites[firstvisspritenum]; vissprite_p = &vissprites[prevvisspritenum]; - DPrintf ("MaxVisSprites increased to %d\n", MaxVisSprites); + DPrintf (DMSG_NOTIFY, "MaxVisSprites increased to %d\n", MaxVisSprites); // Allocate sprites from the new pile for (vissprite_t **p = vissprite_p; p < lastvissprite; ++p) @@ -832,13 +832,11 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor else { // decide which texture to use for the sprite -#ifdef RANGECHECK - if (spritenum >= (signed)sprites.Size () || spritenum < 0) + if ((unsigned)spritenum >= sprites.Size ()) { - DPrintf ("R_ProjectSprite: invalid sprite number %u\n", spritenum); + DPrintf (DMSG_ERROR, "R_ProjectSprite: invalid sprite number %u\n", spritenum); return; } -#endif spritedef_t *sprdef = &sprites[spritenum]; if (thing->frame >= sprdef->numframes) { @@ -1312,13 +1310,13 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double // decide which patch to use if ((unsigned)pspr->GetSprite() >= (unsigned)sprites.Size()) { - DPrintf("R_DrawPSprite: invalid sprite number %i\n", pspr->GetSprite()); + DPrintf(DMSG_ERROR, "R_DrawPSprite: invalid sprite number %i\n", pspr->GetSprite()); return; } sprdef = &sprites[pspr->GetSprite()]; if (pspr->GetFrame() >= sprdef->numframes) { - DPrintf("R_DrawPSprite: invalid sprite frame %i : %i\n", pspr->GetSprite(), pspr->GetFrame()); + DPrintf(DMSG_ERROR, "R_DrawPSprite: invalid sprite frame %i : %i\n", pspr->GetSprite(), pspr->GetFrame()); return; } sprframe = &SpriteFrames[sprdef->spriteframes + pspr->GetFrame()]; diff --git a/src/resourcefiles/file_wad.cpp b/src/resourcefiles/file_wad.cpp index 0732d4c11..5965a5c8a 100644 --- a/src/resourcefiles/file_wad.cpp +++ b/src/resourcefiles/file_wad.cpp @@ -471,7 +471,7 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name { // We can't add this to the flats namespace but // it needs to be flagged for the texture manager. - DPrintf("Marking %s as potential flat\n", Lumps[i].Name); + DPrintf(DMSG_NOTIFY, "Marking %s as potential flat\n", Lumps[i].Name); Lumps[i].Flags |= LUMPF_MAYBEFLAT; } } @@ -517,7 +517,7 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name } // we found a marked block - DPrintf("Found %s block at (%d-%d)\n", startmarker, markers[start].index, end); + DPrintf(DMSG_NOTIFY, "Found %s block at (%d-%d)\n", startmarker, markers[start].index, end); for(int j = markers[start].index + 1; j < end; j++) { if (Lumps[j].Namespace != ns_global) @@ -534,7 +534,7 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name // ignore sprite lumps smaller than 8 bytes (the smallest possible) // in size -- this was used by some dmadds wads // as an 'empty' graphics resource - DPrintf(" Skipped empty sprite %s (lump %d)\n", Lumps[j].Name, j); + DPrintf(DMSG_WARNING, " Skipped empty sprite %s (lump %d)\n", Lumps[j].Name, j); } else { diff --git a/src/s_playlist.cpp b/src/s_playlist.cpp index ec775e275..e1b0fd5b6 100644 --- a/src/s_playlist.cpp +++ b/src/s_playlist.cpp @@ -182,7 +182,7 @@ int FPlayList::SetPosition (int position) { Position = position; } - DPrintf ("Playlist position set to %d\n", Position); + DPrintf (DMSG_NOTIFY, "Playlist position set to %d\n", Position); return Position; } @@ -197,7 +197,7 @@ int FPlayList::Advance () { Position = 0; } - DPrintf ("Playlist advanced to song %d\n", Position); + DPrintf (DMSG_NOTIFY, "Playlist advanced to song %d\n", Position); return Position; } @@ -207,7 +207,7 @@ int FPlayList::Backup () { Position = Songs.Size() - 1; } - DPrintf ("Playlist backed up to song %d\n", Position); + DPrintf (DMSG_NOTIFY, "Playlist backed up to song %d\n", Position); return Position; } diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 321cbce1b..2149f7814 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -552,7 +552,7 @@ void S_UnloadSound (sfxinfo_t *sfx) GSnd->UnloadSound(sfx->data); sfx->data.Clear(); sfx->data3d.Clear(); - DPrintf("Unloaded sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]); + DPrintf(DMSG_NOTIFY, "Unloaded sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]); } } @@ -1327,7 +1327,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) { if (S_sfx[i].data.isValid() && S_sfx[i].link == sfxinfo_t::NO_LINK && S_sfx[i].lumpnum == sfx->lumpnum) { - DPrintf ("Linked %s to %s (%d)\n", sfx->name.GetChars(), S_sfx[i].name.GetChars(), i); + DPrintf (DMSG_NOTIFY, "Linked %s to %s (%d)\n", sfx->name.GetChars(), S_sfx[i].name.GetChars(), i); sfx->link = i; // This is necessary to avoid using the rolloff settings of the linked sound if its // settings are different. @@ -1336,7 +1336,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) } } - DPrintf("Loading sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]); + DPrintf(DMSG_NOTIFY, "Loading sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]); int size = Wads.LumpLength(sfx->lumpnum); if (size > 0) @@ -1396,7 +1396,7 @@ static void S_LoadSound3D(sfxinfo_t *sfx) if(sfx->data3d.isValid()) return; - DPrintf("Loading monoized sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]); + DPrintf(DMSG_NOTIFY, "Loading monoized sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]); int size = Wads.LumpLength(sfx->lumpnum); if(size <= 0) return; diff --git a/src/sc_man.cpp b/src/sc_man.cpp index da106927e..3f5530ff3 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -1044,7 +1044,7 @@ void FScriptPosition::Message (int severity, const char *message, ...) const { FString composed; - if ((severity == MSG_DEBUG || severity == MSG_DEBUGLOG) && !developer) return; + if ((severity == MSG_DEBUG || severity == MSG_DEBUGLOG) && developer < DMSG_NOTIFY) return; if (severity == MSG_OPTERROR) { severity = strictdecorate ? MSG_ERROR : MSG_WARNING; diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 465aade9b..2db5a98a1 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1994,7 +1994,7 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi return CommonChannelSetup(chan, reuse_chan); } - //DPrintf ("Sound %s failed to play: %d\n", sfx->name.GetChars(), result); + //DPrintf (DMSG_WARNING, "Sound %s failed to play: %d\n", sfx->name.GetChars(), result); return NULL; } @@ -2142,7 +2142,7 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * } GRolloff = NULL; - //DPrintf ("Sound %s failed to play: %d\n", sfx->name.GetChars(), result); + //DPrintf (DMSG_WARNING, "Sound %s failed to play: %d\n", sfx->name.GetChars(), result); return 0; } @@ -2566,7 +2566,7 @@ void FMODSoundRenderer::UpdateListener(SoundListener *listener) } if (env != PrevEnvironment || env->Modified) { - DPrintf ("Reverb Environment %s\n", env->Name); + DPrintf (DMSG_NOTIFY, "Reverb Environment %s\n", env->Name); const_cast(env)->Modified = false; SetSystemReverbProperties(&env->Properties); PrevEnvironment = env; @@ -2791,7 +2791,7 @@ std::pair FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int l result = Sys->createSound((char *)sfxdata, samplemode, &exinfo, &sample); if (result != FMOD_OK) { - DPrintf("Failed to allocate sample: Error %d\n", result); + DPrintf(DMSG_ERROR, "Failed to allocate sample: Error %d\n", result); return std::make_pair(retval, true); } @@ -2829,7 +2829,7 @@ std::pair FMODSoundRenderer::LoadSound(BYTE *sfxdata, int leng result = Sys->createSound((char *)sfxdata, samplemode, &exinfo, &sample); if (result != FMOD_OK) { - DPrintf("Failed to allocate sample: Error %d\n", result); + DPrintf(DMSG_ERROR, "Failed to allocate sample: Error %d\n", result); return std::make_pair(retval, true); } SetCustomLoopPts(sample); diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index f19e080c3..67f46b266 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -417,7 +417,7 @@ short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, decoder->getInfo(&srate, &chans, &type); if(chans != ChannelConfig_Mono || type != SampleType_Int16) { - DPrintf("Sample is not 16-bit mono\n"); + DPrintf(DMSG_WARNING, "Sample is not 16-bit mono\n"); delete decoder; return samples; } @@ -553,7 +553,7 @@ std::pair SoundRenderer::LoadSoundVoc(BYTE *sfxdata, int lengt break; default: // Unknown block type okay = false; - DPrintf ("Unknown VOC block type %i\n", blocktype); + DPrintf (DMSG_ERROR, "Unknown VOC block type %i\n", blocktype); break; } // Move to next block diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 0427ca438..b3f7b7d45 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -498,12 +498,12 @@ int FluidSynthMIDIDevice::LoadPatchSets(const char *patches) } if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, path, count == 0)) { - DPrintf("Loaded patch set %s.\n", tok); + DPrintf(DMSG_NOTIFY, "Loaded patch set %s.\n", tok); count++; } else { - DPrintf("Failed to load patch set %s.\n", tok); + DPrintf(DMSG_ERROR, "Failed to load patch set %s.\n", tok); } tok = strtok(NULL, delim); } diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index 30468839d..ee9d322a4 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -376,7 +376,7 @@ bool TimidityPPMIDIDevice::LaunchTimidity () return false; } - DPrintf ("cmd: \x1cG%s\n", CommandLine.GetChars()); + DPrintf (DMSG_NOTIFY, "cmd: \x1cG%s\n", CommandLine.GetChars()); #ifdef _WIN32 STARTUPINFO startup = { sizeof(startup), }; diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index 50b95a776..a9cbcd2c6 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -143,7 +143,7 @@ XMISong::XMISong (FileReader &reader, EMidiDevice type, const char *args) memset(Songs, 0, sizeof(*Songs) * NumSongs); FindXMIDforms(MusHeader, SongLen, Songs); CurrSong = Songs; - DPrintf("XMI song count: %d\n", NumSongs); + DPrintf(DMSG_SPAMMY, "XMI song count: %d\n", NumSongs); } //========================================================================== diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 6dd204c86..21370d082 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -747,8 +747,8 @@ OpenALSoundRenderer::OpenALSoundRenderer() ALCint major=0, minor=0; alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); - DPrintf(" ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); - DPrintf(" ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); + DPrintf(DMSG_SPAMMY, " ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); + DPrintf(DMSG_SPAMMY, " ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); TArray attribs; if(*snd_samplerate > 0) @@ -778,10 +778,10 @@ OpenALSoundRenderer::OpenALSoundRenderer() } attribs.Clear(); - DPrintf(" Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); - DPrintf(" Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); - DPrintf(" Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); - DPrintf(" Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); + DPrintf(DMSG_SPAMMY, " Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); + DPrintf(DMSG_SPAMMY, " Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); + DPrintf(DMSG_SPAMMY, " Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); + DPrintf(DMSG_SPAMMY, " Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); ALC.EXT_EFX = !!alcIsExtensionPresent(Device, "ALC_EXT_EFX"); ALC.EXT_disconnect = !!alcIsExtensionPresent(Device, "ALC_EXT_disconnect"); @@ -864,7 +864,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() return; } FreeSfx = Sources; - DPrintf(" Allocated " TEXTCOLOR_BLUE"%u" TEXTCOLOR_NORMAL" sources\n", Sources.Size()); + DPrintf(DMSG_NOTIFY, " Allocated " TEXTCOLOR_BLUE"%u" TEXTCOLOR_NORMAL" sources\n", Sources.Size()); WasInWater = false; if(*snd_efx && ALC.EXT_EFX) @@ -913,10 +913,10 @@ OpenALSoundRenderer::OpenALSoundRenderer() { alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); if(alGetError() == AL_NO_ERROR) - DPrintf(" EAX Reverb found\n"); + DPrintf(DMSG_SPAMMY, " EAX Reverb found\n"); alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); if(alGetError() == AL_NO_ERROR) - DPrintf(" Standard Reverb found\n"); + DPrintf(DMSG_SPAMMY, " Standard Reverb found\n"); alDeleteEffects(1, &envReverb); getALError(); @@ -929,7 +929,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() alFilteri(EnvFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); alFilteri(EnvFilters[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS); if(getALError() == AL_NO_ERROR) - DPrintf(" Lowpass found\n"); + DPrintf(DMSG_SPAMMY, " Lowpass found\n"); else { alDeleteFilters(2, EnvFilters); @@ -1194,7 +1194,7 @@ std::pair OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int loopend = length / (channels*bits/8); ALint loops[2] = { loopstart, loopend }; - DPrintf("Setting loop points %d -> %d\n", loops[0], loops[1]); + DPrintf(DMSG_NOTIFY, "Setting loop points %d -> %d\n", loops[0], loops[1]); alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops); getALError(); } @@ -1202,7 +1202,7 @@ std::pair OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int { static bool warned = false; if(!warned) - Printf("Loop points not supported!\n"); + Printf(DMSG_WARNING, "Loop points not supported!\n"); warned = true; } @@ -1867,7 +1867,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) if(env != PrevEnvironment || env->Modified) { PrevEnvironment = env; - DPrintf("Reverb Environment %s\n", env->Name); + DPrintf(DMSG_NOTIFY, "Reverb Environment %s\n", env->Name); if(EnvSlot != 0) LoadReverb(env); diff --git a/src/v_video.cpp b/src/v_video.cpp index 01a73950b..0ee065bbe 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -907,11 +907,12 @@ void DFrameBuffer::DrawRateStuff () // Drawing it as a texture does and continues to show how // well the PalTex shader is working. static FPaletteTester palette; + int size = screen->GetHeight() < 800 ? 16 * 7 : 16 * 7 * 2; palette.SetTranslation(vid_showpalette); DrawTexture(&palette, 0, 0, - DTA_DestWidth, 16*7, - DTA_DestHeight, 16*7, + DTA_DestWidth, size, + DTA_DestHeight, size, DTA_Masked, false, TAG_DONE); } diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index 29bb905fb..8eb2349ec 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -793,7 +793,7 @@ void I_SetFPSLimit(int limit) CloseHandle(FPSLimitEvent); FPSLimitEvent = NULL; } - DPrintf("FPS timer disabled\n"); + DPrintf(DMSG_NOTIFY, "FPS timer disabled\n"); } else { @@ -802,7 +802,7 @@ void I_SetFPSLimit(int limit) FPSLimitEvent = CreateEvent(NULL, FALSE, TRUE, NULL); if (FPSLimitEvent == NULL) { // Could not create event, so cannot use timer. - Printf("Failed to create FPS limitter event\n"); + Printf(DMSG_WARNING, "Failed to create FPS limitter event\n"); return; } } @@ -817,7 +817,7 @@ void I_SetFPSLimit(int limit) Printf("Failed to create FPS limitter timer\n"); return; } - DPrintf("FPS timer set to %u ms\n", period); + DPrintf(DMSG_NOTIFY, "FPS timer set to %u ms\n", period); } } diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index d80c048b7..ed224cb57 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1957,6 +1957,7 @@ MSGMNU_TEAMMESSAGES = "Team Messages"; MSGMNU_CENTEREDMESSAGES = "Centered Messages"; MSGMNU_SCREENSHOTMESSAGES = "Screenshot messages"; MSGMNU_LONGSAVEMESSAGES = "Detailed save messages"; +MSGMNU_DEVELOPER = "Developer message mode"; // Scoreboard Options SCRBRDMNU_TITLE = "SCOREBOARD OPTIONS"; @@ -2287,6 +2288,10 @@ OPTVAL_SINC = "Sinc"; OPTVAL_NOTEONOFFONLY = "Note on/off only"; OPTVAL_FULLRAMPING = "Full ramping"; OPTVAL_ALLUNACKNOWLEDGED = "All unacknowledged"; +OPTVAL_ERRORS = "Errors"; +OPTVAL_WARNINGS = "Warnings"; +OPTVAL_NOTIFICATIONS = "Notifications"; +OPTVAL_EVERYTHING = "Everything"; // Colors C_BRICK = "\cabrick"; C_TAN = "\cbtan"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 077dc0608..203576e5d 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1118,6 +1118,15 @@ OptionValue MessageLevels 2.0, "$OPTVAL_CRITICALMESSAGES" } +OptionValue DevMessageLevels +{ + 0, "$OPTVAL_OFF" + 1, "$OPTVAL_ERRORS" + 2, "$OPTVAL_WARNINGS", + 3, "$OPTVAL_NOTIFICATIONS" + 4, "$OPTVAL_EVERYTHING" +} + OptionMenu MessageOptions { Title "$MSGMNU_TITLE" @@ -1126,6 +1135,7 @@ OptionMenu MessageOptions Option "$MSGMNU_SHOWSECRETS", "cl_showsecretmessage", "OnOff" Option "$MSGMNU_SCALETEXT", "con_scaletext", "ScaleValues" Option "$MSGMNU_MESSAGELEVEL", "msg", "MessageLevels" + Option "$MSGMNU_DEVELOPER", "developer", "DevMessageLevels" Option "$MSGMNU_CENTERMESSAGES", "con_centernotify", "OnOff" StaticText " " StaticText "$MSGMNU_MESSAGECOLORS", 1 From da5cf760b0941306b81774f8e130e17466353e56 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 28 Aug 2016 10:10:32 +0200 Subject: [PATCH 42/97] - forgot to save this one... --- wadsrc/static/menudef.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 203576e5d..ae8cfa0bb 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1122,7 +1122,7 @@ OptionValue DevMessageLevels { 0, "$OPTVAL_OFF" 1, "$OPTVAL_ERRORS" - 2, "$OPTVAL_WARNINGS", + 2, "$OPTVAL_WARNINGS" 3, "$OPTVAL_NOTIFICATIONS" 4, "$OPTVAL_EVERYTHING" } From 3299a29c446ea13ee110f75f527acc179c78ed72 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 28 Aug 2016 16:14:24 +0200 Subject: [PATCH 43/97] - added CheckClass ACS function. --- src/p_acs.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 5f08f0152..a2b5275cb 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4449,6 +4449,8 @@ enum EACSFunctions -106 : KickFromGame(2), */ + ACSF_CheckClass = 200, + // ZDaemon ACSF_GetTeamScore = 19620, // (int team) ACSF_SetTeamScore, // (int team, int value) @@ -6028,6 +6030,12 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return false; } + case ACSF_CheckClass: + { + const char *clsname = FBehavior::StaticLookupString(args[0]); + return !!PClass::FindActor(clsname); + } + default: break; } From 49930185206141a5d0219ebbbf405cae88c82f0e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 31 Aug 2016 09:18:59 +0200 Subject: [PATCH 44/97] - fixed: Actor velocity requires an upper limit to prevent uncontrolled accumulation, as can happen when multiple exploding and pushable objects overlap. The value 5000 was chosen because it is high enough to not occur under regular circumstances and small enough to prevent severe slowdowns. In the old fixed point code the lack of such a check just caused random overflows. --- src/p_mobj.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8971efe25..f5791d079 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1806,6 +1806,11 @@ double P_XYMovement (AActor *mo, DVector2 scroll) mo->Vel.X *= fac; mo->Vel.Y *= fac; } + const double VELOCITY_THRESHOLD = 5000; // don't let it move faster than this. Fixed point overflowed at 32768 but that's too much to make this safe. + if (mo->Vel.LengthSquared() >= VELOCITY_THRESHOLD*VELOCITY_THRESHOLD) + { + mo->Vel.MakeResize(VELOCITY_THRESHOLD); + } move = mo->Vel; // [RH] Carrying sectors didn't work with low speeds in BOOM. This is // because BOOM relied on the speed being fast enough to accumulate From c4357bd352b5f8ca0a490a75ae4c6f5ebed77ad5 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Thu, 1 Sep 2016 13:49:58 -0500 Subject: [PATCH 45/97] Tracer pointer is no longer a safe candidate for storing player morph pointers. Instead, actors must have a new, non-manipulatable pointer. This fixes the following circumstances: - Crashes occurred if a particular actor was a tracer to the player and the actor was not gone by the time the player unmorphs. - Failed unmorphs occur if tracer was manipulated through means like A_RearrangePointers, etc. --- src/actor.h | 1 + src/g_shared/a_morph.cpp | 57 ++++++++++++++++++++++------------------ src/p_mobj.cpp | 5 ++++ src/version.h | 2 +- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/actor.h b/src/actor.h index 154d14289..b895d1e2a 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1057,6 +1057,7 @@ public: int skillrespawncount; int TIDtoHate; // TID of things to hate (0 if none) FNameNoInit Species; // For monster families + TObjPtr alternative; // (Un)Morphed actors stored here. Those with the MF_UNMORPHED flag are the originals. TObjPtr tracer; // Thing being chased/attacked for tracers TObjPtr master; // Thing which spawned this one (prevents mutual attacks) double Floorclip; // value to use for floor clipping diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 98af9ff25..57271f768 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -38,7 +38,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp APlayerPawn *actor; actor = p->mo; - if (actor == NULL) + if (actor == nullptr) { return false; } @@ -55,7 +55,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp if ((p->mo->GetClass() == spawntype) && (p->mo->PlayerFlags & PPF_CANSUPERMORPH) && (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE)) - && (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == NULL)) + && (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == nullptr)) { // Make a super chicken p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); } @@ -65,7 +65,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp { // Dead players cannot morph return false; } - if (spawntype == NULL) + if (spawntype == nullptr) { return false; } @@ -94,7 +94,8 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp } morphed->Angles.Yaw = actor->Angles.Yaw; morphed->target = actor->target; - morphed->tracer = actor; + morphed->tracer = actor->tracer; + morphed->alternative = actor; morphed->FriendPlayer = actor->FriendPlayer; morphed->DesignatedTeam = actor->DesignatedTeam; morphed->Score = actor->Score; @@ -113,7 +114,8 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp morphed->flags2 |= actor->flags2 & MF2_FLY; morphed->flags3 |= actor->flags3 & MF3_GHOST; AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE); - actor->player = NULL; + actor->player = nullptr; + actor->alternative = morphed; actor->flags &= ~(MF_SOLID|MF_SHOOTABLE); actor->flags |= MF_UNMORPHED; actor->renderflags |= RF_INVISIBLE; @@ -129,7 +131,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp p->Vel.X = p->Vel.Y = 0; morphed->ObtainInventory (actor); // Remove all armor - for (item = morphed->Inventory; item != NULL; ) + for (item = morphed->Inventory; item != nullptr; ) { AInventory *next = item->Inventory; if (item->IsKindOf (RUNTIME_CLASS(AArmor))) @@ -182,7 +184,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, // because the level or game is ended while morphed, // by the time it gets executed the morphed player // pawn instance may have already been destroyed. - if (pmo == NULL || pmo->tracer == NULL) + if (pmo == nullptr || pmo->alternative == nullptr) { return false; } @@ -197,7 +199,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, return false; } - mo = barrier_cast(pmo->tracer); + mo = barrier_cast(pmo->alternative); mo->SetOrigin (pmo->Pos(), false); mo->flags |= MF_SOLID; pmo->flags &= ~MF_SOLID; @@ -208,10 +210,14 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, player->morphTics = 2*TICRATE; return false; } - pmo->player = NULL; + // No longer using tracer as morph storage. That is what 'alternative' is for. + // If the tracer has changed on the morph, change the original too. + mo->target = pmo->target; + mo->tracer = pmo->tracer; + pmo->player = nullptr; // Remove the morph power if the morph is being undone prematurely. - for (AInventory *item = pmo->Inventory, *next = NULL; item != NULL; item = next) + for (AInventory *item = pmo->Inventory, *next = nullptr; item != nullptr; item = next) { next = item->Inventory; if (item->IsKindOf(RUNTIME_CLASS(APowerMorph))) @@ -252,10 +258,10 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, player->morphTics = 0; player->MorphedPlayerClass = 0; player->MorphStyle = 0; - player->MorphExitFlash = NULL; + player->MorphExitFlash = nullptr; player->viewheight = mo->ViewHeight; AInventory *level2 = mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true); - if (level2 != NULL) + if (level2 != nullptr) { level2->Destroy (); } @@ -310,31 +316,31 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } } - AActor *eflash = NULL; - if (exit_flash != NULL) + AActor *eflash = nullptr; + if (exit_flash != nullptr) { eflash = Spawn(exit_flash, pmo->Vec3Angle(20., mo->Angles.Yaw, TELEFOGHEIGHT), ALLOW_REPLACE); if (eflash) eflash->target = mo; } mo->SetupWeaponSlots(); // Use original class's weapon slots. beastweap = player->ReadyWeapon; - if (player->PremorphWeapon != NULL) + if (player->PremorphWeapon != nullptr) { player->PremorphWeapon->PostMorphWeapon (); } else { - player->ReadyWeapon = player->PendingWeapon = NULL; + player->ReadyWeapon = player->PendingWeapon = nullptr; } if (correctweapon) { // Better "lose morphed weapon" semantics PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon); - if (morphweapon != NULL && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (morphweapon != nullptr && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { AWeapon *OriginalMorphWeapon = static_cast(mo->FindInventory (morphweapon)); - if ((OriginalMorphWeapon != NULL) && (OriginalMorphWeapon->GivenAsMorphWeapon)) + if ((OriginalMorphWeapon != nullptr) && (OriginalMorphWeapon->GivenAsMorphWeapon)) { // You don't get to keep your morphed weapon. - if (OriginalMorphWeapon->SisterWeapon != NULL) + if (OriginalMorphWeapon->SisterWeapon != nullptr) { OriginalMorphWeapon->SisterWeapon->Destroy (); } @@ -344,20 +350,21 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } else // old behaviour (not really useful now) { // Assumptions made here are no longer valid - if (beastweap != NULL) + if (beastweap != nullptr) { // You don't get to keep your morphed weapon. - if (beastweap->SisterWeapon != NULL) + if (beastweap->SisterWeapon != nullptr) { beastweap->SisterWeapon->Destroy (); } beastweap->Destroy (); } } - pmo->tracer = NULL; + mo->alternative = nullptr; + pmo->alternative = nullptr; pmo->Destroy (); // Restore playerclass armor to its normal amount. AHexenArmor *hxarmor = mo->FindInventory(); - if (hxarmor != NULL) + if (hxarmor != nullptr) { hxarmor->Slots[4] = mo->GetClass()->HexenArmor[0]; } @@ -517,9 +524,9 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor (actor->player->morphTics) && (actor->player->MorphStyle & MORPH_UNDOBYDEATH) && (actor->player->mo) && - (actor->player->mo->tracer)) + (actor->player->mo->alternative)) { - AActor *realme = actor->player->mo->tracer; + AActor *realme = actor->player->mo->alternative; int realstyle = actor->player->MorphStyle; int realhealth = actor->health; if (P_UndoPlayerMorph(actor->player, actor->player, 0, !!(actor->player->MorphStyle & MORPH_UNDOBYDEATHFORCED))) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f5791d079..6d8ce4418 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -389,6 +389,11 @@ void AActor::Serialize(FArchive &arc) arc << SpriteRotation; } + if (SaveVersion >= 4550) + { + arc << alternative; + } + { FString tagstr; if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag; diff --git a/src/version.h b/src/version.h index cffa25bdd..57dacaa00 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4549 +#define SAVEVER 4550 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From bf5f10a89717b9d7b970fc53fc7125ed946c6eb3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Sep 2016 10:48:38 +0200 Subject: [PATCH 46/97] - added all relevant licenses to docs. --- docs/licenses/README.TXT | 27 ++ docs/licenses/bsd.txt | 27 ++ docs/licenses/buildlic.txt | 71 ++++++ docs/licenses/cephes.txt | 10 + docs/licenses/doomlic.txt | 112 +++++++++ docs/licenses/dumb.txt | 54 ++++ docs/licenses/gdtoa.txt | 27 ++ docs/licenses/lgpl.txt | 504 +++++++++++++++++++++++++++++++++++++ 8 files changed, 832 insertions(+) create mode 100644 docs/licenses/README.TXT create mode 100644 docs/licenses/bsd.txt create mode 100644 docs/licenses/buildlic.txt create mode 100644 docs/licenses/cephes.txt create mode 100644 docs/licenses/doomlic.txt create mode 100644 docs/licenses/dumb.txt create mode 100644 docs/licenses/gdtoa.txt create mode 100644 docs/licenses/lgpl.txt diff --git a/docs/licenses/README.TXT b/docs/licenses/README.TXT new file mode 100644 index 000000000..f60796436 --- /dev/null +++ b/docs/licenses/README.TXT @@ -0,0 +1,27 @@ +The original Doom source code was released by id Software under the +Doom Source Code License. See doomlic.txt. + +Parts of the renderer use code from the BUILD engine by Ken Silverman. +See buildlic.txt. + +The majority of original code uses a BSD-like lincese. See bsd.txt. + +This software is based in part on the work of the Independent JPEG Group. + +This software uses the 'zlib' general purpose compression library by +Jean-loup Gailly and Mark Adler. + +This software uses the gdtoa package, see gdtoa.txt. + +This software uses the snes_spc library, which is covered by the GNU Lesser +General Public License. See lgpl.txt. + +This software uses the "Dynamic Universal Music Bibliotheque" library for +MOD music playback. See dumb.txt for original license. The version used, +however, has been heavily modified from its original form and is the same +version used by the foobar2000 component foo_dumb as of mid-2008, found at +http://kode54.foobar2000.org/. + +This software uses the OPL emulator from MAME 0.95. Playback of MUS files +on the OPL emulation is accomplished with some help from Vladimir Arnost's +MUS File Player Library, with fixes to make it more accurate. diff --git a/docs/licenses/bsd.txt b/docs/licenses/bsd.txt new file mode 100644 index 000000000..aa48716a9 --- /dev/null +++ b/docs/licenses/bsd.txt @@ -0,0 +1,27 @@ +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit, Christoph Oelckers, et al. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/licenses/buildlic.txt b/docs/licenses/buildlic.txt new file mode 100644 index 000000000..a0cec1251 --- /dev/null +++ b/docs/licenses/buildlic.txt @@ -0,0 +1,71 @@ +BUILD SOURCE CODE LICENSE TERMS: 06/20/2000 + +[1] I give you permission to make modifications to my Build source and + distribute it, BUT: + +[2] Any derivative works based on my Build source may be distributed ONLY + through the INTERNET. + +[3] Distribution of any derivative works MUST be done completely FREE of + charge - no commercial exploitation whatsoever. + +[4] Anything you distribute which uses a part of my Build Engine source + code MUST include: + + [A] The following message somewhere in the archive: + + // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + // Ken Silverman's official web site: "http://www.advsys.net/ken" + // See the included license file "BUILDLIC.TXT" for license info. + + [B] This text file "BUILDLIC.TXT" along with it. + + [C] Any source files that you modify must include this message as well: + + // This file has been modified from Ken Silverman's original release + +[5] The use of the Build Engine for commercial purposes will require an + appropriate license arrangement with me. Contact information is + on my web site. + +[6] I take no responsibility for damage to your system. + +[7] Technical support: Before contacting me with questions, please read + and do ALL of the following! + + [A] Look though ALL of my text files. There are 7 of them (including this + one). I like to think that I wrote them for a reason. You will find + many of your answers in the history section of BUILD.TXT and + BUILD2.TXT (they're located inside SRC.ZIP). + + [B] If that doesn't satisfy you, then try going to: + + "http://www.advsys.net/ken/buildsrc" + + where I will maintain a Build Source Code FAQ (or perhaps I might + just provide a link to a good FAQ). + + [C] I am willing to respond to questions, but ONLY if they come at a rate + that I can handle. + + PLEASE TRY TO AVOID ASKING DUPLICATE QUESTIONS! + + As my line of defense, I will post my current policy about + answering Build source questions (right below the E-mail address + on my web site.) You can check there to see if I'm getting + overloaded with questions or not. + + If I'm too busy, it might say something like this: + + I'm too busy to answer Build source questions right now. + Sorry, but don't expect a reply from me any time soon. + + If I'm open for Build source questions, please state your question + clearly and don't include any unsolicited attachments unless + they're really small (like less than 50k). Assume that I have + a 28.8k modem. Also, don't leave out important details just + to make your question appear shorter - making me guess what + you're asking doesn't save me time! + +---------------------------------------------------------------------------- +-Ken S. (official web site: http://www.advsys.net/ken) diff --git a/docs/licenses/cephes.txt b/docs/licenses/cephes.txt new file mode 100644 index 000000000..cb4e3f9d6 --- /dev/null +++ b/docs/licenses/cephes.txt @@ -0,0 +1,10 @@ + Some software in this archive may be from the book _Methods and +Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster +International, 1989) or from the Cephes Mathematical Library, a +commercial product. In either event, it is copyrighted by the author. +What you see here may be used freely but it comes with no support or +guarantee. + + Stephen L. Moshier + moshier@na-net.ornl.gov + \ No newline at end of file diff --git a/docs/licenses/doomlic.txt b/docs/licenses/doomlic.txt new file mode 100644 index 000000000..2b2252ee2 --- /dev/null +++ b/docs/licenses/doomlic.txt @@ -0,0 +1,112 @@ + + + LIMITED USE SOFTWARE LICENSE AGREEMENT + + This Limited Use Software License Agreement (the "Agreement") +is a legal agreement between you, the end-user, and Id Software, Inc. +("ID"). By downloading or purchasing the software material, which +includes source code (the "Source Code"), artwork data, music and +software tools (collectively, the "Software"), you are agreeing to +be bound by the terms of this Agreement. If you do not agree to the +terms of this Agreement, promptly destroy the Software you may have +downloaded or copied. + +ID SOFTWARE LICENSE + +1. Grant of License. ID grants to you the right to use the +Software. You have no ownership or proprietary rights in or to the +Software, or the Trademark. For purposes of this section, "use" means +loading the Software into RAM, as well as installation on a hard disk +or other storage device. The Software, together with any archive copy +thereof, shall be destroyed when no longer used in accordance with +this Agreement, or when the right to use the Software is terminated. +You agree that the Software will not be shipped, transferred or +exported into any country in violation of the U.S. Export +Administration Act (or any other law governing such matters) and that +you will not utilize, in any other manner, the Software in violation +of any applicable law. + +2. Permitted Uses. For educational purposes only, you, the +end-user, may use portions of the Source Code, such as particular +routines, to develop your own software, but may not duplicate the +Source Code, except as noted in paragraph 4. The limited right +referenced in the preceding sentence is hereinafter referred to as +"Educational Use." By so exercising the Educational Use right you +shall not obtain any ownership, copyright, proprietary or other +interest in or to the Source Code, or any portion of the Source +Code. You may dispose of your own software in your sole discretion. +With the exception of the Educational Use right, you may not +otherwise use the Software, or an portion of the Software, which +includes the Source Code, for commercial gain. + +3. Prohibited Uses: Under no circumstances shall you, the +end-user, be permitted, allowed or authorized to commercially exploit +the Software. Neither you nor anyone at your direction shall do any +of the following acts with regard to the Software, or any portion +thereof: + + Rent; + + Sell; + + Lease; + + Offer on a pay-per-play basis; + + Distribute for money or any other consideration; or + + In any other manner and through any medium whatsoever +commercially exploit or use for any commercial purpose. + +Notwithstanding the foregoing prohibitions, you may commercially +exploit the software you develop by exercising the Educational Use +right, referenced in paragraph 2. hereinabove. + +4. Copyright. The Software and all copyrights related thereto +(including all characters and other images generated by the Software +or depicted in the Software) are owned by ID and is protected by +United States copyright laws and international treaty provisions. +Id shall retain exclusive ownership and copyright in and to the +Software and all portions of the Software and you shall have no +ownership or other proprietary interest in such materials. You must +treat the Software like any other copyrighted material. You may not +otherwise reproduce, copy or disclose to others, in whole or in any +part, the Software. You may not copy the written materials +accompanying the Software. You agree to use your best efforts to +see that any user of the Software licensed hereunder complies with +this Agreement. + +5. NO WARRANTIES. ID DISCLAIMS ALL WARRANTIES, BOTH EXPRESS +IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT +TO THE SOFTWARE. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL +RIGHTS. YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO +JURISDICTION. ID DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE +WILL BE UNINTERRUPTED, ERROR FREE OR MEET YOUR SPECIFIC REQUIREMENTS. +THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS +WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES, +DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE +MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF +OF ID. + + Exclusive Remedies. The Software is being offered to you +free of any charge. You agree that you have no remedy against ID, its +affiliates, contractors, suppliers, and agents for loss or damage +caused by any defect or failure in the Software regardless of the form +of action, whether in contract, tort, includinegligence, strict +liability or otherwise, with regard to the Software. This Agreement +shall be construed in accordance with and governed by the laws of the +State of Texas. Copyright and other proprietary matters will be +governed by United States laws and international treaties. IN ANY +CASE, ID SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST +SAVINGS, SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT OR OTHER +SIMILAR DAMAGES ARISING FROM BREACH OF WARRANTY, BREACH OF CONTRACT, +NEGLIGENCE, OR OTHER LEGAL THEORY EVEN IF ID OR ITS AGENT HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY +OTHER PARTY. Some jurisdictions do not allow the exclusion or +limitation of incidental or consequential damages, so the above +limitation or exclusion may not apply to you. + + + + diff --git a/docs/licenses/dumb.txt b/docs/licenses/dumb.txt new file mode 100644 index 000000000..231bfa7f1 --- /dev/null +++ b/docs/licenses/dumb.txt @@ -0,0 +1,54 @@ +/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * licence.txt - Conditions for use of DUMB. / / \ \ + * | < / \_ + * If you do not agree to these terms, please | \/ /\ / + * do not use DUMB. \_ / > / + * | \ / / + * Information in [brackets] is provided to aid | ' / + * interpretation of the licence. \__/ + */ + + +Dynamic Universal Music Bibliotheque + +Copyright (C) 2001-2003 Ben Davis, Robert J Ohannessian and Julien Cugniere + +This software is provided 'as-is', without any express or implied warranty. +In no event shall the authors be held liable for any damages arising from the +use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim + that you wrote the original software. If you use this software in a + product, you are requested to acknowledge its use in the product + documentation, along with details on where to get an unmodified version of + this software, but this is not a strict requirement. + + [Note that the above point asks for a link to DUMB, not just a mention. + Googling for DUMB doesn't help much! The URL is "http://dumb.sf.net/".] + + [The only reason why the link is not strictly required is that such a + requirement prevents DUMB from being used in projects with certain other + licences, notably the GPL. See http://www.gnu.org/philosophy/bsd.html .] + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +3. This notice may not be removed from or altered in any source distribution. + +4. If you are using the Program in someone else's bedroom at any Monday + 3:05 PM, you are not allowed to modify the Program for ten minutes. [This + clause provided by Inphernic; every licence should contain at least one + clause, the reasoning behind which is far from obvious.] diff --git a/docs/licenses/gdtoa.txt b/docs/licenses/gdtoa.txt new file mode 100644 index 000000000..13c0d4140 --- /dev/null +++ b/docs/licenses/gdtoa.txt @@ -0,0 +1,27 @@ +/**************************************************************** + +The author of this software is David M. Gay. + +Copyright (C) 1998 by Lucent Technologies +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of Lucent or any of its entities +not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + +****************************************************************/ diff --git a/docs/licenses/lgpl.txt b/docs/licenses/lgpl.txt new file mode 100644 index 000000000..5ab7695ab --- /dev/null +++ b/docs/licenses/lgpl.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + From d14782fb37fc2283b2043e200a75c234fe298204 Mon Sep 17 00:00:00 2001 From: arookas Date: Wed, 31 Aug 2016 22:04:22 -0400 Subject: [PATCH 47/97] Added Thing_Damage3 function It acts as a simple wrapper around P_DamageMobj which can damage a single actor, but can also set the actor inflicting the damage. It returns the amount of damage actually done, or -1 if the damaging was cancelled. --- src/p_acs.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index a2b5275cb..edabca784 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4450,6 +4450,7 @@ enum EACSFunctions */ ACSF_CheckClass = 200, + ACSF_Thing_Damage3, // [arookas] // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -6035,6 +6036,15 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) const char *clsname = FBehavior::StaticLookupString(args[0]); return !!PClass::FindActor(clsname); } + + case ACSF_Thing_Damage3: // [arookas] wrapper around P_DamageMobj + { + // (target, ptr_select1, inflictor, ptr_select2, amount, damagetype) + AActor* target = COPY_AAPTR(SingleActorFromTID(args[0], activator), args[1]); + AActor* inflictor = COPY_AAPTR(SingleActorFromTID(args[2], activator), args[3]); + FName damagetype(FBehavior::StaticLookupString(args[5])); + return P_DamageMobj(target, inflictor, inflictor, args[4], damagetype); + } default: break; From d7b5bdc0f7e68b45fe2f76f8da35b61459e441dc Mon Sep 17 00:00:00 2001 From: arookas Date: Fri, 2 Sep 2016 23:04:12 -0400 Subject: [PATCH 48/97] Renamed Thing_Damage3 to DamageActor --- src/p_acs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index edabca784..0157fda75 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4450,7 +4450,7 @@ enum EACSFunctions */ ACSF_CheckClass = 200, - ACSF_Thing_Damage3, // [arookas] + ACSF_DamageActor, // [arookas] // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -6037,7 +6037,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return !!PClass::FindActor(clsname); } - case ACSF_Thing_Damage3: // [arookas] wrapper around P_DamageMobj + case ACSF_DamageActor: // [arookas] wrapper around P_DamageMobj { // (target, ptr_select1, inflictor, ptr_select2, amount, damagetype) AActor* target = COPY_AAPTR(SingleActorFromTID(args[0], activator), args[1]); From 5770e5dfaf0711619f3bb1f17fdd89065f98983d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Sep 2016 12:00:08 +0200 Subject: [PATCH 49/97] - split up m_specialpaths.cpp to be a separate file for each operating system. The reason for this is that the macOS version uses a deprecated API and in order to correct this, the file needs to be compiled as Objective-C++ which requires a different extension. --- src/CMakeLists.txt | 14 +- src/posix/osx/i_specialpaths.mm | 187 +++++++++ src/posix/unix/i_specialpaths.cpp | 199 ++++++++++ .../i_specialpaths.cpp} | 360 ++---------------- 4 files changed, 429 insertions(+), 331 deletions(-) create mode 100644 src/posix/osx/i_specialpaths.mm create mode 100644 src/posix/unix/i_specialpaths.cpp rename src/{m_specialpaths.cpp => win32/i_specialpaths.cpp} (50%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f6caa2f5d..51548afdd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -635,6 +635,7 @@ set( PLAT_WIN32_SOURCES win32/i_main.cpp win32/i_movie.cpp win32/i_system.cpp + win32/i_specialpaths.cpp win32/st_start.cpp win32/win32video.cpp ) set( PLAT_POSIX_SOURCES @@ -652,8 +653,11 @@ set( PLAT_SDL_SOURCES posix/sdl/i_timer.cpp posix/sdl/sdlvideo.cpp posix/sdl/st_start.cpp ) +set( PLAT_UNIX_SOURCES + posix/unix/i_specialpaths.cpp ) set( PLAT_OSX_SOURCES posix/osx/iwadpicker_cocoa.mm + posix/osx/i_specialpaths.mm posix/osx/zdoom.icns ) set( PLAT_COCOA_SOURCES posix/cocoa/critsec.cpp @@ -670,7 +674,7 @@ set( PLAT_COCOA_SOURCES if( WIN32 ) set( SYSTEM_SOURCES_DIR win32 ) set( SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ) - set( OTHER_SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ) + set( OTHER_SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ${PLAT_UNIX_SOURCES} ) if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) # CMake is not set up to compile and link rc files with GCC. :( @@ -685,12 +689,12 @@ elseif( APPLE ) if( OSX_COCOA_BACKEND ) set( SYSTEM_SOURCES_DIR posix posix/cocoa ) set( SYSTEM_SOURCES ${PLAT_COCOA_SOURCES} ) - set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_SDL_SOURCES} ) + set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_UNIX_SOURCES} ) else() set( SYSTEM_SOURCES_DIR posix posix/sdl ) set( SYSTEM_SOURCES ${PLAT_SDL_SOURCES} ) set( PLAT_OSX_SOURCES ${PLAT_OSX_SOURCES} posix/sdl/i_system.mm ) - set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_COCOA_SOURCES} ) + set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_COCOA_SOURCES} ${PLAT_UNIX_SOURCES} ) endif() set( SYSTEM_SOURCES ${SYSTEM_SOURCES} ${PLAT_POSIX_SOURCES} ${PLAT_OSX_SOURCES} "${FMOD_LIBRARY}" ) @@ -700,7 +704,7 @@ elseif( APPLE ) set_source_files_properties( posix/osx/iwadpicker_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-exceptions ) else() set( SYSTEM_SOURCES_DIR posix posix/sdl ) - set( SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ) + set( SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_UNIX_SOURCES} ) set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ) endif() @@ -1246,7 +1250,6 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE ${FASTMATH_SOURCES} ${PCH_SOURCES} x86.cpp - m_specialpaths.cpp strnatcmp.c zstring.cpp math/asin.c @@ -1410,6 +1413,7 @@ source_group("Resource Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r source_group("POSIX Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/.+") source_group("Cocoa Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/cocoa/.+") source_group("OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/.+") +source_group("Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/unix/.+") source_group("SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+") source_group("SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sfmt/.+") source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+") diff --git a/src/posix/osx/i_specialpaths.mm b/src/posix/osx/i_specialpaths.mm new file mode 100644 index 000000000..843fb82d6 --- /dev/null +++ b/src/posix/osx/i_specialpaths.mm @@ -0,0 +1,187 @@ +/* +** i_specialpaths.mm +** Gets special system folders where data should be stored. (macOS version) +** +**--------------------------------------------------------------------------- +** Copyright 2013-2016 Randy Heit +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include + +#include "cmdlib.h" +#include "m_misc.h" +#include "version.h" // for GAMENAME + +//=========================================================================== +// +// M_GetCachePath macOS +// +// Returns the path for cache GL nodes. +// +//=========================================================================== + +FString M_GetCachePath(bool create) +{ + FString path; + + char pathstr[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX)) + { + path = pathstr; + } + else + { + path = progdir; + } + path += "/zdoom/cache"; + return path; +} + +//=========================================================================== +// +// M_GetAutoexecPath macOS +// +// Returns the expected location of autoexec.cfg. +// +//=========================================================================== + +FString M_GetAutoexecPath() +{ + FString path; + + char cpath[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + path << cpath << "/" GAME_DIR "/autoexec.cfg"; + } + return path; +} + +//=========================================================================== +// +// M_GetCajunPath macOS +// +// Returns the location of the Cajun Bot definitions. +// +//=========================================================================== + +FString M_GetCajunPath(const char *botfilename) +{ + FString path; + + // Just copies the Windows code. Should this be more Mac-specific? + path << progdir << "zcajun/" << botfilename; + if (!FileExists(path)) + { + path = ""; + } + return path; +} + +//=========================================================================== +// +// M_GetConfigPath macOS +// +// Returns the path to the config file. On Windows, this can vary for reading +// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try +// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. +// +//=========================================================================== + +FString M_GetConfigPath(bool for_reading) +{ + char cpath[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kPreferencesFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + FString path; + path << cpath << "/" GAMENAMELOWERCASE ".ini"; + return path; + } + // Ungh. + return GAMENAMELOWERCASE ".ini"; +} + +//=========================================================================== +// +// M_GetScreenshotsPath macOS +// +// Returns the path to the default screenshots directory. +// +//=========================================================================== + +FString M_GetScreenshotsPath() +{ + FString path; + char cpath[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + path << cpath << "/" GAME_DIR "/Screenshots/"; + } + else + { + path = "~/"; + } + return path; +} + +//=========================================================================== +// +// M_GetSavegamesPath macOS +// +// Returns the path to the default save games directory. +// +//=========================================================================== + +FString M_GetSavegamesPath() +{ + FString path; + char cpath[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + path << cpath << "/" GAME_DIR "/Savegames/"; + } + return path; +} + diff --git a/src/posix/unix/i_specialpaths.cpp b/src/posix/unix/i_specialpaths.cpp new file mode 100644 index 000000000..6a17e1318 --- /dev/null +++ b/src/posix/unix/i_specialpaths.cpp @@ -0,0 +1,199 @@ +/* +** i_specialpaths.cpp +** Gets special system folders where data should be stored. (Unix version) +** +**--------------------------------------------------------------------------- +** Copyright 2013-2016 Randy Heit +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include "i_system.h" + +#include "version.h" // for GAMENAME + + +FString GetUserFile (const char *file) +{ + FString path; + struct stat info; + + path = NicePath("~/" GAME_DIR "/"); + + if (stat (path, &info) == -1) + { + struct stat extrainfo; + + // Sanity check for ~/.config + FString configPath = NicePath("~/.config/"); + if (stat (configPath, &extrainfo) == -1) + { + if (mkdir (configPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) + { + I_FatalError ("Failed to create ~/.config directory:\n%s", strerror(errno)); + } + } + else if (!S_ISDIR(extrainfo.st_mode)) + { + I_FatalError ("~/.config must be a directory"); + } + + // This can be removed after a release or two + // Transfer the old zdoom directory to the new location + bool moved = false; + FString oldpath = NicePath("~/." GAMENAMELOWERCASE "/"); + if (stat (oldpath, &extrainfo) != -1) + { + if (rename(oldpath, path) == -1) + { + I_Error ("Failed to move old " GAMENAMELOWERCASE " directory (%s) to new location (%s).", + oldpath.GetChars(), path.GetChars()); + } + else + moved = true; + } + + if (!moved && mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) + { + I_FatalError ("Failed to create %s directory:\n%s", + path.GetChars(), strerror (errno)); + } + } + else + { + if (!S_ISDIR(info.st_mode)) + { + I_FatalError ("%s must be a directory", path.GetChars()); + } + } + path += file; + return path; +} + +//=========================================================================== +// +// M_GetCachePath Unix +// +// Returns the path for cache GL nodes. +// +//=========================================================================== + +FString M_GetCachePath(bool create) +{ + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + FString path = NicePath("~/.config/zdoom/cache"); + if (create) + { + CreatePath(path); + } + return path; +} + +//=========================================================================== +// +// M_GetAutoexecPath Unix +// +// Returns the expected location of autoexec.cfg. +// +//=========================================================================== + +FString M_GetAutoexecPath() +{ + return GetUserFile("autoexec.cfg"); +} + +//=========================================================================== +// +// M_GetCajunPath Unix +// +// Returns the location of the Cajun Bot definitions. +// +//=========================================================================== + +FString M_GetCajunPath(const char *botfilename) +{ + FString path; + + // Check first in ~/.config/zdoom/botfilename. + path = GetUserFile(botfilename); + if (!FileExists(path)) + { + // Then check in SHARE_DIR/botfilename. + path = SHARE_DIR; + path << botfilename; + if (!FileExists(path)) + { + path = ""; + } + } + return path; +} + +//=========================================================================== +// +// M_GetConfigPath Unix +// +// Returns the path to the config file. On Windows, this can vary for reading +// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try +// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. +// +//=========================================================================== + +FString M_GetConfigPath(bool for_reading) +{ + return GetUserFile(GAMENAMELOWERCASE ".ini"); +} + +//=========================================================================== +// +// M_GetScreenshotsPath Unix +// +// Returns the path to the default screenshots directory. +// +//=========================================================================== + +FString M_GetScreenshotsPath() +{ + return NicePath("~/" GAME_DIR "/screenshots/"); +} + +//=========================================================================== +// +// M_GetSavegamesPath Unix +// +// Returns the path to the default save games directory. +// +//=========================================================================== + +FString M_GetSavegamesPath() +{ + return NicePath("~/" GAME_DIR); +} diff --git a/src/m_specialpaths.cpp b/src/win32/i_specialpaths.cpp similarity index 50% rename from src/m_specialpaths.cpp rename to src/win32/i_specialpaths.cpp index abfb5db8f..ed8dc2ee6 100644 --- a/src/m_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -1,27 +1,46 @@ -#ifdef __APPLE__ -#include -#endif +/* +** i_specialpaths.cpp +** Gets special system folders where data should be stored. (Windows version) +** +**--------------------------------------------------------------------------- +** Copyright 2013-2016 Randy Heit +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ -#ifdef _WIN32 #include #include #include #define USE_WINDOWS_DWORD -#endif #include "cmdlib.h" #include "m_misc.h" - -#if !defined(__APPLE__) && !defined(_WIN32) -#include -#include -#include "i_system.h" -#endif - #include "version.h" // for GAMENAME - -#if defined(_WIN32) - #include "i_system.h" typedef HRESULT (WINAPI *GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *); @@ -323,314 +342,3 @@ FString M_GetSavegamesPath() } return path; } - -#elif defined(__APPLE__) - -//=========================================================================== -// -// M_GetCachePath Mac OS X -// -// Returns the path for cache GL nodes. -// -//=========================================================================== - -FString M_GetCachePath(bool create) -{ - FString path; - - char pathstr[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX)) - { - path = pathstr; - } - else - { - path = progdir; - } - path += "/zdoom/cache"; - return path; -} - -//=========================================================================== -// -// M_GetAutoexecPath Mac OS X -// -// Returns the expected location of autoexec.cfg. -// -//=========================================================================== - -FString M_GetAutoexecPath() -{ - FString path; - - char cpath[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) - { - path << cpath << "/" GAME_DIR "/autoexec.cfg"; - } - return path; -} - -//=========================================================================== -// -// M_GetCajunPath Mac OS X -// -// Returns the location of the Cajun Bot definitions. -// -//=========================================================================== - -FString M_GetCajunPath(const char *botfilename) -{ - FString path; - - // Just copies the Windows code. Should this be more Mac-specific? - path << progdir << "zcajun/" << botfilename; - if (!FileExists(path)) - { - path = ""; - } - return path; -} - -//=========================================================================== -// -// M_GetConfigPath Mac OS X -// -// Returns the path to the config file. On Windows, this can vary for reading -// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try -// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. -// -//=========================================================================== - -FString M_GetConfigPath(bool for_reading) -{ - char cpath[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kUserDomain, kPreferencesFolderType, kCreateFolder, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) - { - FString path; - path << cpath << "/" GAMENAMELOWERCASE ".ini"; - return path; - } - // Ungh. - return GAMENAMELOWERCASE ".ini"; -} - -//=========================================================================== -// -// M_GetScreenshotsPath Mac OS X -// -// Returns the path to the default screenshots directory. -// -//=========================================================================== - -FString M_GetScreenshotsPath() -{ - FString path; - char cpath[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) - { - path << cpath << "/" GAME_DIR "/Screenshots/"; - } - else - { - path = "~/"; - } - return path; -} - -//=========================================================================== -// -// M_GetSavegamesPath Mac OS X -// -// Returns the path to the default save games directory. -// -//=========================================================================== - -FString M_GetSavegamesPath() -{ - FString path; - char cpath[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) - { - path << cpath << "/" GAME_DIR "/Savegames/"; - } - return path; -} - -#else // Linux, et al. - - -FString GetUserFile (const char *file) -{ - FString path; - struct stat info; - - path = NicePath("~/" GAME_DIR "/"); - - if (stat (path, &info) == -1) - { - struct stat extrainfo; - - // Sanity check for ~/.config - FString configPath = NicePath("~/.config/"); - if (stat (configPath, &extrainfo) == -1) - { - if (mkdir (configPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) - { - I_FatalError ("Failed to create ~/.config directory:\n%s", strerror(errno)); - } - } - else if (!S_ISDIR(extrainfo.st_mode)) - { - I_FatalError ("~/.config must be a directory"); - } - - // This can be removed after a release or two - // Transfer the old zdoom directory to the new location - bool moved = false; - FString oldpath = NicePath("~/." GAMENAMELOWERCASE "/"); - if (stat (oldpath, &extrainfo) != -1) - { - if (rename(oldpath, path) == -1) - { - I_Error ("Failed to move old " GAMENAMELOWERCASE " directory (%s) to new location (%s).", - oldpath.GetChars(), path.GetChars()); - } - else - moved = true; - } - - if (!moved && mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) - { - I_FatalError ("Failed to create %s directory:\n%s", - path.GetChars(), strerror (errno)); - } - } - else - { - if (!S_ISDIR(info.st_mode)) - { - I_FatalError ("%s must be a directory", path.GetChars()); - } - } - path += file; - return path; -} - -//=========================================================================== -// -// M_GetCachePath Unix -// -// Returns the path for cache GL nodes. -// -//=========================================================================== - -FString M_GetCachePath(bool create) -{ - // Don't use GAME_DIR and such so that ZDoom and its child ports can - // share the node cache. - FString path = NicePath("~/.config/zdoom/cache"); - if (create) - { - CreatePath(path); - } - return path; -} - -//=========================================================================== -// -// M_GetAutoexecPath Unix -// -// Returns the expected location of autoexec.cfg. -// -//=========================================================================== - -FString M_GetAutoexecPath() -{ - return GetUserFile("autoexec.cfg"); -} - -//=========================================================================== -// -// M_GetCajunPath Unix -// -// Returns the location of the Cajun Bot definitions. -// -//=========================================================================== - -FString M_GetCajunPath(const char *botfilename) -{ - FString path; - - // Check first in ~/.config/zdoom/botfilename. - path = GetUserFile(botfilename); - if (!FileExists(path)) - { - // Then check in SHARE_DIR/botfilename. - path = SHARE_DIR; - path << botfilename; - if (!FileExists(path)) - { - path = ""; - } - } - return path; -} - -//=========================================================================== -// -// M_GetConfigPath Unix -// -// Returns the path to the config file. On Windows, this can vary for reading -// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try -// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. -// -//=========================================================================== - -FString M_GetConfigPath(bool for_reading) -{ - return GetUserFile(GAMENAMELOWERCASE ".ini"); -} - -//=========================================================================== -// -// M_GetScreenshotsPath Unix -// -// Returns the path to the default screenshots directory. -// -//=========================================================================== - -FString M_GetScreenshotsPath() -{ - return NicePath("~/" GAME_DIR "/screenshots/"); -} - -//=========================================================================== -// -// M_GetSavegamesPath Unix -// -// Returns the path to the default save games directory. -// -//=========================================================================== - -FString M_GetSavegamesPath() -{ - return NicePath("~/" GAME_DIR); -} - -#endif From f31346968f447f396f190fd42cf1bfcd6162b09e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 3 Sep 2016 17:29:28 +0200 Subject: [PATCH 50/97] - added missing #include. --- src/posix/unix/i_specialpaths.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/posix/unix/i_specialpaths.cpp b/src/posix/unix/i_specialpaths.cpp index 6a17e1318..5dedba057 100644 --- a/src/posix/unix/i_specialpaths.cpp +++ b/src/posix/unix/i_specialpaths.cpp @@ -36,6 +36,7 @@ #include #include #include "i_system.h" +#include "cmdlib.h" #include "version.h" // for GAMENAME From 2ed4208a1b4ef65b339e543a4d05acc78988e329 Mon Sep 17 00:00:00 2001 From: Blue-Shadow Date: Sat, 3 Sep 2016 18:55:19 +0300 Subject: [PATCH 51/97] Added IfCVarInt SBARINFO command --- src/g_shared/sbarinfo_commands.cpp | 77 +++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index b4a011510..ba83ce1c6 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -3464,6 +3464,78 @@ class CommandIfWaterLevel : public SBarInfoNegatableFlowControl //////////////////////////////////////////////////////////////////////////////// +class CommandIfCVarInt : public SBarInfoNegatableFlowControl +{ + public: + CommandIfCVarInt(SBarInfo *script) : SBarInfoNegatableFlowControl(script), + equalcomp(false) + { + } + + void ParseNegatable(FScanner &sc, bool fullScreenOffsets) + { + if(!sc.CheckToken(TK_StringConst)) + { + sc.MustGetToken(TK_Identifier); + } + + cvarname = sc.String; + cvar = FindCVar(cvarname, nullptr); + + if (cvar != nullptr) + { + ECVarType cvartype = cvar->GetRealType(); + + if (cvartype == CVAR_Bool || cvartype == CVAR_Int) + { + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + value = sc.Number; + + if (sc.CheckToken(',')) + { + sc.MustGetToken(TK_Identifier); + + if(sc.Compare("equal")) + { + equalcomp = true; + } + } + } + else + { + sc.ScriptError("Type mismatch: console variable '%s' is not of type 'bool' or 'int'.", cvarname); + } + } + else + { + sc.ScriptError("Unknown console variable '%s'.", cvarname); + } + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SBarInfoNegatableFlowControl::Tick(block, statusBar, hudChanged); + + bool result = false; + cvar = GetCVar(statusBar->CPlayer->mo, cvarname); + + if (cvar != nullptr) + { + int cvarvalue = cvar->GetGenericRep(CVAR_Int).Int; + result = equalcomp ? cvarvalue == value : cvarvalue >= value; + } + + SetTruth(result, block, statusBar); + } + protected: + FString cvarname; + FBaseCVar *cvar; + int value; + bool equalcomp; +}; + +//////////////////////////////////////////////////////////////////////////////// + static const char *SBarInfoCommandNames[] = { "drawimage", "drawnumber", "drawswitchableimage", @@ -3474,7 +3546,7 @@ static const char *SBarInfoCommandNames[] = "isselected", "usesammo", "usessecondaryammo", "hasweaponpiece", "inventorybarnotvisible", "weaponammo", "ininventory", "alpha", "ifhealth", - "ifinvulnerable", "ifwaterlevel", + "ifinvulnerable", "ifwaterlevel", "ifcvarint", NULL }; @@ -3488,7 +3560,7 @@ enum SBarInfoCommands SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO, SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE, SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA, SBARINFO_IFHEALTH, - SBARINFO_IFINVULNERABLE, SBARINFO_IFWATERLEVEL, + SBARINFO_IFINVULNERABLE, SBARINFO_IFWATERLEVEL, SBARINFO_IFCVARINT, }; SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc) @@ -3524,6 +3596,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc) case SBARINFO_IFHEALTH: return new CommandIfHealth(script); case SBARINFO_IFINVULNERABLE: return new CommandIfInvulnerable(script); case SBARINFO_IFWATERLEVEL: return new CommandIfWaterLevel(script); + case SBARINFO_IFCVARINT: return new CommandIfCVarInt(script); } sc.ScriptError("Unknown command '%s'.\n", sc.String); From 77ac3bb2655ec922d62159ea93db73aaae8701e3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 4 Sep 2016 08:33:19 +0200 Subject: [PATCH 52/97] - fixed angle range checks in A_CheckIfTargetInLOS. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fixed point version had a mostly useless check that excluded ANGLE_MAX, this got incorrectly converted to floating point. Note that this version will clamp the angle to 360°, not merely overflow like it did with the fixed point code --- src/thingdef/thingdef_codeptr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 1f24a35c7..83db1fdaa 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4501,7 +4501,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) else { target = viewport; viewport = self; } } - if (fov > 0 && (fov < 360.)) + fov = MIN(fov, 360.); + + if (fov > 0) { DAngle an = absangle(viewport->AngleTo(target), viewport->Angles.Yaw); From 677efb73bce2b178b90781afbba1f9b3912f2206 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 4 Sep 2016 10:02:09 +0300 Subject: [PATCH 53/97] Fixed compilation with GCC/Clang No longer aborts with error: cannot pass object of non-trivial type 'FString' through variadic method; call will abort at runtime --- src/g_shared/sbarinfo_commands.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index ba83ce1c6..a9fac2ee1 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -3504,12 +3504,12 @@ class CommandIfCVarInt : public SBarInfoNegatableFlowControl } else { - sc.ScriptError("Type mismatch: console variable '%s' is not of type 'bool' or 'int'.", cvarname); + sc.ScriptError("Type mismatch: console variable '%s' is not of type 'bool' or 'int'.", cvarname.GetChars()); } } else { - sc.ScriptError("Unknown console variable '%s'.", cvarname); + sc.ScriptError("Unknown console variable '%s'.", cvarname.GetChars()); } } void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) From eff03d13f0e4b54c7ac1fe0f942f1bc3580c7ddf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 4 Sep 2016 10:22:59 +0200 Subject: [PATCH 54/97] - fixed last commit. --- src/thingdef/thingdef_codeptr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 83db1fdaa..d520a0b9d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -76,6 +76,7 @@ #include "d_player.h" #include "p_maputl.h" #include "p_spec.h" +#include "templates.h" #include "math/cmath.h" AActor *SingleActorFromTID(int tid, AActor *defactor); @@ -4501,7 +4502,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) else { target = viewport; viewport = self; } } - fov = MIN(fov, 360.); + fov = MIN(fov, 360.); if (fov > 0) { From 954ac8ce5e607e7811a91717e0e1cfe5126d820a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 4 Sep 2016 10:27:41 +0200 Subject: [PATCH 55/97] - removed DirectX setup from CMakeLists for Visual Studio For VS 2015 this is no longer needed, the DX headers and libraries are part of the Windows SDK and do not need to be looked for explicitly. --- src/CMakeLists.txt | 84 ++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 51548afdd..190a9560a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -114,49 +114,59 @@ if( WIN32 ) set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) set( NASM_NAMES nasmw nasm ) - find_path( D3D_INCLUDE_DIR d3d9.h - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Include ) - if( NOT D3D_INCLUDE_DIR ) - message( SEND_ERROR "Could not find DirectX 9 header files" ) - else() - include_directories( ${D3D_INCLUDE_DIR} ) - endif() + if( NOT MSVC ) + find_path( D3D_INCLUDE_DIR d3d9.h + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Include ) + if( NOT D3D_INCLUDE_DIR ) + message( SEND_ERROR "Could not find DirectX 9 header files" ) + else() + include_directories( ${D3D_INCLUDE_DIR} ) + endif() - find_path( XINPUT_INCLUDE_DIR xinput.h - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Include ) - if( NOT XINPUT_INCLUDE_DIR ) - message( WARNING "Could not find xinput.h. XInput will be disabled." ) - add_definitions( -DNO_XINPUT ) + find_path( XINPUT_INCLUDE_DIR xinput.h + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Include ) + if( NOT XINPUT_INCLUDE_DIR ) + message( WARNING "Could not find xinput.h. XInput will be disabled." ) + add_definitions( -DNO_XINPUT ) + else() + include_directories( ${XINPUT_INCLUDE_DIR} ) + endif() + + find_library( DX_dxguid_LIBRARY dxguid + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) + find_library( DX_dinput8_LIBRARY dinput8 + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) + + set( DX_LIBS_FOUND YES ) + if( NOT DX_dxguid_LIBRARY ) + set( DX_LIBS_FOUND NO ) + endif() + if( NOT DX_dinput8_LIBRARY ) + set( DX_LIBS_FOUND NO ) + endif() + + if( NOT DX_LIBS_FOUND ) + message( FATAL_ERROR "Could not find DirectX 9 libraries" ) + endif() + + set( DX_LIBS + "${DX_dxguid_LIBRARY}" + "${DX_dinput8_LIBRARY}" + ) else() - include_directories( ${XINPUT_INCLUDE_DIR} ) + set( DX_LIBS + dxguid + dinput8 + ) endif() - find_library( DX_dxguid_LIBRARY dxguid - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - find_library( DX_dinput8_LIBRARY dinput8 - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - - set( DX_LIBS_FOUND YES ) - if( NOT DX_dxguid_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif() - if( NOT DX_dinput8_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif() - - if( NOT DX_LIBS_FOUND ) - message( FATAL_ERROR "Could not find DirectX 9 libraries" ) - endif() - - set( ZDOOM_LIBS + set( ZDOOM_LIBS ${DX_LIBS} wsock32 winmm - "${DX_dxguid_LIBRARY}" - "${DX_dinput8_LIBRARY}" ole32 user32 gdi32 From 3ce25bc348a84c43ae4b15f8c7d8cff908da668b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 6 Sep 2016 08:41:13 +0200 Subject: [PATCH 56/97] - fixed: FxPreIncrDecr depended on undefined compiler behavior. It could only work with right to left function argument processing, but with left to right it failed because the ParseExpressionA call altered sc.TokenType. Note that with register-based arguments on 64 bit platforms this is a very critical issue! --- src/thingdef/thingdef_exp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 991e9b947..cad6198f0 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -309,7 +309,8 @@ static FxExpression *ParseExpressionC (FScanner &sc, PClassActor *cls) static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls) { sc.GetToken(); - switch(sc.TokenType) + int token = sc.TokenType; + switch(token) { case '~': return new FxUnaryNotBitwise(ParseExpressionA (sc, cls)); @@ -325,7 +326,7 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls) case TK_Incr: case TK_Decr: - return new FxPreIncrDecr(ParseExpressionA(sc, cls), sc.TokenType); + return new FxPreIncrDecr(ParseExpressionA(sc, cls), token); default: sc.UnGet(); From 5a3147407ec1c08e29d701061d2436edac40af4b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 6 Sep 2016 22:34:59 +0200 Subject: [PATCH 57/97] - fixed floatification error in A_MaulerTorpedoWave. --- src/g_strife/a_strifeweapons.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index f81ca79f7..0a753e961 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -552,7 +552,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) // If the torpedo hit the ceiling, it should still spawn the wave savedz = self->Z(); - if (wavedef && self->ceilingz < wavedef->Top()) + if (wavedef && self->ceilingz < self->Z() + wavedef->height) { self->SetZ(self->ceilingz - wavedef->Height); } From f536523fbda2b7ef67febe71f50565479a8902f0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 6 Sep 2016 22:36:53 +0200 Subject: [PATCH 58/97] - It's Height, not height... --- src/g_strife/a_strifeweapons.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 0a753e961..24e7fb5c7 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -552,7 +552,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) // If the torpedo hit the ceiling, it should still spawn the wave savedz = self->Z(); - if (wavedef && self->ceilingz < self->Z() + wavedef->height) + if (wavedef && self->ceilingz < self->Z() + wavedef->Height) { self->SetZ(self->ceilingz - wavedef->Height); } From 2e8aa53e6ad0fb35728ffa2aff0227444f467966 Mon Sep 17 00:00:00 2001 From: yqco Date: Wed, 24 Aug 2016 04:21:46 -0600 Subject: [PATCH 59/97] Add SetActorFlag ACS function int SetActorFlag(int tid, str flagname, bool value); - Mimics DECORATE's A_ChangeFlag - Returns number of actors affected (number of things with the flag) - Affects activator if TID is 0 # Conflicts: # src/p_acs.cpp --- src/p_acs.cpp | 29 ++++++++++ src/thingdef/thingdef.h | 1 + src/thingdef/thingdef_codeptr.cpp | 85 +--------------------------- src/thingdef/thingdef_properties.cpp | 65 +++++++++++++++++++++ 4 files changed, 96 insertions(+), 84 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 0157fda75..67ae37771 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4451,6 +4451,7 @@ enum EACSFunctions ACSF_CheckClass = 200, ACSF_DamageActor, // [arookas] + ACSF_SetActorFlag, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -6046,6 +6047,34 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return P_DamageMobj(target, inflictor, inflictor, args[4], damagetype); } + case ACSF_SetActorFlag: + { + int tid = args[0]; + FString flagname = FBehavior::StaticLookupString(args[1]); + bool flagvalue = !!args[2]; + int count = 0; // Return value; number of actors affected + if (tid == 0) + { + if (ModActorFlag(activator, flagname, flagvalue)) + { + ++count; + } + } + else + { + FActorIterator it(tid); + while ((actor = it.Next()) != nullptr) + { + // Don't log errors when affecting many actors because things might share a TID but not share the flag + if (ModActorFlag(actor, flagname, flagvalue, false)) + { + ++count; + } + } + } + return count; + } + default: break; } diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 296383a3d..3a419b112 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -30,6 +30,7 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index); const char *GetFlagName(unsigned int flagnum, int flagoffset); void ModActorFlag(AActor *actor, FFlagDef *fd, bool set); +bool ModActorFlag(AActor *actor, FString &flagname, bool set, bool printerror = true); INTBOOL CheckActorFlag(const AActor *actor, FFlagDef *fd); INTBOOL CheckActorFlag(const AActor *owner, const char *flagname, bool printerror = true); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d520a0b9d..8c2a020c7 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4681,90 +4681,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) PARAM_STRING (flagname); PARAM_BOOL (value); - const char *dot = strchr(flagname, '.'); - FFlagDef *fd; - PClassActor *cls = self->GetClass(); - - if (dot != NULL) - { - FString part1(flagname.GetChars(), dot - flagname); - fd = FindFlag(cls, part1, dot + 1); - } - else - { - fd = FindFlag(cls, flagname, NULL); - } - - if (fd != NULL) - { - bool kill_before, kill_after; - INTBOOL item_before, item_after; - INTBOOL secret_before, secret_after; - - kill_before = self->CountsAsKill(); - item_before = self->flags & MF_COUNTITEM; - secret_before = self->flags5 & MF5_COUNTSECRET; - - if (fd->structoffset == -1) - { - HandleDeprecatedFlags(self, cls, value, fd->flagbit); - } - else - { - ActorFlags *flagp = (ActorFlags*) (((char*)self) + fd->structoffset); - - // If these 2 flags get changed we need to update the blockmap and sector links. - bool linkchange = flagp == &self->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR); - - if (linkchange) self->UnlinkFromWorld(); - ModActorFlag(self, fd, value); - if (linkchange) self->LinkToWorld(); - } - kill_after = self->CountsAsKill(); - item_after = self->flags & MF_COUNTITEM; - secret_after = self->flags5 & MF5_COUNTSECRET; - // Was this monster previously worth a kill but no longer is? - // Or vice versa? - if (kill_before != kill_after) - { - if (kill_after) - { // It counts as a kill now. - level.total_monsters++; - } - else - { // It no longer counts as a kill. - level.total_monsters--; - } - } - // same for items - if (item_before != item_after) - { - if (item_after) - { // It counts as an item now. - level.total_items++; - } - else - { // It no longer counts as an item - level.total_items--; - } - } - // and secretd - if (secret_before != secret_after) - { - if (secret_after) - { // It counts as an secret now. - level.total_secrets++; - } - else - { // It no longer counts as an secret - level.total_secrets--; - } - } - } - else - { - Printf("Unknown flag '%s' in '%s'\n", flagname.GetChars(), cls->TypeName.GetChars()); - } + ModActorFlag(self, flagname, value); return 0; } diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 372f444cd..f6ad511af 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -162,6 +162,71 @@ void ModActorFlag(AActor *actor, FFlagDef *fd, bool set) #endif } +//========================================================================== +// +// Finds a flag by name and sets or clears it +// +// Returns true if the flag was found for the actor; else returns false +// +//========================================================================== + +bool ModActorFlag(AActor *actor, FString &flagname, bool set, bool printerror) +{ + bool found = false; + + if (actor != NULL) + { + const char *dot = strchr(flagname, '.'); + FFlagDef *fd; + PClassActor *cls = actor->GetClass(); + + if (dot != NULL) + { + FString part1(flagname.GetChars(), dot - flagname); + fd = FindFlag(cls, part1, dot + 1); + } + else + { + fd = FindFlag(cls, flagname, NULL); + } + + if (fd != NULL) + { + found = true; + + if (actor->CountsAsKill() && actor->health > 0) --level.total_monsters; + if (actor->flags & MF_COUNTITEM) --level.total_items; + if (actor->flags5 & MF5_COUNTSECRET) --level.total_secrets; + + if (fd->structoffset == -1) + { + HandleDeprecatedFlags(actor, cls, set, fd->flagbit); + } + else + { + ActorFlags *flagp = (ActorFlags*)(((char*)actor) + fd->structoffset); + + // If these 2 flags get changed we need to update the blockmap and sector links. + bool linkchange = flagp == &actor->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR); + + if (linkchange) actor->UnlinkFromWorld(); + ModActorFlag(actor, fd, set); + if (linkchange) actor->LinkToWorld(); + } + + if (actor->CountsAsKill() && actor->health > 0) ++level.total_monsters; + if (actor->flags & MF_COUNTITEM) ++level.total_items; + if (actor->flags5 & MF5_COUNTSECRET) ++level.total_secrets; + } + else if (printerror) + { + DPrintf(DMSG_ERROR, "ACS/DECORATE: '%s' is not a flag in '%s'\n", flagname.GetChars(), cls->TypeName.GetChars()); + } + } + + return found; +} + //========================================================================== // // Returns whether an actor flag is true or not. From ce13b5c6e1731ea04a28c9708470e189593d0e76 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sun, 4 Sep 2016 08:53:20 -0500 Subject: [PATCH 60/97] Enhanced FastProjectile trails. - Trails now copy pitch, and set the projectile as the target. - Added GETOWNER flag. Using it sets the owner of the fast projectile as the target instead, if it has an owner. --- src/actor.h | 2 +- src/g_shared/a_fastprojectile.cpp | 8 +++++++- src/thingdef/thingdef_data.cpp | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/actor.h b/src/actor.h index b895d1e2a..522405dd6 100644 --- a/src/actor.h +++ b/src/actor.h @@ -283,7 +283,7 @@ enum ActorFlag4 enum ActorFlag5 { MF5_DONTDRAIN = 0x00000001, // cannot be drained health from. - /* FREE SLOT 0x00000002*/ + MF5_GETOWNER = 0x00000002, MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances. MF5_NOFORWARDFALL = 0x00000008, // Does not make any actor fall forward by being damaged by this MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 8c7d63b74..c1253f966 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -166,8 +166,14 @@ void AFastProjectile::Effect() if (trail != NULL) { AActor *act = Spawn (trail, PosAtZ(hitz), ALLOW_REPLACE); - if (act != NULL) + if (act != nullptr) { + if ((flags5 & MF5_GETOWNER) && (target != nullptr)) + act->target = target; + else + act->target = this; + + act->Angles.Pitch = Angles.Pitch; act->Angles.Yaw = Angles.Yaw; } } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 8fceca8ee..756c56a1a 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -182,6 +182,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF4, BOSSDEATH, AActor, flags4), DEFINE_FLAG(MF5, DONTDRAIN, AActor, flags5), + DEFINE_FLAG(MF5, GETOWNER, AActor, flags5), DEFINE_FLAG(MF5, NODROPOFF, AActor, flags5), DEFINE_FLAG(MF5, NOFORWARDFALL, AActor, flags5), DEFINE_FLAG(MF5, COUNTSECRET, AActor, flags5), From 043ada24da842dd5e6085422f1b957851794767a Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sun, 4 Sep 2016 16:49:57 -0500 Subject: [PATCH 61/97] Wave quakes now stack. --- src/g_shared/a_quake.cpp | 67 +++++++++++++++++++---------------- src/g_shared/a_sharedglobal.h | 5 ++- src/r_utility.cpp | 18 +++++----- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index 74c416468..aae006ca7 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -161,7 +161,7 @@ double DEarthquake::GetModWave(double waveMultiplier) const // //========================================================================== -double DEarthquake::GetModIntensity(double intensity) const +double DEarthquake::GetModIntensity(double intensity, bool fake) const { assert(m_CountdownStart >= m_Countdown); @@ -195,7 +195,7 @@ double DEarthquake::GetModIntensity(double intensity) const } scalar = (scalar > divider) ? divider : scalar; - if (m_Flags & QF_FULLINTENSITY) + if (!fake && (m_Flags & QF_FULLINTENSITY)) { scalar *= 2; } @@ -273,64 +273,69 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger DEarthquake *quake; int count = 0; - while ( (quake = iterator.Next()) != NULL) + while ( (quake = iterator.Next()) != nullptr) { - if (quake->m_Spot != NULL) + if (quake->m_Spot != nullptr) { - double dist = quake->m_Spot->Distance2D (victim, true); + const double dist = quake->m_Spot->Distance2D(victim, true); if (dist < quake->m_TremorRadius) { - const double falloff = quake->GetFalloff(dist); - const double rfalloff = (quake->m_RollIntensity != 0) ? falloff : 0.; ++count; - double x = quake->GetModIntensity(quake->m_Intensity.X); - double y = quake->GetModIntensity(quake->m_Intensity.Y); - double z = quake->GetModIntensity(quake->m_Intensity.Z); - double r = quake->GetModIntensity(quake->m_RollIntensity); + const double falloff = quake->GetFalloff(dist); + const double r = quake->GetModIntensity(quake->m_RollIntensity); + const double strength = quake->GetModIntensity(1.0, true); + DVector3 intensity; + intensity.X = quake->GetModIntensity(quake->m_Intensity.X); + intensity.Y = quake->GetModIntensity(quake->m_Intensity.Y); + intensity.Z = quake->GetModIntensity(quake->m_Intensity.Z); if (!(quake->m_Flags & QF_WAVE)) { jiggers.Falloff = MAX(falloff, jiggers.Falloff); - jiggers.RFalloff = MAX(rfalloff, jiggers.RFalloff); - jiggers.RollIntensity = MAX(r, jiggers.RollIntensity); + jiggers.RollIntensity = MAX(r, jiggers.RollIntensity) * jiggers.Falloff; + + intensity *= jiggers.Falloff; if (quake->m_Flags & QF_RELATIVE) { - jiggers.RelIntensity.X = MAX(x, jiggers.RelIntensity.X); - jiggers.RelIntensity.Y = MAX(y, jiggers.RelIntensity.Y); - jiggers.RelIntensity.Z = MAX(z, jiggers.RelIntensity.Z); + jiggers.RelIntensity.X = MAX(intensity.X, jiggers.RelIntensity.X); + jiggers.RelIntensity.Y = MAX(intensity.Y, jiggers.RelIntensity.Y); + jiggers.RelIntensity.Z = MAX(intensity.Z, jiggers.RelIntensity.Z); } else { - jiggers.Intensity.X = MAX(x, jiggers.Intensity.X); - jiggers.Intensity.Y = MAX(y, jiggers.Intensity.Y); - jiggers.Intensity.Z = MAX(z, jiggers.Intensity.Z); + jiggers.Intensity.X = MAX(intensity.X, jiggers.Intensity.X); + jiggers.Intensity.Y = MAX(intensity.Y, jiggers.Intensity.Y); + jiggers.Intensity.Z = MAX(intensity.Z, jiggers.Intensity.Z); } } else { - jiggers.WFalloff = MAX(falloff, jiggers.WFalloff); - jiggers.RWFalloff = MAX(rfalloff, jiggers.RWFalloff); - jiggers.RollWave = r * quake->GetModWave(quake->m_RollWave); - double mx = x * quake->GetModWave(quake->m_WaveSpeed.X); - double my = y * quake->GetModWave(quake->m_WaveSpeed.Y); - double mz = z * quake->GetModWave(quake->m_WaveSpeed.Z); + jiggers.Falloff = MAX(falloff, jiggers.Falloff); + jiggers.RollWave = r * quake->GetModWave(quake->m_RollWave) * jiggers.Falloff * strength; + + + intensity.X *= quake->GetModWave(quake->m_WaveSpeed.X); + intensity.Y *= quake->GetModWave(quake->m_WaveSpeed.Y); + intensity.Z *= quake->GetModWave(quake->m_WaveSpeed.Z); + intensity *= strength * jiggers.Falloff; // [RH] This only gives effect to the last sine quake. I would // prefer if some way was found to make multiples coexist // peacefully, but just summing them together is undesirable // because they could cancel each other out depending on their // relative phases. + + // [MC] Now does so. And they stack rather well. I'm a little + // surprised at how easy it was. + + if (quake->m_Flags & QF_RELATIVE) { - jiggers.RelOffset.X = mx; - jiggers.RelOffset.Y = my; - jiggers.RelOffset.Z = mz; + jiggers.RelOffset += intensity; } else { - jiggers.Offset.X = mx; - jiggers.Offset.Y = my; - jiggers.Offset.Z = mz; + jiggers.Offset += intensity; } } } diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index f873ab0b7..314061f04 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -153,7 +153,7 @@ struct FQuakeJiggers DVector3 RelIntensity; DVector3 Offset; DVector3 RelOffset; - double Falloff, WFalloff, RFalloff, RWFalloff; + double Falloff; double RollIntensity, RollWave; }; @@ -180,8 +180,7 @@ public: int m_Highpoint, m_MiniCount; double m_RollIntensity, m_RollWave; - - double GetModIntensity(double intensity) const; + double GetModIntensity(double intensity, bool fake = false) const; double GetModWave(double waveMultiplier) const; double GetFalloff(double dist) const; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 71d3f2376..00ac91c97 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -656,7 +656,7 @@ void R_AddInterpolationPoint(const DVector3a &vec) // //========================================================================== -static double QuakePower(double factor, double intensity, double offset, double falloff, double wfalloff) +static double QuakePower(double factor, double intensity, double offset) { double randumb; if (intensity == 0) @@ -667,7 +667,7 @@ static double QuakePower(double factor, double intensity, double offset, double { randumb = pr_torchflicker.GenRand_Real2() * (intensity * 2) - intensity; } - return factor * (wfalloff * offset + falloff * randumb); + return factor * (offset + randumb); } //========================================================================== @@ -797,36 +797,36 @@ void R_SetupFrame (AActor *actor) if (jiggers.RollIntensity != 0 || jiggers.RollWave != 0) { - ViewRoll += QuakePower(quakefactor, jiggers.RollIntensity, jiggers.RollWave, jiggers.RFalloff, jiggers.RWFalloff); + ViewRoll += QuakePower(quakefactor, jiggers.RollIntensity, jiggers.RollWave); } if (jiggers.RelIntensity.X != 0 || jiggers.RelOffset.X != 0) { an = camera->Angles.Yaw; - double power = QuakePower(quakefactor, jiggers.RelIntensity.X, jiggers.RelOffset.X, jiggers.Falloff, jiggers.WFalloff); + double power = QuakePower(quakefactor, jiggers.RelIntensity.X, jiggers.RelOffset.X); ViewPos += an.ToVector(power); } if (jiggers.RelIntensity.Y != 0 || jiggers.RelOffset.Y != 0) { an = camera->Angles.Yaw + 90; - double power = QuakePower(quakefactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y, jiggers.Falloff, jiggers.WFalloff); + double power = QuakePower(quakefactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y); ViewPos += an.ToVector(power); } // FIXME: Relative Z is not relative if (jiggers.RelIntensity.Z != 0 || jiggers.RelOffset.Z != 0) { - ViewPos.Z += QuakePower(quakefactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z, jiggers.Falloff, jiggers.WFalloff); + ViewPos.Z += QuakePower(quakefactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z); } if (jiggers.Intensity.X != 0 || jiggers.Offset.X != 0) { - ViewPos.X += QuakePower(quakefactor, jiggers.Intensity.X, jiggers.Offset.X, jiggers.Falloff, jiggers.WFalloff); + ViewPos.X += QuakePower(quakefactor, jiggers.Intensity.X, jiggers.Offset.X); } if (jiggers.Intensity.Y != 0 || jiggers.Offset.Y != 0) { - ViewPos.Y += QuakePower(quakefactor, jiggers.Intensity.Y, jiggers.Offset.Y, jiggers.Falloff, jiggers.WFalloff); + ViewPos.Y += QuakePower(quakefactor, jiggers.Intensity.Y, jiggers.Offset.Y); } if (jiggers.Intensity.Z != 0 || jiggers.Offset.Z != 0) { - ViewPos.Z += QuakePower(quakefactor, jiggers.Intensity.Z, jiggers.Offset.Z, jiggers.Falloff, jiggers.WFalloff); + ViewPos.Z += QuakePower(quakefactor, jiggers.Intensity.Z, jiggers.Offset.Z); } } } From 01e9d351b48cb48e94d9b4b90c5c799eda2378f9 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Wed, 7 Sep 2016 11:24:04 -0500 Subject: [PATCH 62/97] - Don't pass flags directly from A_Explode to P_RadiusAttack. XF_EXPLICITDAMAGETYPE would cause explosions to deal no damage otherwise. --- src/thingdef/thingdef_codeptr.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 8c2a020c7..642f132af 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1422,7 +1422,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) damagetype = self->DamageType; } - int count = P_RadiusAttack (self, self->target, damage, distance, damagetype, flags, fulldmgdistance); + int pflags = 0; + if (flags & XF_HURTSOURCE) pflags |= RADF_HURTSOURCE; + if (flags & XF_NOTMISSILE) pflags |= RADF_SOURCEISSPOT; + + int count = P_RadiusAttack (self, self->target, damage, distance, damagetype, pflags, fulldmgdistance); P_CheckSplash(self, distance); if (alert && self->target != NULL && self->target->player != NULL) { From 6414e013544218f5450510078f27383087ae4b8f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 6 Sep 2016 19:48:14 +0200 Subject: [PATCH 63/97] Add uiscale slider controlling what scale the On setting uses for hud_scale, hud_althudscale and con_scaletext --- src/c_console.cpp | 61 +++++++++++------------ src/ct_chat.cpp | 32 +++++-------- src/g_shared/hudmessages.cpp | 93 +++++++++--------------------------- src/g_shared/sbarinfo.cpp | 10 +++- src/g_shared/shared_hud.cpp | 42 +++++++++------- src/g_shared/shared_sbar.cpp | 38 ++++++--------- src/v_draw.cpp | 10 +++- src/v_video.h | 2 + wadsrc/static/language.enu | 1 + wadsrc/static/menudef.txt | 3 ++ 10 files changed, 125 insertions(+), 167 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 850a29455..026266359 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -159,12 +159,24 @@ static int HistSize; CVAR (Float, con_notifytime, 3.f, CVAR_ARCHIVE) CVAR (Bool, con_centernotify, false, CVAR_ARCHIVE) -CUSTOM_CVAR (Int, con_scaletext, 0, CVAR_ARCHIVE) // Scale notify text at high resolutions? +CUSTOM_CVAR (Int, con_scaletext, 1, CVAR_ARCHIVE) // Scale notify text at high resolutions? { if (self < 0) self = 0; if (self > 3) self = 3; } +int con_uiscale() +{ + switch (con_scaletext) + { + default: + case 0: return 1; + case 1: return uiscale; + case 2: return 2; + case 3: return 4; + } +} + CUSTOM_CVAR(Float, con_alpha, 0.75f, CVAR_ARCHIVE) { if (self < 0.f) self = 0.f; @@ -493,13 +505,13 @@ void C_AddNotifyString (int printlevel, const char *source) return; } - switch (con_scaletext) + if (con_uiscale() == 0) { - default: - case 0: width = DisplayWidth; break; - case 1: width = DisplayWidth / CleanXfac; break; - case 2: width = DisplayWidth / 2; break; - case 3: width = DisplayWidth / 4; break; + width = DisplayWidth / CleanXfac; + } + else + { + width = DisplayWidth / con_uiscale(); } if (addtype == APPENDLINE && NotifyStrings[NUMNOTIFIES-1].PrintLevel == printlevel) @@ -721,7 +733,7 @@ static void C_DrawNotifyText () canskip = true; lineadv = SmallFont->GetHeight (); - if (con_scaletext == 1) + if (con_uiscale() == 0) { lineadv *= CleanYfac; } @@ -755,7 +767,7 @@ static void C_DrawNotifyText () else color = PrintColors[NotifyStrings[i].PrintLevel]; - if (con_scaletext == 1) + if (con_uiscale() == 0) { if (!center) screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, @@ -766,7 +778,7 @@ static void C_DrawNotifyText () line, NotifyStrings[i].Text, DTA_CleanNoMove, true, DTA_AlphaF, alpha, TAG_DONE); } - else if (con_scaletext == 0) + else if (con_uiscale() == 1) { if (!center) screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, @@ -777,37 +789,20 @@ static void C_DrawNotifyText () line, NotifyStrings[i].Text, DTA_AlphaF, alpha, TAG_DONE); } - else if (con_scaletext == 3) - { - if (!center) - screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, - DTA_VirtualWidth, screen->GetWidth() / 4, - DTA_VirtualHeight, screen->GetHeight() / 4, - DTA_KeepRatio, true, - DTA_AlphaF, alpha, TAG_DONE); - else - screen->DrawText (SmallFont, color, (screen->GetWidth() / 4 - - SmallFont->StringWidth (NotifyStrings[i].Text))/4, - line, NotifyStrings[i].Text, - DTA_VirtualWidth, screen->GetWidth() / 4, - DTA_VirtualHeight, screen->GetHeight() / 4, - DTA_KeepRatio, true, - DTA_AlphaF, alpha, TAG_DONE); - } else { if (!center) screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, - DTA_VirtualWidth, screen->GetWidth() / 2, - DTA_VirtualHeight, screen->GetHeight() / 2, + DTA_VirtualWidth, screen->GetWidth() / con_uiscale(), + DTA_VirtualHeight, screen->GetHeight() / con_uiscale(), DTA_KeepRatio, true, DTA_AlphaF, alpha, TAG_DONE); else - screen->DrawText (SmallFont, color, (screen->GetWidth() / 2 - - SmallFont->StringWidth (NotifyStrings[i].Text))/2, + screen->DrawText (SmallFont, color, (screen->GetWidth() / con_uiscale() - + SmallFont->StringWidth (NotifyStrings[i].Text))/ con_uiscale(), line, NotifyStrings[i].Text, - DTA_VirtualWidth, screen->GetWidth() / 2, - DTA_VirtualHeight, screen->GetHeight() / 2, + DTA_VirtualWidth, screen->GetWidth() / con_uiscale(), + DTA_VirtualHeight, screen->GetHeight() / con_uiscale(), DTA_KeepRatio, true, DTA_AlphaF, alpha, TAG_DONE); } diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index b053d8bd8..7fd36d0ab 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -46,6 +46,8 @@ EXTERN_CVAR (Bool, sb_cooperative_enable) EXTERN_CVAR (Bool, sb_deathmatch_enable) EXTERN_CVAR (Bool, sb_teamdeathmatch_enable) +int con_uiscale(); + // Public data void CT_Init (); @@ -224,7 +226,7 @@ void CT_Drawer (void) int i, x, scalex, y, promptwidth; y = (viewactive || gamestate != GS_LEVEL) ? -10 : -30; - if (con_scaletext == 1) + if (con_uiscale() == 0) { scalex = CleanXfac; y *= CleanYfac; @@ -235,25 +237,17 @@ void CT_Drawer (void) } int screen_width, screen_height, st_y; - switch (con_scaletext) + if (con_uiscale() == 0) { - default: - case 0: - case 1: screen_width = SCREENWIDTH; screen_height = SCREENHEIGHT; st_y = ST_Y; - break; - case 2: - screen_width = SCREENWIDTH / 2; - screen_height = SCREENHEIGHT / 2; - st_y = ST_Y / 2; - break; - case 3: - screen_width = SCREENWIDTH / 4; - screen_height = SCREENHEIGHT / 4; - st_y = ST_Y / 4; - break; + } + else + { + screen_width = SCREENWIDTH / con_uiscale(); + screen_height = SCREENHEIGHT / con_uiscale(); + st_y = ST_Y / con_uiscale(); } y += ((SCREENHEIGHT == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y; @@ -280,10 +274,10 @@ void CT_Drawer (void) // draw the prompt, text, and cursor ChatQueue[len] = SmallFont->GetCursor(); ChatQueue[len+1] = '\0'; - if (con_scaletext < 2) + if (con_uiscale() < 2) { - screen->DrawText (SmallFont, CR_GREEN, 0, y, prompt, DTA_CleanNoMove, *con_scaletext, TAG_DONE); - screen->DrawText (SmallFont, CR_GREY, promptwidth, y, (char *)(ChatQueue + i), DTA_CleanNoMove, *con_scaletext, TAG_DONE); + screen->DrawText (SmallFont, CR_GREEN, 0, y, prompt, DTA_CleanNoMove, con_uiscale() == 0, TAG_DONE); + screen->DrawText (SmallFont, CR_GREY, promptwidth, y, (char *)(ChatQueue + i), DTA_CleanNoMove, con_uiscale() == 0, TAG_DONE); } else { diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 9f13d3d9e..628c8a5ee 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -41,7 +41,8 @@ #include "doomstat.h" #include "farchive.h" -EXTERN_CVAR (Int, con_scaletext) +EXTERN_CVAR(Int, con_scaletext) +int con_uiscale(); IMPLEMENT_POINTY_CLASS (DHUDMessage) DECLARE_POINTER(Next) @@ -260,13 +261,10 @@ void DHUDMessage::ResetText (const char *text) } else { - switch (con_scaletext) + switch (con_uiscale()) { - default: - case 0: width = SCREENWIDTH; break; - case 1: width = SCREENWIDTH / CleanXfac; break; - case 2: width = SCREENWIDTH / 2; break; - case 3: width = SCREENWIDTH / 4; break; + case 0: width = SCREENWIDTH / CleanXfac; break; + default: width = SCREENWIDTH / con_uiscale(); break; } } @@ -332,7 +330,7 @@ void DHUDMessage::Draw (int bottom, int visibility) int screen_width = SCREENWIDTH; int screen_height = SCREENHEIGHT; - if (HUDWidth == 0 && con_scaletext==1) + if (HUDWidth == 0 && con_uiscale() == 0) { clean = true; xscale = CleanXfac; @@ -341,17 +339,11 @@ void DHUDMessage::Draw (int bottom, int visibility) else { xscale = yscale = 1; - if (HUDWidth==0 && con_scaletext==2) + if (HUDWidth == 0) { - screen_width/=2; - screen_height/=2; - bottom/=2; - } - else if (HUDWidth==0 && con_scaletext==3) - { - screen_width/=4; - screen_height/=4; - bottom/=4; + screen_width /= con_uiscale(); + screen_height /= con_uiscale(); + bottom /= con_uiscale(); } } @@ -453,7 +445,7 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight) { if (hudheight == 0) { - if (con_scaletext <= 1) + if (con_uiscale() <= 1) { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_CleanNoMove, clean, @@ -461,21 +453,11 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight) DTA_RenderStyle, Style, TAG_DONE); } - else if (con_scaletext == 3) - { - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH/4, - DTA_VirtualHeight, SCREENHEIGHT/4, - DTA_AlphaF, Alpha, - DTA_RenderStyle, Style, - DTA_KeepRatio, true, - TAG_DONE); - } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH/2, - DTA_VirtualHeight, SCREENHEIGHT/2, + DTA_VirtualWidth, SCREENWIDTH / con_uiscale(), + DTA_VirtualHeight, SCREENHEIGHT / con_uiscale(), DTA_AlphaF, Alpha, DTA_RenderStyle, Style, DTA_KeepRatio, true, @@ -566,7 +548,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh float trans = float(Alpha * -(Tics - FadeOutTics) / FadeOutTics); if (hudheight == 0) { - if (con_scaletext <= 1) + if (con_uiscale() <= 1) { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_CleanNoMove, clean, @@ -574,21 +556,11 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh DTA_RenderStyle, Style, TAG_DONE); } - else if (con_scaletext == 3) - { - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH/4, - DTA_VirtualHeight, SCREENHEIGHT/4, - DTA_AlphaF, trans, - DTA_RenderStyle, Style, - DTA_KeepRatio, true, - TAG_DONE); - } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH/2, - DTA_VirtualHeight, SCREENHEIGHT/2, + DTA_VirtualWidth, SCREENWIDTH / con_uiscale(), + DTA_VirtualHeight, SCREENHEIGHT / con_uiscale(), DTA_AlphaF, trans, DTA_RenderStyle, Style, DTA_KeepRatio, true, @@ -676,7 +648,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu float trans = float(Alpha * Tics / FadeInTics); if (hudheight == 0) { - if (con_scaletext <= 1) + if (con_uiscale() <= 1) { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_CleanNoMove, clean, @@ -684,21 +656,11 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu DTA_RenderStyle, Style, TAG_DONE); } - else if (con_scaletext == 3) - { - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH/4, - DTA_VirtualHeight, SCREENHEIGHT/4, - DTA_AlphaF, trans, - DTA_RenderStyle, Style, - DTA_KeepRatio, true, - TAG_DONE); - } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH/2, - DTA_VirtualHeight, SCREENHEIGHT/2, + DTA_VirtualWidth, SCREENWIDTH / con_uiscale(), + DTA_VirtualHeight, SCREENHEIGHT / con_uiscale(), DTA_AlphaF, trans, DTA_RenderStyle, Style, DTA_KeepRatio, true, @@ -864,7 +826,7 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in { if (hudheight == 0) { - if (con_scaletext <= 1) + if (con_uiscale() <= 1) { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_CleanNoMove, clean, @@ -873,22 +835,11 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in DTA_RenderStyle, Style, TAG_DONE); } - else if (con_scaletext == 3) - { - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH/4, - DTA_VirtualHeight, SCREENHEIGHT/4, - DTA_KeepRatio, true, - DTA_TextLen, LineVisible, - DTA_AlphaF, Alpha, - DTA_RenderStyle, Style, - TAG_DONE); - } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH/2, - DTA_VirtualHeight, SCREENHEIGHT/2, + DTA_VirtualWidth, SCREENWIDTH / con_uiscale(), + DTA_VirtualHeight, SCREENHEIGHT / con_uiscale(), DTA_KeepRatio, true, DTA_TextLen, LineVisible, DTA_AlphaF, Alpha, diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 0136b4f25..42f28173c 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1013,7 +1013,15 @@ public: void ScreenSizeChanged() { Super::ScreenSizeChanged(); - V_CalcCleanFacs(script->resW, script->resH, SCREENWIDTH, SCREENHEIGHT, &script->cleanX, &script->cleanY); + if (uiscale > 0) + { + script->cleanX = uiscale; + script->cleanY = uiscale; + } + else + { + V_CalcCleanFacs(script->resW, script->resH, SCREENWIDTH, SCREENHEIGHT, &script->cleanX, &script->cleanY); + } } void Draw (EHudState state) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index cddc86ee4..26504cb7d 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -66,7 +66,7 @@ EXTERN_CVAR (Int, screenblocks) EXTERN_CVAR (Bool, am_showtime) EXTERN_CVAR (Bool, am_showtotaltime) -CVAR(Int,hud_althudscale, 2, CVAR_ARCHIVE) // Scale the hud to 640x400? +CVAR(Int,hud_althudscale, 4, CVAR_ARCHIVE) // Scale the hud to 640x400? CVAR(Bool,hud_althud, false, CVAR_ARCHIVE) // Enable/Disable the alternate HUD // These are intentionally not the same as in the automap! @@ -118,7 +118,7 @@ static int hudwidth, hudheight; // current width/height for HUD display static int statspace; DVector2 AM_GetPosition(); - +int con_uiscale(); FTextureID GetHUDIcon(PClassInventory *cls) { @@ -886,22 +886,15 @@ static void DrawCoordinates(player_t * CPlayer) } int vwidth, vheight; - switch (con_scaletext) + if (con_uiscale() == 0) { - default: - case 0: - vwidth = SCREENWIDTH; - vheight = SCREENHEIGHT; - break; - case 1: - case 2: - vwidth = SCREENWIDTH/2; - vheight = SCREENHEIGHT/2; - break; - case 3: - vwidth = SCREENWIDTH/4; - vheight = SCREENHEIGHT/4; - break; + vwidth = SCREENWIDTH / 2; + vheight = SCREENHEIGHT / 2; + } + else + { + vwidth = SCREENWIDTH / con_uiscale(); + vheight = SCREENHEIGHT / con_uiscale(); } int xpos = vwidth - SmallFont->StringWidth("X: -00000")-6; @@ -1090,7 +1083,20 @@ void DrawHUD() if (hud_althudscale && SCREENWIDTH>640) { hudwidth=SCREENWIDTH/2; - if (hud_althudscale == 3) + if (hud_althudscale == 4) + { + if (uiscale == 0) + { + hudwidth = CleanWidth; + hudheight = CleanHeight; + } + else + { + hudwidth = SCREENWIDTH / uiscale; + hudheight = SCREENHEIGHT / uiscale; + } + } + else if (hud_althudscale == 3) { hudwidth = SCREENWIDTH / 4; hudheight = SCREENHEIGHT / 4; diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index c3b1fd262..6f495581f 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -74,6 +74,8 @@ EXTERN_CVAR (Bool, am_showtotaltime) EXTERN_CVAR (Bool, noisedebug) EXTERN_CVAR (Int, con_scaletext) +int con_uiscale(); + DBaseStatusBar *StatusBar; extern int setblocks; @@ -1240,17 +1242,17 @@ void DBaseStatusBar::Draw (EHudState state) int xpos; int y; - if (con_scaletext == 0) + if (con_uiscale() == 1) { vwidth = SCREENWIDTH; vheight = SCREENHEIGHT; xpos = vwidth - 80; y = ::ST_Y - height; } - else if (con_scaletext == 3) + else if (con_uiscale() > 1) { - vwidth = SCREENWIDTH/4; - vheight = SCREENHEIGHT/4; + vwidth = SCREENWIDTH / con_uiscale(); + vheight = SCREENHEIGHT / con_uiscale(); xpos = vwidth - SmallFont->StringWidth("X: -00000")-6; y = ::ST_Y/4 - height; } @@ -1264,9 +1266,9 @@ void DBaseStatusBar::Draw (EHudState state) if (gameinfo.gametype == GAME_Strife) { - if (con_scaletext == 0) + if (con_uiscale() == 1) y -= height * 4; - else if (con_scaletext == 3) + else if (con_uiscale() > 3) y -= height; else y -= height * 2; @@ -1400,27 +1402,15 @@ void DBaseStatusBar::DrawLog () if (CPlayer->LogText.IsNotEmpty()) { // This uses the same scaling as regular HUD messages - switch (con_scaletext) + if (con_uiscale() == 0) { - default: - hudwidth = SCREENWIDTH; - hudheight = SCREENHEIGHT; - break; - - case 1: hudwidth = SCREENWIDTH / CleanXfac; hudheight = SCREENHEIGHT / CleanYfac; - break; - - case 2: - hudwidth = SCREENWIDTH / 2; - hudheight = SCREENHEIGHT / 2; - break; - - case 3: - hudwidth = SCREENWIDTH / 4; - hudheight = SCREENHEIGHT / 4; - break; + } + else + { + hudwidth = SCREENWIDTH / con_uiscale(); + hudheight = SCREENHEIGHT / con_uiscale(); } int linelen = hudwidth<640? Scale(hudwidth,9,10)-40 : 560; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 89023d4bd..dada0cd57 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -62,6 +62,14 @@ #include "colormatcher.h" #include "r_data/colormaps.h" +CUSTOM_CVAR(Int, uiscale, 2, CVAR_ARCHIVE | CVAR_NOINITCALL) +{ + if (StatusBar != NULL) + { + StatusBar->ScreenSizeChanged(); + } +} + // [RH] Stretch values to make a 320x200 image best fit the screen // without using fractional steppings int CleanXfac, CleanYfac; @@ -75,7 +83,7 @@ int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1; // FillSimplePoly uses this extern "C" short spanend[MAXHEIGHT]; -CVAR (Bool, hud_scale, false, CVAR_ARCHIVE); +CVAR (Bool, hud_scale, true, CVAR_ARCHIVE); // For routines that take RGB colors, cache the previous lookup in case there // are several repetitions with the same color. diff --git a/src/v_video.h b/src/v_video.h index 7091c518d..4f0a78675 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -522,4 +522,6 @@ inline bool Is54Aspect(int ratio) { return ratio == 4; } +EXTERN_CVAR(Int, uiscale); + #endif // __V_VIDEO_H__ diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index ed224cb57..d337f0cbf 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1807,6 +1807,7 @@ DSPLYMNU_STILLBOB = "View bob amount while not moving"; HUDMNU_TITLE = "HUD Options"; HUDMNU_ALTHUD = "Alternative HUD"; HUDMNU_MESSAGE = "Message Options"; +HUDMNU_UISCALE = "User interface scale"; HUDMNU_CROSSHAIR = "Default Crosshair"; HUDMNU_FORCECROSSHAIR = "Force default crosshair"; HUDMNU_GROWCROSSHAIR = "Grow crosshair when picking up items"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index ae8cfa0bb..f814b6709 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -755,6 +755,8 @@ OptionMenu "HUDOptions" Submenu "$HUDMNU_ALTHUD", "AltHudOptions" Submenu "$HUDMNU_MESSAGE", "MessageOptions" StaticText " " + Slider "$HUDMNU_UISCALE", "uiscale", 0.0, 8.0, 1.0, 0 + StaticText " " Option "$HUDMNU_CROSSHAIR", "crosshair", "Crosshairs" Option "$HUDMNU_FORCECROSSHAIR", "crosshairforce", "OnOff" Option "$HUDMNU_GROWCROSSHAIR", "crosshairgrow", "OnOff" @@ -789,6 +791,7 @@ OptionValue "AMCoordinates" OptionValue "AltHUDScale" { 0, "$OPTVAL_OFF" + 4, "$OPTVAL_ON" 1, "$OPTVAL_SCALETO640X400" 2, "$OPTVAL_PIXELDOUBLE" 3, "$OPTVAL_PIXELQUADRUPLE" From d2f8fc63fc5d6935fbaf89317cdf458a6bb54ea3 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 6 Sep 2016 21:35:57 +0200 Subject: [PATCH 64/97] Scale the console itself as specified by con_scaletext --- src/c_console.cpp | 109 +++++++++++++++++++++++++++++++++++++--------- src/v_video.cpp | 17 ++++++-- 2 files changed, 102 insertions(+), 24 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 026266359..bdb9fb559 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -846,9 +846,13 @@ void C_DrawConsole (bool hw2d) static int oldbottom = 0; int lines, left, offset; + int textScale = con_uiscale(); + if (textScale == 0) + textScale = CleanXfac; + left = LEFTMARGIN; - lines = (ConBottom-ConFont->GetHeight()*2)/ConFont->GetHeight(); - if (-ConFont->GetHeight() + lines*ConFont->GetHeight() > ConBottom - ConFont->GetHeight()*7/2) + lines = (ConBottom/textScale-ConFont->GetHeight()*2)/ConFont->GetHeight(); + if (-ConFont->GetHeight() + lines*ConFont->GetHeight() > ConBottom/textScale - ConFont->GetHeight()*7/2) { offset = -ConFont->GetHeight()/2; lines--; @@ -894,16 +898,26 @@ void C_DrawConsole (bool hw2d) if (ConBottom >= 12) { - screen->DrawText (ConFont, CR_ORANGE, SCREENWIDTH - 8 - - ConFont->StringWidth (GetVersionString()), - ConBottom - ConFont->GetHeight() - 4, - GetVersionString(), TAG_DONE); + if (textScale == 1) + screen->DrawText (ConFont, CR_ORANGE, SCREENWIDTH - 8 - + ConFont->StringWidth (GetVersionString()), + ConBottom / textScale - ConFont->GetHeight() - 4, + GetVersionString(), TAG_DONE); + else + screen->DrawText(ConFont, CR_ORANGE, SCREENWIDTH / textScale - 8 - + ConFont->StringWidth(GetVersionString()), + ConBottom / textScale - ConFont->GetHeight() - 4, + GetVersionString(), + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + if (TickerMax) { char tickstr[256]; - const int tickerY = ConBottom - ConFont->GetHeight() - 4; + const int tickerY = ConBottom / textScale - ConFont->GetHeight() - 4; size_t i; - int tickend = ConCols - SCREENWIDTH / 90 - 6; + int tickend = ConCols / textScale - SCREENWIDTH / textScale / 90 - 6; int tickbegin = 0; if (TickerLabel) @@ -926,11 +940,23 @@ void C_DrawConsole (bool hw2d) { tickstr[tickend+3] = 0; } - screen->DrawText (ConFont, CR_BROWN, LEFTMARGIN, tickerY, tickstr, TAG_DONE); + if (textScale == 1) + screen->DrawText (ConFont, CR_BROWN, LEFTMARGIN, tickerY, tickstr, TAG_DONE); + else + screen->DrawText (ConFont, CR_BROWN, LEFTMARGIN, tickerY, tickstr, + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); // Draw the marker i = LEFTMARGIN+5+tickbegin*8 + Scale (TickerAt, (SDWORD)(tickend - tickbegin)*8, TickerMax); - screen->DrawChar (ConFont, CR_ORANGE, (int)i, tickerY, 0x13, TAG_DONE); + if (textScale == 1) + screen->DrawChar (ConFont, CR_ORANGE, (int)i, tickerY, 0x13, TAG_DONE); + else + screen->DrawChar(ConFont, CR_ORANGE, (int)i, tickerY, 0x13, + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); TickerVisible = true; } @@ -966,18 +992,28 @@ void C_DrawConsole (bool hw2d) if (lines > 0) { // No more enqueuing because adding new text to the console won't touch the actual print data. - conbuffer->FormatText(ConFont, ConWidth); + conbuffer->FormatText(ConFont, ConWidth / textScale); unsigned int consolelines = conbuffer->GetFormattedLineCount(); FBrokenLines **blines = conbuffer->GetLines(); FBrokenLines **printline = blines + consolelines - 1 - RowAdjust; - int bottomline = ConBottom - ConFont->GetHeight()*2 - 4; + int bottomline = ConBottom / textScale - ConFont->GetHeight()*2 - 4; ConsoleDrawing = true; for(FBrokenLines **p = printline; p >= blines && lines > 0; p--, lines--) { - screen->DrawText(ConFont, CR_TAN, LEFTMARGIN, offset + lines * ConFont->GetHeight(), (*p)->Text, TAG_DONE); + if (textScale == 1) + { + screen->DrawText(ConFont, CR_TAN, LEFTMARGIN, offset + lines * ConFont->GetHeight(), (*p)->Text, TAG_DONE); + } + else + { + screen->DrawText(ConFont, CR_TAN, LEFTMARGIN, offset + lines * ConFont->GetHeight(), (*p)->Text, + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + } } ConsoleDrawing = false; @@ -992,21 +1028,52 @@ void C_DrawConsole (bool hw2d) FString command((char *)&CmdLine[2+CmdLine[259]]); int cursorpos = CmdLine[1] - CmdLine[259]; - screen->DrawChar (ConFont, CR_ORANGE, left, bottomline, '\x1c', TAG_DONE); - screen->DrawText (ConFont, CR_ORANGE, left + ConFont->GetCharWidth(0x1c), bottomline, - command, TAG_DONE); - - if (cursoron) + if (textScale == 1) { - screen->DrawChar (ConFont, CR_YELLOW, left + ConFont->GetCharWidth(0x1c) + cursorpos * ConFont->GetCharWidth(0xb), - bottomline, '\xb', TAG_DONE); + screen->DrawChar(ConFont, CR_ORANGE, left, bottomline, '\x1c', TAG_DONE); + screen->DrawText(ConFont, CR_ORANGE, left + ConFont->GetCharWidth(0x1c), bottomline, + command, TAG_DONE); + + if (cursoron) + { + screen->DrawChar(ConFont, CR_YELLOW, left + ConFont->GetCharWidth(0x1c) + cursorpos * ConFont->GetCharWidth(0xb), + bottomline, '\xb', TAG_DONE); + } + } + else + { + screen->DrawChar(ConFont, CR_ORANGE, left, bottomline, '\x1c', + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + + screen->DrawText(ConFont, CR_ORANGE, left + ConFont->GetCharWidth(0x1c), bottomline, + command, + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + + if (cursoron) + { + screen->DrawChar(ConFont, CR_YELLOW, left + ConFont->GetCharWidth(0x1c) + cursorpos * ConFont->GetCharWidth(0xb), + bottomline, '\xb', + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + } } } if (RowAdjust && ConBottom >= ConFont->GetHeight()*7/2) { // Indicate that the view has been scrolled up (10) // and if we can scroll no further (12) - screen->DrawChar (ConFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, TAG_DONE); + if (textScale == 1) + screen->DrawChar (ConFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, TAG_DONE); + else + screen->DrawChar(ConFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); } } } diff --git a/src/v_video.cpp b/src/v_video.cpp index 0ee065bbe..e1997d581 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -65,6 +65,7 @@ #include "menu/menu.h" #include "r_data/voxels.h" +int con_uiscale(); FRenderer *Renderer; @@ -857,10 +858,20 @@ void DFrameBuffer::DrawRateStuff () int chars; int rate_x; + int textScale = con_uiscale(); + if (textScale == 0) + textScale = CleanXfac; + chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2u ms (%3u fps)", howlong, LastCount); - rate_x = Width - ConFont->StringWidth(&fpsbuff[0]); - Clear (rate_x, 0, Width, ConFont->GetHeight(), GPalette.BlackIndex, 0); - DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], TAG_DONE); + rate_x = Width / textScale - ConFont->StringWidth(&fpsbuff[0]); + Clear (rate_x * textScale, 0, Width, ConFont->GetHeight() * textScale, GPalette.BlackIndex, 0); + if (textScale == 1) + DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], TAG_DONE); + else + DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); DWORD thisSec = ms/1000; if (LastSec < thisSec) From e794e59cd2798e8fbb36dce3dcad4a18b72dd3bd Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 7 Sep 2016 11:34:49 +0200 Subject: [PATCH 65/97] Add con_scale for scaling just the console --- src/c_console.cpp | 39 ++++++++++++++++++++++++------------ src/ct_chat.cpp | 18 ++++++++--------- src/g_shared/hudmessages.cpp | 38 +++++++++++++++++------------------ src/g_shared/shared_hud.cpp | 8 ++++---- src/g_shared/shared_sbar.cpp | 20 +++++++++--------- src/v_video.cpp | 4 ++-- wadsrc/static/language.enu | 2 ++ wadsrc/static/menudef.txt | 10 +++++++++ 8 files changed, 82 insertions(+), 57 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index bdb9fb559..08f850675 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -165,7 +165,20 @@ CUSTOM_CVAR (Int, con_scaletext, 1, CVAR_ARCHIVE) // Scale notify text at high if (self > 3) self = 3; } -int con_uiscale() +CUSTOM_CVAR(Int, con_scale, 0, CVAR_ARCHIVE) +{ + if (self < 0) self = 0; +} + +int active_con_scale() +{ + if (con_scale == 0) + return uiscale; + else + return con_scale; +} + +int active_con_scaletext() { switch (con_scaletext) { @@ -505,13 +518,13 @@ void C_AddNotifyString (int printlevel, const char *source) return; } - if (con_uiscale() == 0) + if (active_con_scaletext() == 0) { width = DisplayWidth / CleanXfac; } else { - width = DisplayWidth / con_uiscale(); + width = DisplayWidth / active_con_scaletext(); } if (addtype == APPENDLINE && NotifyStrings[NUMNOTIFIES-1].PrintLevel == printlevel) @@ -733,7 +746,7 @@ static void C_DrawNotifyText () canskip = true; lineadv = SmallFont->GetHeight (); - if (con_uiscale() == 0) + if (active_con_scaletext() == 0) { lineadv *= CleanYfac; } @@ -767,7 +780,7 @@ static void C_DrawNotifyText () else color = PrintColors[NotifyStrings[i].PrintLevel]; - if (con_uiscale() == 0) + if (active_con_scaletext() == 0) { if (!center) screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, @@ -778,7 +791,7 @@ static void C_DrawNotifyText () line, NotifyStrings[i].Text, DTA_CleanNoMove, true, DTA_AlphaF, alpha, TAG_DONE); } - else if (con_uiscale() == 1) + else if (active_con_scaletext() == 1) { if (!center) screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, @@ -793,16 +806,16 @@ static void C_DrawNotifyText () { if (!center) screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, - DTA_VirtualWidth, screen->GetWidth() / con_uiscale(), - DTA_VirtualHeight, screen->GetHeight() / con_uiscale(), + DTA_VirtualWidth, screen->GetWidth() / active_con_scaletext(), + DTA_VirtualHeight, screen->GetHeight() / active_con_scaletext(), DTA_KeepRatio, true, DTA_AlphaF, alpha, TAG_DONE); else - screen->DrawText (SmallFont, color, (screen->GetWidth() / con_uiscale() - - SmallFont->StringWidth (NotifyStrings[i].Text))/ con_uiscale(), + screen->DrawText (SmallFont, color, (screen->GetWidth() / active_con_scaletext() - + SmallFont->StringWidth (NotifyStrings[i].Text))/ active_con_scaletext(), line, NotifyStrings[i].Text, - DTA_VirtualWidth, screen->GetWidth() / con_uiscale(), - DTA_VirtualHeight, screen->GetHeight() / con_uiscale(), + DTA_VirtualWidth, screen->GetWidth() / active_con_scaletext(), + DTA_VirtualHeight, screen->GetHeight() / active_con_scaletext(), DTA_KeepRatio, true, DTA_AlphaF, alpha, TAG_DONE); } @@ -846,7 +859,7 @@ void C_DrawConsole (bool hw2d) static int oldbottom = 0; int lines, left, offset; - int textScale = con_uiscale(); + int textScale = active_con_scale(); if (textScale == 0) textScale = CleanXfac; diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index 7fd36d0ab..3c0994a3b 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -46,7 +46,7 @@ EXTERN_CVAR (Bool, sb_cooperative_enable) EXTERN_CVAR (Bool, sb_deathmatch_enable) EXTERN_CVAR (Bool, sb_teamdeathmatch_enable) -int con_uiscale(); +int active_con_scaletext(); // Public data @@ -226,7 +226,7 @@ void CT_Drawer (void) int i, x, scalex, y, promptwidth; y = (viewactive || gamestate != GS_LEVEL) ? -10 : -30; - if (con_uiscale() == 0) + if (active_con_scaletext() == 0) { scalex = CleanXfac; y *= CleanYfac; @@ -237,7 +237,7 @@ void CT_Drawer (void) } int screen_width, screen_height, st_y; - if (con_uiscale() == 0) + if (active_con_scaletext() == 0) { screen_width = SCREENWIDTH; screen_height = SCREENHEIGHT; @@ -245,9 +245,9 @@ void CT_Drawer (void) } else { - screen_width = SCREENWIDTH / con_uiscale(); - screen_height = SCREENHEIGHT / con_uiscale(); - st_y = ST_Y / con_uiscale(); + screen_width = SCREENWIDTH / active_con_scaletext(); + screen_height = SCREENHEIGHT / active_con_scaletext(); + st_y = ST_Y / active_con_scaletext(); } y += ((SCREENHEIGHT == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y; @@ -274,10 +274,10 @@ void CT_Drawer (void) // draw the prompt, text, and cursor ChatQueue[len] = SmallFont->GetCursor(); ChatQueue[len+1] = '\0'; - if (con_uiscale() < 2) + if (active_con_scaletext() < 2) { - screen->DrawText (SmallFont, CR_GREEN, 0, y, prompt, DTA_CleanNoMove, con_uiscale() == 0, TAG_DONE); - screen->DrawText (SmallFont, CR_GREY, promptwidth, y, (char *)(ChatQueue + i), DTA_CleanNoMove, con_uiscale() == 0, TAG_DONE); + screen->DrawText (SmallFont, CR_GREEN, 0, y, prompt, DTA_CleanNoMove, active_con_scaletext() == 0, TAG_DONE); + screen->DrawText (SmallFont, CR_GREY, promptwidth, y, (char *)(ChatQueue + i), DTA_CleanNoMove, active_con_scaletext() == 0, TAG_DONE); } else { diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 628c8a5ee..32a8d2de5 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -42,7 +42,7 @@ #include "farchive.h" EXTERN_CVAR(Int, con_scaletext) -int con_uiscale(); +int active_con_scaletext(); IMPLEMENT_POINTY_CLASS (DHUDMessage) DECLARE_POINTER(Next) @@ -261,10 +261,10 @@ void DHUDMessage::ResetText (const char *text) } else { - switch (con_uiscale()) + switch (active_con_scaletext()) { case 0: width = SCREENWIDTH / CleanXfac; break; - default: width = SCREENWIDTH / con_uiscale(); break; + default: width = SCREENWIDTH / active_con_scaletext(); break; } } @@ -330,7 +330,7 @@ void DHUDMessage::Draw (int bottom, int visibility) int screen_width = SCREENWIDTH; int screen_height = SCREENHEIGHT; - if (HUDWidth == 0 && con_uiscale() == 0) + if (HUDWidth == 0 && active_con_scaletext() == 0) { clean = true; xscale = CleanXfac; @@ -341,9 +341,9 @@ void DHUDMessage::Draw (int bottom, int visibility) xscale = yscale = 1; if (HUDWidth == 0) { - screen_width /= con_uiscale(); - screen_height /= con_uiscale(); - bottom /= con_uiscale(); + screen_width /= active_con_scaletext(); + screen_height /= active_con_scaletext(); + bottom /= active_con_scaletext(); } } @@ -445,7 +445,7 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight) { if (hudheight == 0) { - if (con_uiscale() <= 1) + if (active_con_scaletext() <= 1) { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_CleanNoMove, clean, @@ -456,8 +456,8 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight) else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH / con_uiscale(), - DTA_VirtualHeight, SCREENHEIGHT / con_uiscale(), + DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(), + DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(), DTA_AlphaF, Alpha, DTA_RenderStyle, Style, DTA_KeepRatio, true, @@ -548,7 +548,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh float trans = float(Alpha * -(Tics - FadeOutTics) / FadeOutTics); if (hudheight == 0) { - if (con_uiscale() <= 1) + if (active_con_scaletext() <= 1) { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_CleanNoMove, clean, @@ -559,8 +559,8 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH / con_uiscale(), - DTA_VirtualHeight, SCREENHEIGHT / con_uiscale(), + DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(), + DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(), DTA_AlphaF, trans, DTA_RenderStyle, Style, DTA_KeepRatio, true, @@ -648,7 +648,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu float trans = float(Alpha * Tics / FadeInTics); if (hudheight == 0) { - if (con_uiscale() <= 1) + if (active_con_scaletext() <= 1) { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_CleanNoMove, clean, @@ -659,8 +659,8 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH / con_uiscale(), - DTA_VirtualHeight, SCREENHEIGHT / con_uiscale(), + DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(), + DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(), DTA_AlphaF, trans, DTA_RenderStyle, Style, DTA_KeepRatio, true, @@ -826,7 +826,7 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in { if (hudheight == 0) { - if (con_uiscale() <= 1) + if (active_con_scaletext() <= 1) { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_CleanNoMove, clean, @@ -838,8 +838,8 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH / con_uiscale(), - DTA_VirtualHeight, SCREENHEIGHT / con_uiscale(), + DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(), + DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(), DTA_KeepRatio, true, DTA_TextLen, LineVisible, DTA_AlphaF, Alpha, diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 26504cb7d..25a88cb35 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -118,7 +118,7 @@ static int hudwidth, hudheight; // current width/height for HUD display static int statspace; DVector2 AM_GetPosition(); -int con_uiscale(); +int active_con_scaletext(); FTextureID GetHUDIcon(PClassInventory *cls) { @@ -886,15 +886,15 @@ static void DrawCoordinates(player_t * CPlayer) } int vwidth, vheight; - if (con_uiscale() == 0) + if (active_con_scaletext() == 0) { vwidth = SCREENWIDTH / 2; vheight = SCREENHEIGHT / 2; } else { - vwidth = SCREENWIDTH / con_uiscale(); - vheight = SCREENHEIGHT / con_uiscale(); + vwidth = SCREENWIDTH / active_con_scaletext(); + vheight = SCREENHEIGHT / active_con_scaletext(); } int xpos = vwidth - SmallFont->StringWidth("X: -00000")-6; diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 6f495581f..4631a99aa 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -74,7 +74,7 @@ EXTERN_CVAR (Bool, am_showtotaltime) EXTERN_CVAR (Bool, noisedebug) EXTERN_CVAR (Int, con_scaletext) -int con_uiscale(); +int active_con_scaletext(); DBaseStatusBar *StatusBar; @@ -1242,17 +1242,17 @@ void DBaseStatusBar::Draw (EHudState state) int xpos; int y; - if (con_uiscale() == 1) + if (active_con_scaletext() == 1) { vwidth = SCREENWIDTH; vheight = SCREENHEIGHT; xpos = vwidth - 80; y = ::ST_Y - height; } - else if (con_uiscale() > 1) + else if (active_con_scaletext() > 1) { - vwidth = SCREENWIDTH / con_uiscale(); - vheight = SCREENHEIGHT / con_uiscale(); + vwidth = SCREENWIDTH / active_con_scaletext(); + vheight = SCREENHEIGHT / active_con_scaletext(); xpos = vwidth - SmallFont->StringWidth("X: -00000")-6; y = ::ST_Y/4 - height; } @@ -1266,9 +1266,9 @@ void DBaseStatusBar::Draw (EHudState state) if (gameinfo.gametype == GAME_Strife) { - if (con_uiscale() == 1) + if (active_con_scaletext() == 1) y -= height * 4; - else if (con_uiscale() > 3) + else if (active_con_scaletext() > 3) y -= height; else y -= height * 2; @@ -1402,15 +1402,15 @@ void DBaseStatusBar::DrawLog () if (CPlayer->LogText.IsNotEmpty()) { // This uses the same scaling as regular HUD messages - if (con_uiscale() == 0) + if (active_con_scaletext() == 0) { hudwidth = SCREENWIDTH / CleanXfac; hudheight = SCREENHEIGHT / CleanYfac; } else { - hudwidth = SCREENWIDTH / con_uiscale(); - hudheight = SCREENHEIGHT / con_uiscale(); + hudwidth = SCREENWIDTH / active_con_scaletext(); + hudheight = SCREENHEIGHT / active_con_scaletext(); } int linelen = hudwidth<640? Scale(hudwidth,9,10)-40 : 560; diff --git a/src/v_video.cpp b/src/v_video.cpp index e1997d581..b9917a1cb 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -65,7 +65,7 @@ #include "menu/menu.h" #include "r_data/voxels.h" -int con_uiscale(); +int active_con_scale(); FRenderer *Renderer; @@ -858,7 +858,7 @@ void DFrameBuffer::DrawRateStuff () int chars; int rate_x; - int textScale = con_uiscale(); + int textScale = active_con_scale(); if (textScale == 0) textScale = CleanXfac; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index d337f0cbf..e91c9dd43 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1947,6 +1947,7 @@ MSGMNU_SHOWMESSAGES = "Show messages"; MSGMNU_SHOWOBITUARIES = "Show obituaries"; MSGMNU_SHOWSECRETS = "Show secret notifications"; MSGMNU_SCALETEXT = "Scale text in high res"; +MSGMNU_SCALECONSOLE = "Scale console"; MSGMNU_MESSAGELEVEL = "Minimum message level"; MSGMNU_CENTERMESSAGES = "Center messages"; MSGMNU_MESSAGECOLORS = "Message Colors"; @@ -2238,6 +2239,7 @@ OPTVAL_ANIMATED = "Animated"; OPTVAL_ROTATED = "Rotated"; OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colors only"; OPTVAL_DOUBLE = "Double"; +OPTVAL_TRIPLE = "Triple"; OPTVAL_QUADRUPLE = "Quadruple"; OPTVAL_ITEMPICKUP = "Item Pickup"; OPTVAL_OBITUARIES = "Obituaries"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index f814b6709..a605b5cc4 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1114,6 +1114,15 @@ OptionValue ScaleValues 3, "$OPTVAL_QUADRUPLE" } +OptionValue ConsoleScaleValues +{ + 1, "$OPTVAL_OFF" + 0, "$OPTVAL_ON" + 2, "$OPTVAL_DOUBLE" + 3, "$OPTVAL_TRIPLE" + 4, "$OPTVAL_QUADRUPLE" +} + OptionValue MessageLevels { 0.0, "$OPTVAL_ITEMPICKUP" @@ -1137,6 +1146,7 @@ OptionMenu MessageOptions Option "$MSGMNU_SHOWOBITUARIES", "show_obituaries", "OnOff" Option "$MSGMNU_SHOWSECRETS", "cl_showsecretmessage", "OnOff" Option "$MSGMNU_SCALETEXT", "con_scaletext", "ScaleValues" + Option "$MSGMNU_SCALECONSOLE", "con_scale", "ConsoleScaleValues" Option "$MSGMNU_MESSAGELEVEL", "msg", "MessageLevels" Option "$MSGMNU_DEVELOPER", "developer", "DevMessageLevels" Option "$MSGMNU_CENTERMESSAGES", "con_centernotify", "OnOff" From 303da0e071d3b6b4fac993147fe4dcdce0eb7680 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 9 Sep 2016 20:09:54 +0200 Subject: [PATCH 66/97] Fix center text alignment issue --- src/c_console.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 08f850675..086861229 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -811,8 +811,8 @@ static void C_DrawNotifyText () DTA_KeepRatio, true, DTA_AlphaF, alpha, TAG_DONE); else - screen->DrawText (SmallFont, color, (screen->GetWidth() / active_con_scaletext() - - SmallFont->StringWidth (NotifyStrings[i].Text))/ active_con_scaletext(), + screen->DrawText (SmallFont, color, (screen->GetWidth() - + SmallFont->StringWidth (NotifyStrings[i].Text) * active_con_scaletext()) / 2 / active_con_scaletext(), line, NotifyStrings[i].Text, DTA_VirtualWidth, screen->GetWidth() / active_con_scaletext(), DTA_VirtualHeight, screen->GetHeight() / active_con_scaletext(), From 02e4ba464ac5e1dc4e0a9c06af6949a1dcfba669 Mon Sep 17 00:00:00 2001 From: raa-eruanna Date: Fri, 9 Sep 2016 22:27:37 -0400 Subject: [PATCH 67/97] Fixed mirror angle issue, fixes rendering of mirrors --- src/r_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_main.cpp b/src/r_main.cpp index ce4841a2e..ecbd4cb34 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -678,7 +678,7 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) ViewPos.X = (x1 + r * dx)*2 - x; ViewPos.Y = (y1 + r * dy)*2 - y; } - ViewAngle = pds->src->Delta().Angle() - startang; + ViewAngle = pds->src->Delta().Angle() * 2 - startang; } else { From d3d8180f578924b275defd937e10cd3cb370922e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Sep 2016 13:04:36 +0200 Subject: [PATCH 68/97] Resize framebuffer in windowed mode to match the client area --- src/v_video.cpp | 42 ++++++++++++++++++++++++++++++++++++------ src/v_video.h | 4 ++++ src/win32/fb_d3d9.cpp | 18 ++++++++++++++++++ src/win32/i_input.cpp | 16 ++++++++++++---- 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index b9917a1cb..9d377b7fd 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -725,6 +725,21 @@ void DCanvas::CalcGamma (float gamma, BYTE gammalookup[256]) DSimpleCanvas::DSimpleCanvas (int width, int height) : DCanvas (width, height) { + MemBuffer = nullptr; + Resize(width, height); +} + +void DSimpleCanvas::Resize(int width, int height) +{ + Width = width; + Height = height; + + if (MemBuffer != NULL) + { + delete[] MemBuffer; + MemBuffer = NULL; + } + // Making the pitch a power of 2 is very bad for performance // Try to maximize the number of cache lines that can be filled // for each column drawing operation by making the pitch slightly @@ -761,7 +776,7 @@ DSimpleCanvas::DSimpleCanvas (int width, int height) } } MemBuffer = new BYTE[Pitch * height]; - memset (MemBuffer, 0, Pitch * height); + memset(MemBuffer, 0, Pitch * height); } //========================================================================== @@ -1259,7 +1274,6 @@ CCMD(clean) bool V_DoModeSetup (int width, int height, int bits) { DFrameBuffer *buff = I_SetMode (width, height, screen); - int cx1, cx2; if (buff == NULL) { @@ -1274,6 +1288,17 @@ bool V_DoModeSetup (int width, int height, int bits) // if D3DFB is being used for the display. FFont::StaticPreloadFonts(); + DisplayBits = bits; + V_UpdateModeSize(width, height); + + M_RefreshModesList (); + + return true; +} + +void V_UpdateModeSize (int width, int height) +{ + int cx1, cx2; V_CalcCleanFacs(320, 200, width, height, &CleanXfac, &CleanYfac, &cx1, &cx2); CleanWidth = width / CleanXfac; @@ -1314,14 +1339,19 @@ bool V_DoModeSetup (int width, int height, int bits) DisplayWidth = width; DisplayHeight = height; - DisplayBits = bits; R_OldBlend = ~0; Renderer->OnModeSet(); - - M_RefreshModesList (); +} - return true; +void V_OutputResized (int width, int height) +{ + V_UpdateModeSize(width, height); + setsizeneeded = true; + if (StatusBar != NULL) + { + StatusBar->ScreenSizeChanged(); + } } void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *_cx1, int *_cx2) diff --git a/src/v_video.h b/src/v_video.h index 4f0a78675..11a10c8d8 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -47,6 +47,8 @@ extern int CleanWidth_1, CleanHeight_1, CleanXfac_1, CleanYfac_1; extern int DisplayWidth, DisplayHeight, DisplayBits; bool V_DoModeSetup (int width, int height, int bits); +void V_UpdateModeSize (int width, int height); +void V_OutputResized (int width, int height); void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *cx1=NULL, int *cx2=NULL); class FTexture; @@ -300,6 +302,8 @@ public: void Unlock (); protected: + void Resize(int width, int height); + BYTE *MemBuffer; DSimpleCanvas() {} diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index efdced151..06bfa0569 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1220,6 +1220,24 @@ void D3DFB::Flip() CurrRenderTexture ^= RenderTextureToggle; TempRenderTexture = RenderTexture[CurrRenderTexture]; } + + if (Windowed) + { + RECT box; + GetClientRect(Window, &box); + if (box.right > 0 && box.right > 0 && (Width != box.right || Height != box.bottom)) + { + Resize(box.right, box.bottom); + + TrueHeight = Height; + PixelDoubling = 0; + LBOffsetI = 0; + LBOffset = 0.0f; + Reset(); + + V_OutputResized(Width, Height); + } + } } //========================================================================== diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index 2b0659c83..1e6390392 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -537,10 +537,18 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if (screen && !VidResizing) { LPMINMAXINFO mmi = (LPMINMAXINFO)lParam; - RECT rect = { 0, 0, screen->GetWidth(), screen->GetHeight() }; - AdjustWindowRectEx(&rect, WS_VISIBLE|WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW); - mmi->ptMinTrackSize.x = rect.right - rect.left; - mmi->ptMinTrackSize.y = rect.bottom - rect.top; + if (screen->IsFullscreen()) + { + RECT rect = { 0, 0, screen->GetWidth(), screen->GetHeight() }; + AdjustWindowRectEx(&rect, WS_VISIBLE | WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW); + mmi->ptMinTrackSize.x = rect.right - rect.left; + mmi->ptMinTrackSize.y = rect.bottom - rect.top; + } + else + { + mmi->ptMinTrackSize.x = 320; + mmi->ptMinTrackSize.y = 200; + } return 0; } break; From b003c47e3e02bed94b76757a512b195b1d7d70c8 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Sep 2016 13:37:05 +0200 Subject: [PATCH 69/97] Improve CheckRatio to always return the closest ratio --- src/v_video.cpp | 77 +++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 47 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index 9d377b7fd..78995f300 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1610,13 +1610,36 @@ CUSTOM_CVAR (Int, vid_aspect, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) // 2: 16:10 // 3: 17:10 // 4: 5:4 -// 5: 17:10 (redundant) +// 5: 17:10 (redundant, never returned) // 6: 21:9 int CheckRatio (int width, int height, int *trueratio) { - int fakeratio = -1; - int ratio; + float aspect = width / (float)height; + static std::pair ratioTypes[] = + { + { 21 / 9.0f , 6 }, + { 16 / 9.0f , 1 }, + { 17 / 10.0f , 3 }, + { 16 / 10.0f , 2 }, + { 4 / 3.0f , 0 }, + { 5 / 4.0f , 4 }, + { 0.0f, 0 } + }; + + int ratio = ratioTypes[0].second; + float distance = abs(ratioTypes[0].first - aspect); + for (int i = 1; ratioTypes[i].first != 0.0f; i++) + { + float d = abs(ratioTypes[i].first - aspect); + if (d < distance) + { + ratio = ratioTypes[i].second; + distance = d; + } + } + + int fakeratio = ratio; if ((vid_aspect >= 1) && (vid_aspect <= 6)) { // [SP] User wants to force aspect ratio; let them. @@ -1628,7 +1651,7 @@ int CheckRatio (int width, int height, int *trueratio) else if (fakeratio == 5) { fakeratio = 3; - } + } } if (vid_nowidescreen) { @@ -1638,53 +1661,13 @@ int CheckRatio (int width, int height, int *trueratio) } else { - fakeratio = (height * 5/4 == width) ? 4 : 0; + fakeratio = (height * 5 / 4 == width) ? 4 : 0; } } - // If the size is approximately 16:9, consider it so. - if (abs (height * 16/9 - width) < 10) - { - ratio = 1; - } - // Consider 17:10 as well. - else if (abs (height * 17/10 - width) < 10) - { - ratio = 3; - } - // 16:10 has more variance in the pixel dimensions. Grr. - else if (abs (height * 16/10 - width) < 60) - { - // 320x200 and 640x400 are always 4:3, not 16:10 - if ((width == 320 && height == 200) || (width == 640 && height == 400)) - { - ratio = 0; - } - else - { - ratio = 2; - } - } - // Unless vid_tft is set, 1280x1024 is 4:3, not 5:4. - else if (height * 5/4 == width && vid_tft) - { - ratio = 4; - } - // test for 21:9 (actually 64:27, 21:9 is a semi-accurate ratio used in marketing) - else if (abs (height * 64/27 - width) < 30) - { - ratio = 6; - } - // Assume anything else is 4:3. (Which is probably wrong these days...) - else - { - ratio = 0; - } - if (trueratio != NULL) - { + if (trueratio) *trueratio = ratio; - } - return (fakeratio >= 0) ? fakeratio : ratio; + return fakeratio; } // First column: Base width From 5720634045b0812bc838eb4671a4039917582a94 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Sep 2016 13:59:01 +0200 Subject: [PATCH 70/97] Add ActiveRatio to be used where CheckRatio is used today --- src/v_video.cpp | 81 ++++++++++++++++++++++++++++++++++--------------- src/v_video.h | 2 ++ 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index 78995f300..dcc5789ee 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1603,6 +1603,59 @@ CUSTOM_CVAR (Int, vid_aspect, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) } } +// Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none. +int ActiveFakeRatio(int width, int height) +{ + int fakeratio = -1; + if ((vid_aspect >= 1) && (vid_aspect <= 6)) + { + // [SP] User wants to force aspect ratio; let them. + fakeratio = int(vid_aspect); + if (fakeratio == 3) + { + fakeratio = 0; + } + else if (fakeratio == 5) + { + fakeratio = 3; + } + } + if (vid_nowidescreen) + { + if (!vid_tft) + { + fakeratio = 0; + } + else + { + fakeratio = (height * 5 / 4 == width) ? 4 : 0; + } + } + return fakeratio; +} + +// Active screen ratio based on cvars and size +float ActiveRatio(int width, int height, float *trueratio) +{ + static float forcedRatioTypes[] = + { + 4 / 3.0f, + 16 / 9.0f, + 16 / 10.0f, + 17 / 10.0f, + 5 / 4.0f, + 17 / 10.0f, + 21 / 9.0f + }; + + float ratio = width / (float)height; + int fakeratio = ActiveFakeRatio(width, height); + + if (trueratio) + *trueratio = ratio; + return (fakeratio != -1) ? forcedRatioTypes[fakeratio] : ratio; +} + // Tries to guess the physical dimensions of the screen based on the // screen's pixel dimensions. Can return: // 0: 4:3 @@ -1639,31 +1692,9 @@ int CheckRatio (int width, int height, int *trueratio) } } - int fakeratio = ratio; - if ((vid_aspect >= 1) && (vid_aspect <= 6)) - { - // [SP] User wants to force aspect ratio; let them. - fakeratio = int(vid_aspect); - if (fakeratio == 3) - { - fakeratio = 0; - } - else if (fakeratio == 5) - { - fakeratio = 3; - } - } - if (vid_nowidescreen) - { - if (!vid_tft) - { - fakeratio = 0; - } - else - { - fakeratio = (height * 5 / 4 == width) ? 4 : 0; - } - } + int fakeratio = ActiveFakeRatio(width, height); + if (fakeratio == -1) + fakeratio = ratio; if (trueratio) *trueratio = ratio; diff --git a/src/v_video.h b/src/v_video.h index 11a10c8d8..6b46fa278 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -516,6 +516,8 @@ extern "C" void ASM_PatchPitch (void); int CheckRatio (int width, int height, int *trueratio=NULL); static inline int CheckRatio (double width, double height) { return CheckRatio(int(width), int(height)); } +float ActiveRatio (int width, int height, float *trueratio = NULL); +static inline double ActiveRatio (double width, double height) { return ActiveRatio(int(width), int(height)); } extern const int BaseRatioSizes[7][4]; inline bool IsRatioWidescreen(int ratio) { From 6d4e4dad25ffa3978f5bf54d0fc60dd59b29d119 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Sep 2016 14:37:10 +0200 Subject: [PATCH 71/97] BaseRatioSizes replacement functions --- src/v_video.cpp | 20 ++++++++++++++++++++ src/v_video.h | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/src/v_video.cpp b/src/v_video.cpp index dcc5789ee..acd34f37f 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1721,6 +1721,26 @@ const int BaseRatioSizes[7][4] = { 1707, 338, 0, 48*9/16 } // 21:9 568.8889, 337.5, multiplied by three }; +int AspectBaseWidth(float aspect) +{ + return (int)round(240.0f * aspect * 3.0f); +} + +int AspectBaseHeight(float aspect) +{ + return (int)round(200.0f * (320.0f / (240.0f * aspect)) * 3.0f); +} + +int AspectPspriteOffset(float aspect) +{ + return aspect < 1.3f ? (int)(6.5*FRACUNIT) : 0; +} + +int AspectMultiplier(float aspect) +{ + return (int)round(320.0f / (240.0f * aspect) * 48.0f); +} + void IVideo::DumpAdapters () { Printf("Multi-monitor support unavailable.\n"); diff --git a/src/v_video.h b/src/v_video.h index 6b46fa278..2dc3bbddc 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -518,6 +518,11 @@ int CheckRatio (int width, int height, int *trueratio=NULL); static inline int CheckRatio (double width, double height) { return CheckRatio(int(width), int(height)); } float ActiveRatio (int width, int height, float *trueratio = NULL); static inline double ActiveRatio (double width, double height) { return ActiveRatio(int(width), int(height)); } + +int AspectBaseWidth(float aspect); +int AspectBaseHeight(float aspect); +int AspectPspriteOffset(float aspect); +int AspectMultiplier(float aspect); extern const int BaseRatioSizes[7][4]; inline bool IsRatioWidescreen(int ratio) { From 5b438d220f918e4d5b604e970f0f45f96963e8d1 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Sep 2016 15:51:50 +0200 Subject: [PATCH 72/97] Switch from ratio enum to float --- src/g_shared/shared_hud.cpp | 6 +++--- src/g_shared/shared_sbar.cpp | 17 +++++++++-------- src/r_main.cpp | 16 ++++++++-------- src/r_renderer.h | 2 +- src/r_swrenderer.cpp | 4 ++-- src/r_swrenderer.h | 2 +- src/r_things.cpp | 2 +- src/r_utility.cpp | 11 +++++------ src/r_utility.h | 2 +- src/v_draw.cpp | 34 +++++++++++++++++----------------- src/v_video.cpp | 30 +++++------------------------- src/v_video.h | 11 ++--------- 12 files changed, 55 insertions(+), 82 deletions(-) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 25a88cb35..e40233def 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -1108,13 +1108,13 @@ void DrawHUD() } else { - if (WidescreenRatio == 4) + if (CheckRatio(SCREENWIDTH, SCREENHEIGHT) == 4) { - hudheight = hudwidth * 30 / BaseRatioSizes[WidescreenRatio][3]; // BaseRatioSizes is inverted for this mode + hudheight = hudwidth * 30 / AspectMultiplier(WidescreenRatio); // BaseRatioSizes is inverted for this mode } else { - hudheight = hudwidth * 30 / (48*48/BaseRatioSizes[WidescreenRatio][3]); + hudheight = hudwidth * 30 / (48*48/AspectMultiplier(WidescreenRatio)); } } } diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 4631a99aa..3c41d18ca 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -299,14 +299,15 @@ void DBaseStatusBar::SetScaled (bool scale, bool force) { ST_X = 0; ST_Y = VirticalResolution - RelTop; - if (CheckRatio(SCREENWIDTH, SCREENHEIGHT) != 4) + float aspect = ActiveRatio(SCREENWIDTH, SCREENHEIGHT); + if (aspect >= 1.3f) { // Normal resolution ::ST_Y = Scale (ST_Y, SCREENHEIGHT, VirticalResolution); } else { // 5:4 resolution - ::ST_Y = Scale(ST_Y - VirticalResolution/2, SCREENHEIGHT*3, Scale(VirticalResolution, BaseRatioSizes[4][1], 200)) + SCREENHEIGHT/2 - + (SCREENHEIGHT - SCREENHEIGHT * BaseRatioSizes[4][3] / 48) / 2; + ::ST_Y = Scale(ST_Y - VirticalResolution/2, SCREENHEIGHT*3, Scale(VirticalResolution, AspectBaseHeight(aspect), 200)) + SCREENHEIGHT/2 + + (SCREENHEIGHT - SCREENHEIGHT * AspectMultiplier(aspect) / 48) / 2; } Displacement = 0; } @@ -1035,10 +1036,10 @@ void DBaseStatusBar::DrSmallNumberOuter (int val, int x, int y, bool center) con void DBaseStatusBar::RefreshBackground () const { - int x, x2, y, ratio; + int x, x2, y; - ratio = CheckRatio (SCREENWIDTH, SCREENHEIGHT); - x = (!IsRatioWidescreen(ratio) || !Scaled) ? ST_X : SCREENWIDTH*(48-BaseRatioSizes[ratio][3])/(48*2); + float ratio = ActiveRatio (SCREENWIDTH, SCREENHEIGHT); + x = (ratio < 1.5f || !Scaled) ? ST_X : SCREENWIDTH*(48-AspectMultiplier(ratio))/(48*2); y = x == ST_X && x > 0 ? ST_Y : ::ST_Y; if(!CompleteBorder) @@ -1058,8 +1059,8 @@ void DBaseStatusBar::RefreshBackground () const { if(!CompleteBorder) { - x2 = !IsRatioWidescreen(ratio) || !Scaled ? ST_X+HorizontalResolution : - SCREENWIDTH - (SCREENWIDTH*(48-BaseRatioSizes[ratio][3])+48*2-1)/(48*2); + x2 = ratio < 1.5f || !Scaled ? ST_X+HorizontalResolution : + SCREENWIDTH - (SCREENWIDTH*(48-AspectMultiplier(ratio))+48*2-1)/(48*2); } else { diff --git a/src/r_main.cpp b/src/r_main.cpp index ecbd4cb34..d84698b7c 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -232,7 +232,7 @@ void R_SetVisibility(double vis) else r_WallVisibility = r_BaseVisibility; - r_WallVisibility = (InvZtoScale * SCREENWIDTH*BaseRatioSizes[WidescreenRatio][1] / + r_WallVisibility = (InvZtoScale * SCREENWIDTH*AspectBaseHeight(WidescreenRatio) / (viewwidth*SCREENHEIGHT*3)) * (r_WallVisibility * FocalTangent); // Prevent overflow on floors/ceilings. Note that the calculation of @@ -295,7 +295,7 @@ CCMD (r_visibility) // //========================================================================== -void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio) +void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio) { int virtheight, virtwidth, virtwidth2, virtheight2; @@ -318,22 +318,22 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, virtwidth = virtwidth2 = fullWidth; virtheight = virtheight2 = fullHeight; - if (Is54Aspect(trueratio)) + if (trueratio < 1.3f) { - virtheight2 = virtheight2 * BaseRatioSizes[trueratio][3] / 48; + virtheight2 = virtheight2 * AspectMultiplier(trueratio) / 48; } else { - virtwidth2 = virtwidth2 * BaseRatioSizes[trueratio][3] / 48; + virtwidth2 = virtwidth2 * AspectMultiplier(trueratio) / 48; } - if (Is54Aspect(WidescreenRatio)) + if (WidescreenRatio < 1.3f) { - virtheight = virtheight * BaseRatioSizes[WidescreenRatio][3] / 48; + virtheight = virtheight * AspectMultiplier(WidescreenRatio) / 48; } else { - virtwidth = virtwidth * BaseRatioSizes[WidescreenRatio][3] / 48; + virtwidth = virtwidth * AspectMultiplier(WidescreenRatio) / 48; } BaseYaspectMul = 320.0 * virtheight2 / (r_Yaspect * virtwidth2); diff --git a/src/r_renderer.h b/src/r_renderer.h index 6c65fc12f..a39520b49 100644 --- a/src/r_renderer.h +++ b/src/r_renderer.h @@ -55,7 +55,7 @@ struct FRenderer virtual void ErrorCleanup () {} virtual void ClearBuffer(int color) = 0; virtual void Init() = 0; - virtual void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio) {} + virtual void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio) {} virtual void SetupFrame(player_t *player) {} virtual void CopyStackedViewParameters() {} virtual void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov) = 0; diff --git a/src/r_swrenderer.cpp b/src/r_swrenderer.cpp index 07edf25e9..4d1fd0371 100644 --- a/src/r_swrenderer.cpp +++ b/src/r_swrenderer.cpp @@ -45,7 +45,7 @@ class FArchive; -void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio); +void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio); void R_SetupColormap(player_t *); void R_SetupFreelook(); void R_InitRenderer(); @@ -275,7 +275,7 @@ void FSoftwareRenderer::ClearBuffer(int color) // //=========================================================================== -void FSoftwareRenderer::SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio) +void FSoftwareRenderer::SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio) { R_SWRSetWindow(windowSize, fullWidth, fullHeight, stHeight, trueratio); } diff --git a/src/r_swrenderer.h b/src/r_swrenderer.h index 3e5fed9bc..2856d9586 100644 --- a/src/r_swrenderer.h +++ b/src/r_swrenderer.h @@ -30,7 +30,7 @@ struct FSoftwareRenderer : public FRenderer void ErrorCleanup (); void ClearBuffer(int color); void Init(); - void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio); + void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio); void SetupFrame(player_t *player); void CopyStackedViewParameters(); void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov); diff --git a/src/r_things.cpp b/src/r_things.cpp index 28b52129b..a62525d08 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1393,7 +1393,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double } if (pspr->GetID() < PSP_TARGETCENTER) { // Move the weapon down for 1280x1024. - vis->texturemid -= BaseRatioSizes[WidescreenRatio][2]; + vis->texturemid -= AspectPspriteOffset(WidescreenRatio); } vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth : x2; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 00ac91c97..8e4284b7e 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -138,7 +138,7 @@ angle_t LocalViewAngle; int LocalViewPitch; bool LocalKeyboardTurner; -int WidescreenRatio; +float WidescreenRatio; int setblocks; int extralight; bool setsizeneeded; @@ -200,7 +200,7 @@ void R_SetViewSize (int blocks) void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) { - int trueratio; + float trueratio; if (windowSize >= 11) { @@ -220,8 +220,7 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) freelookviewheight = ((setblocks*fullHeight)/10)&~7; } - // If the screen is approximately 16:9 or 16:10, consider it widescreen. - WidescreenRatio = CheckRatio (fullWidth, fullHeight, &trueratio); + WidescreenRatio = ActiveRatio (fullWidth, fullHeight, &trueratio); DrawFSHUD = (windowSize == 11); @@ -230,13 +229,13 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) centery = viewheight/2; centerx = viewwidth/2; - if (Is54Aspect(WidescreenRatio)) + if (WidescreenRatio < 1.3f) { centerxwide = centerx; } else { - centerxwide = centerx * BaseRatioSizes[WidescreenRatio][3] / 48; + centerxwide = centerx * AspectMultiplier(WidescreenRatio) / 48; } diff --git a/src/r_utility.h b/src/r_utility.h index 8cabfa600..e9fd436e5 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -33,7 +33,7 @@ extern int validcount; extern angle_t LocalViewAngle; // [RH] Added to consoleplayer's angle extern int LocalViewPitch; // [RH] Used directly instead of consoleplayer's pitch extern bool LocalKeyboardTurner; // [RH] The local player used the keyboard to turn, so interpolate -extern int WidescreenRatio; +extern float WidescreenRatio; extern double r_TicFracF; extern DWORD r_FrameTime; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index dada0cd57..a33fd618b 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -863,37 +863,37 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h, double vwidth, double vheight, bool vbottom, bool handleaspect) const { - int myratio = handleaspect ? CheckRatio (Width, Height) : 0; + float myratio = handleaspect ? ActiveRatio (Width, Height) : (4.0f / 3.0f); // if 21:9 AR, map to 16:9 for all callers. // this allows for black bars and stops the stretching of fullscreen images - if (myratio == 6) { - myratio = 2; + if (myratio > 1.7f) { + myratio = 16.0f / 9.0f; } double right = x + w; double bottom = y + h; - if (myratio != 0 && myratio != 4) + if (myratio > 1.4f) { // The target surface is either 16:9 or 16:10, so expand the // specified virtual size to avoid undesired stretching of the // image. Does not handle non-4:3 virtual sizes. I'll worry about // those if somebody expresses a desire to use them. - x = (x - vwidth * 0.5) * Width * 960 / (vwidth * BaseRatioSizes[myratio][0]) + Width * 0.5; - w = (right - vwidth * 0.5) * Width * 960 / (vwidth * BaseRatioSizes[myratio][0]) + Width * 0.5 - x; + x = (x - vwidth * 0.5) * Width * 960 / (vwidth * AspectBaseWidth(myratio)) + Width * 0.5; + w = (right - vwidth * 0.5) * Width * 960 / (vwidth * AspectBaseWidth(myratio)) + Width * 0.5 - x; } else { x = x * Width / vwidth; w = right * Width / vwidth - x; } - if (myratio == 4) + if (myratio < 1.3f) { // The target surface is 5:4 - y = (y - vheight * 0.5) * Height * 600 / (vheight * BaseRatioSizes[myratio][1]) + Height * 0.5; - h = (bottom - vheight * 0.5) * Height * 600 / (vheight * BaseRatioSizes[myratio][1]) + Height * 0.5 - y; + y = (y - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5; + h = (bottom - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5 - y; if (vbottom) { - y += (Height - Height * BaseRatioSizes[myratio][3] / 48.0) * 0.5; + y += (Height - Height * AspectMultiplier(myratio) / 48.0) * 0.5; } } else @@ -937,30 +937,30 @@ void DCanvas::VirtualToRealCoordsInt(int &x, int &y, int &w, int &h, void DCanvas::FillBorder (FTexture *img) { - int myratio = CheckRatio (Width, Height); + float myratio = ActiveRatio (Width, Height); // if 21:9 AR, fill borders akin to 16:9, since all fullscreen // images are being drawn to that scale. - if (myratio == 6) { - myratio = 2; + if (myratio > 1.7f) { + myratio = 16 / 9.0f; } - if (myratio == 0) + if (myratio >= 1.3f && myratio <= 1.4f) { // This is a 4:3 display, so no border to show return; } int bordtop, bordbottom, bordleft, bordright, bord; - if (Is54Aspect(myratio)) + if (myratio < 1.3f) { // Screen is taller than it is wide bordleft = bordright = 0; - bord = Height - Height * BaseRatioSizes[myratio][3] / 48; + bord = Height - Height * AspectMultiplier(myratio) / 48; bordtop = bord / 2; bordbottom = bord - bordtop; } else { // Screen is wider than it is tall bordtop = bordbottom = 0; - bord = Width - Width * BaseRatioSizes[myratio][3] / 48; + bord = Width - Width * AspectMultiplier(myratio) / 48; bordleft = bord / 2; bordright = bord - bordleft; } diff --git a/src/v_video.cpp b/src/v_video.cpp index acd34f37f..43458dc63 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1356,20 +1356,20 @@ void V_OutputResized (int width, int height) void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *_cx1, int *_cx2) { - int ratio; + float ratio; int cwidth; int cheight; int cx1, cy1, cx2, cy2; - ratio = CheckRatio(realwidth, realheight); - if (Is54Aspect(ratio)) + ratio = ActiveRatio(realwidth, realheight); + if (ratio < 1.3f) { cwidth = realwidth; - cheight = realheight * BaseRatioSizes[ratio][3] / 48; + cheight = realheight * AspectMultiplier(ratio) / 48; } else { - cwidth = realwidth * BaseRatioSizes[ratio][3] / 48; + cwidth = realwidth * AspectMultiplier(ratio) / 48; cheight = realheight; } // Use whichever pair of cwidth/cheight or width/height that produces less difference @@ -1701,26 +1701,6 @@ int CheckRatio (int width, int height, int *trueratio) return fakeratio; } -// First column: Base width -// Second column: Base height (used for wall visibility multiplier) -// Third column: Psprite offset (needed for "tallscreen" modes) -// Fourth column: Width or height multiplier - -// For widescreen aspect ratio x:y ... -// base_width = 240 * x / y -// multiplier = 320 / base_width -// base_height = 200 * multiplier -const int BaseRatioSizes[7][4] = -{ - { 960, 600, 0, 48 }, // 4:3 320, 200, multiplied by three - { 1280, 450, 0, 48*3/4 }, // 16:9 426.6667, 150, multiplied by three - { 1152, 500, 0, 48*5/6 }, // 16:10 386, 166.6667, multiplied by three - { 1224, 471, 0, 48*40/51 }, // 17:10 408, 156.8627, multiplied by three - { 960, 640, (int)(6.5*FRACUNIT), 48*15/16 }, // 5:4 320, 213.3333, multiplied by three - { 1224, 471, 0, 48*40/51 }, // 17:10 408, 156.8627, multiplied by three (REDUNDANT) - { 1707, 338, 0, 48*9/16 } // 21:9 568.8889, 337.5, multiplied by three -}; - int AspectBaseWidth(float aspect) { return (int)round(240.0f * aspect * 3.0f); diff --git a/src/v_video.h b/src/v_video.h index 2dc3bbddc..8d785e43f 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -516,6 +516,8 @@ extern "C" void ASM_PatchPitch (void); int CheckRatio (int width, int height, int *trueratio=NULL); static inline int CheckRatio (double width, double height) { return CheckRatio(int(width), int(height)); } +inline bool IsRatioWidescreen(int ratio) { return (ratio & 3) != 0; } + float ActiveRatio (int width, int height, float *trueratio = NULL); static inline double ActiveRatio (double width, double height) { return ActiveRatio(int(width), int(height)); } @@ -523,15 +525,6 @@ int AspectBaseWidth(float aspect); int AspectBaseHeight(float aspect); int AspectPspriteOffset(float aspect); int AspectMultiplier(float aspect); -extern const int BaseRatioSizes[7][4]; - -inline bool IsRatioWidescreen(int ratio) { - return (ratio & 3)!=0; -} - -inline bool Is54Aspect(int ratio) { - return ratio == 4; -} EXTERN_CVAR(Int, uiscale); From 4e58e6626cf0372a3fbca5649a66aa7e2441554c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Sep 2016 16:05:42 +0200 Subject: [PATCH 73/97] Fix buffer overrun in CommandAspectRatio for 21:9 aspect ratio --- src/g_shared/sbarinfo_commands.cpp | 33 +++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index a9fac2ee1..47785076e 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1914,7 +1914,7 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl { SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); - SetTruth(ratioMap[CheckRatio(screen->GetWidth(), screen->GetHeight())] == ratio, block, statusBar); + SetTruth(ratioMap[FindRatio()] == ratio, block, statusBar); } protected: enum Ratio @@ -1931,6 +1931,37 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl static Ratio ratioMap[5]; Ratio ratio; + + private: + int FindRatio() + { + float aspect = ActiveRatio(screen->GetWidth(), screen->GetHeight()); + + static std::pair ratioTypes[] = + { + { 21 / 9.0f , ASPECTRATIO_16_9 }, + { 16 / 9.0f , ASPECTRATIO_16_9 }, + { 17 / 10.0f , ASPECTRATIO_17_10 }, + { 16 / 10.0f , ASPECTRATIO_16_10 }, + { 4 / 3.0f , ASPECTRATIO_4_3 }, + { 5 / 4.0f , ASPECTRATIO_5_4 }, + { 0.0f, 0 } + }; + + int ratio = ratioTypes[0].second; + float distance = abs(ratioTypes[0].first - aspect); + for (int i = 1; ratioTypes[i].first != 0.0f; i++) + { + float d = abs(ratioTypes[i].first - aspect); + if (d < distance) + { + ratio = ratioTypes[i].second; + distance = d; + } + } + + return ratio; + } }; CommandAspectRatio::Ratio CommandAspectRatio::ratioMap[5] = {ASPECTRATIO_4_3,ASPECTRATIO_16_9,ASPECTRATIO_16_10,ASPECTRATIO_16_10,ASPECTRATIO_5_4}; From 01b1efe9eec9877a409d14f749b9934a10224a58 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Sep 2016 18:44:04 +0200 Subject: [PATCH 74/97] Switch from abs to fabs --- src/g_shared/sbarinfo_commands.cpp | 4 ++-- src/v_video.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 47785076e..b7827f6bd 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1949,10 +1949,10 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl }; int ratio = ratioTypes[0].second; - float distance = abs(ratioTypes[0].first - aspect); + float distance = fabs(ratioTypes[0].first - aspect); for (int i = 1; ratioTypes[i].first != 0.0f; i++) { - float d = abs(ratioTypes[i].first - aspect); + float d = fabs(ratioTypes[i].first - aspect); if (d < distance) { ratio = ratioTypes[i].second; diff --git a/src/v_video.cpp b/src/v_video.cpp index 43458dc63..20e1f526c 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1681,10 +1681,10 @@ int CheckRatio (int width, int height, int *trueratio) }; int ratio = ratioTypes[0].second; - float distance = abs(ratioTypes[0].first - aspect); + float distance = fabs(ratioTypes[0].first - aspect); for (int i = 1; ratioTypes[i].first != 0.0f; i++) { - float d = abs(ratioTypes[i].first - aspect); + float d = fabs(ratioTypes[i].first - aspect); if (d < distance) { ratio = ratioTypes[i].second; From a2a1d2a36d0b8e7c921f5310ca478f16ccf9034c Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 6 Sep 2016 11:55:29 +0300 Subject: [PATCH 75/97] Fixed significant distortion of sound effects with FMOD Studio API --- src/sound/fmodsound.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 2db5a98a1..81bbfb8c1 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -2758,6 +2758,16 @@ std::pair FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int l exinfo.defaultfrequency = frequency; switch (bits) { +#if FMOD_STUDIO + case -8: + // Need to convert sample data from signed to unsigned. + for (int i = 0; i < length; i++) + { + sfxdata[i] ^= 0x80; + } + + case 8: +#else // !FMOD_STUDIO case 8: // Need to convert sample data from unsigned to signed. for (int i = 0; i < length; ++i) @@ -2766,6 +2776,7 @@ std::pair FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int l } case -8: +#endif // FMOD_STUDIO exinfo.format = FMOD_SOUND_FORMAT_PCM8; numsamples = length; break; From 764705a8e065889c2b896076642091b21e3ce46b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 6 Sep 2016 11:34:15 +0300 Subject: [PATCH 76/97] Fixed 'Could not set resampler method. Defaults will be used. (Error 31)' message with FMOD Studio API --- src/sound/fmodsound.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 81bbfb8c1..e45385210 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -971,6 +971,7 @@ bool FMODSoundRenderer::Init() #if FMOD_STUDIO FMOD_ADVANCEDSETTINGS advSettings = {}; + advSettings.cbSize = sizeof advSettings; advSettings.resamplerMethod = resampler; result = Sys->setAdvancedSettings(&advSettings); if (result != FMOD_OK) From c88eec3d7361f2fd83a445cfcf08c18effe2a53d Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 6 Sep 2016 10:23:12 +0300 Subject: [PATCH 77/97] Fixed 'unreferenced local variable' warnings when building with FMOD Studio API --- src/sound/fmodsound.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index e45385210..c130b7e6a 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1371,11 +1371,8 @@ void FMODSoundRenderer::PrintStatus() { FMOD_OUTPUTTYPE output; FMOD_SPEAKERMODE speakermode; - FMOD_SOUND_FORMAT format; - FMOD_DSP_RESAMPLER resampler; int driver; int samplerate; - int numoutputchannels; unsigned int bufferlength; int numbuffers; @@ -1414,6 +1411,9 @@ void FMODSoundRenderer::PrintStatus() #endif } #if !FMOD_STUDIO + FMOD_SOUND_FORMAT format; + FMOD_DSP_RESAMPLER resampler; + int numoutputchannels; if (FMOD_OK == Sys->getSoftwareFormat(&samplerate, &format, &numoutputchannels, NULL, &resampler, NULL)) { Printf (TEXTCOLOR_LIGHTBLUE "Software mixer sample rate: " TEXTCOLOR_GREEN "%d\n", samplerate); From 7e61a1ce2b8108375e7089f26548e70ce4c7cc0b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 6 Sep 2016 12:35:22 +0300 Subject: [PATCH 78/97] Added simple detection for FMOD Studio API in CMake --- src/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 190a9560a..025d651c3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -272,6 +272,10 @@ if( NOT NO_FMOD ) if( FMOD_INCLUDE_DIR ) message( STATUS "FMOD include files found at ${FMOD_INCLUDE_DIR}" ) include_directories( "${FMOD_INCLUDE_DIR}" ) + + if( EXISTS "${FMOD_INCLUDE_DIR}/fmod_common.h" ) + set( FMOD_STUDIO YES ) + endif() else() message( STATUS "Could not find FMOD include files" ) set( NO_FMOD ON ) From 9c91686e0fa2fc1af18c06e05ac9f6e33e0dc068 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 6 Sep 2016 12:36:30 +0300 Subject: [PATCH 79/97] Set delay loading for proper .dll depending on FMOD version (Studio vs. Ex) --- src/CMakeLists.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 025d651c3..841c06a6f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1343,7 +1343,16 @@ endif() if( MSVC ) option( ZDOOM_GENERATE_MAPFILE "Generate .map file for debugging." OFF ) - set( LINKERSTUFF "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\"" ) + set( LINKERSTUFF "/MANIFEST:NO" ) + + if( NOT NO_FMOD ) + if( FMOD_STUDIO ) + set( LINKERSTUFF "${LINKERSTUFF} /DELAYLOAD:\"fmod${X64}.dll\"" ) + else() + set( LINKERSTUFF "${LINKERSTUFF} /DELAYLOAD:\"fmodex${X64}.dll\"" ) + endif() + endif() + if( ZDOOM_GENERATE_MAPFILE ) set( LINKERSTUFF "${LINKERSTUFF} /MAP" ) endif() From b308a7df52dc9d6a223ddb53365a1852f0205d54 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 6 Sep 2016 12:43:57 +0300 Subject: [PATCH 80/97] Proper name of FMOD .dylib in loading path adjustment for macOS --- src/CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 841c06a6f..bb5f21308 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1392,17 +1392,23 @@ if( APPLE ) MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist" ) if( NOT NO_FMOD ) + if( FMOD_STUDIO ) + set( FMOD_DYLIB libfmod.dylib ) + else() + set( FMOD_DYLIB libfmodex.dylib ) + endif() + # Fix fmod link so that it can be found in the app bundle. find_program( OTOOL otool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" ) find_program( INSTALL_NAME_TOOL install_name_tool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" ) execute_process( COMMAND "${OTOOL}" -L "${FMOD_LIBRARY}" - COMMAND grep "libfmodex.dylib (compat" + COMMAND grep "${FMOD_DYLIB} (compat" COMMAND head -n1 COMMAND awk "{print $1}" OUTPUT_VARIABLE FMOD_LINK OUTPUT_STRIP_TRAILING_WHITESPACE ) add_custom_command( TARGET zdoom POST_BUILD - COMMAND "${INSTALL_NAME_TOOL}" -change "${FMOD_LINK}" @executable_path/../Frameworks/libfmodex.dylib "$" + COMMAND "${INSTALL_NAME_TOOL}" -change "${FMOD_LINK}" @executable_path/../Frameworks/${FMOD_DYLIB} "$" COMMENT "Relinking FMOD Ex" ) endif() endif() From 823f75e59239093a0947667ead7fbefa484cb851 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 12 Sep 2016 21:32:17 +0200 Subject: [PATCH 81/97] - fixed: UDMF user value lists need to be sorted for binary search to work but weren't. --- src/p_udmf.cpp | 5 +++++ src/r_defs.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 0b054247e..c09debc51 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -309,6 +309,11 @@ void FUDMFKeys::Sort() FUDMFKey *FUDMFKeys::Find(FName key) { + if (!mSorted) + { + mSorted = true; + Sort(); + } int min = 0, max = Size()-1; while (min <= max) diff --git a/src/r_defs.h b/src/r_defs.h index f27ac2716..59b1fe0d3 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -220,6 +220,7 @@ struct FUDMFKey class FUDMFKeys : public TArray { + bool mSorted = false; public: void Sort(); FUDMFKey *Find(FName key); From e10abcad067b7786cabec0e723c7c61def64b6a1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 13 Sep 2016 10:43:53 +0200 Subject: [PATCH 82/97] - fixed: The TabCommands array needs to be cleared before the NameManager is destroyed. TabCommands use an FName to store the command's name so once the NameManager is destroyed its data will become invalid. This is a problem because C_RemoveTabCommand is being called from FBaseCVar's destructor and most CVARs are global variables. --- src/name.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/name.cpp b/src/name.cpp index 8140829c6..ecedcf0f3 100644 --- a/src/name.cpp +++ b/src/name.cpp @@ -35,6 +35,7 @@ #include #include "name.h" #include "c_dispatch.h" +#include "c_console.h" // MACROS ------------------------------------------------------------------ @@ -268,6 +269,8 @@ FName::NameManager::~NameManager() { NameBlock *block, *next; + C_ClearTabCommands(); + for (block = Blocks; block != NULL; block = next) { next = block->NextBlock; From ba68cfd61153ed260ae1cf3c8dc7e4986ee4fa69 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 13 Sep 2016 21:01:50 +0200 Subject: [PATCH 83/97] - do not even allow creation of names in C_RemoveTabCommands if there are no tab commands, so that FindName cannot be called after the NameManager has been destroyed. --- src/c_console.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/c_console.cpp b/src/c_console.cpp index 086861229..2d164c478 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1747,6 +1747,14 @@ void C_AddTabCommand (const char *name) void C_RemoveTabCommand (const char *name) { + if (TabCommands.Size() == 0) + { + // There are no tab commands that can be removed. + // This is important to skip construction of aname + // in case the NameManager has already been destroyed. + return; + } + FName aname(name, true); if (aname == NAME_None) From 172f58c1655848df85d35676a4a5aeb094d05b2c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 13 Sep 2016 11:46:05 +0200 Subject: [PATCH 84/97] Fix 5:4 aspect ratio gun and status bar --- src/g_shared/shared_sbar.cpp | 2 +- src/r_main.cpp | 4 ++-- src/r_utility.cpp | 2 +- src/v_draw.cpp | 4 ++-- src/v_video.cpp | 19 +++++++++++++------ src/v_video.h | 3 ++- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 3c41d18ca..22171a4bb 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -300,7 +300,7 @@ void DBaseStatusBar::SetScaled (bool scale, bool force) ST_X = 0; ST_Y = VirticalResolution - RelTop; float aspect = ActiveRatio(SCREENWIDTH, SCREENHEIGHT); - if (aspect >= 1.3f) + if (!Is54Aspect(aspect)) { // Normal resolution ::ST_Y = Scale (ST_Y, SCREENHEIGHT, VirticalResolution); } diff --git a/src/r_main.cpp b/src/r_main.cpp index d84698b7c..6094f70de 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -318,7 +318,7 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, virtwidth = virtwidth2 = fullWidth; virtheight = virtheight2 = fullHeight; - if (trueratio < 1.3f) + if (Is54Aspect(trueratio)) { virtheight2 = virtheight2 * AspectMultiplier(trueratio) / 48; } @@ -327,7 +327,7 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, virtwidth2 = virtwidth2 * AspectMultiplier(trueratio) / 48; } - if (WidescreenRatio < 1.3f) + if (Is54Aspect(WidescreenRatio)) { virtheight = virtheight * AspectMultiplier(WidescreenRatio) / 48; } diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 8e4284b7e..76cf05e9b 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -229,7 +229,7 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) centery = viewheight/2; centerx = viewwidth/2; - if (WidescreenRatio < 1.3f) + if (Is54Aspect(WidescreenRatio)) { centerxwide = centerx; } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index a33fd618b..3075cd92d 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -887,7 +887,7 @@ void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h, x = x * Width / vwidth; w = right * Width / vwidth - x; } - if (myratio < 1.3f) + if (Is54Aspect(myratio)) { // The target surface is 5:4 y = (y - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5; h = (bottom - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5 - y; @@ -950,7 +950,7 @@ void DCanvas::FillBorder (FTexture *img) return; } int bordtop, bordbottom, bordleft, bordright, bord; - if (myratio < 1.3f) + if (Is54Aspect(myratio)) { // Screen is taller than it is wide bordleft = bordright = 0; bord = Height - Height * AspectMultiplier(myratio) / 48; diff --git a/src/v_video.cpp b/src/v_video.cpp index 20e1f526c..710d8b1cf 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1362,7 +1362,7 @@ void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int real int cx1, cy1, cx2, cy2; ratio = ActiveRatio(realwidth, realheight); - if (ratio < 1.3f) + if (Is54Aspect(ratio)) { cwidth = realwidth; cheight = realheight * AspectMultiplier(ratio) / 48; @@ -1703,22 +1703,29 @@ int CheckRatio (int width, int height, int *trueratio) int AspectBaseWidth(float aspect) { - return (int)round(240.0f * aspect * 3.0f); + return !Is54Aspect(aspect) ? (int)round(240.0f * aspect * 3.0f) : 960; } int AspectBaseHeight(float aspect) { - return (int)round(200.0f * (320.0f / (240.0f * aspect)) * 3.0f); + return !Is54Aspect(aspect) ? (int)round(200.0f * (320.0f / (240.0f * aspect)) * 3.0f) : 640; } -int AspectPspriteOffset(float aspect) +double AspectPspriteOffset(float aspect) { - return aspect < 1.3f ? (int)(6.5*FRACUNIT) : 0; + return !Is54Aspect(aspect) ? 0.0 : 6.5; } int AspectMultiplier(float aspect) { - return (int)round(320.0f / (240.0f * aspect) * 48.0f); + return !Is54Aspect(aspect) ? (int)round(320.0f / (240.0f * aspect) * 48.0f) : 48 * 15 / 16; +} + +bool Is54Aspect(float aspect) +{ + // The 5:4 aspect ratio redefined all the values to mean something else.. + // Limit the range this is active to try prevent square cam textures inheriting this madness. + return aspect > 1.1f && aspect < 1.3f; } void IVideo::DumpAdapters () diff --git a/src/v_video.h b/src/v_video.h index 8d785e43f..26d45d9a0 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -523,8 +523,9 @@ static inline double ActiveRatio (double width, double height) { return ActiveRa int AspectBaseWidth(float aspect); int AspectBaseHeight(float aspect); -int AspectPspriteOffset(float aspect); +double AspectPspriteOffset(float aspect); int AspectMultiplier(float aspect); +bool Is54Aspect(float aspect); EXTERN_CVAR(Int, uiscale); From 017d1cee29adf2b2b479cc26dbb8ac5f461f5f0a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 13 Sep 2016 23:26:30 +0200 Subject: [PATCH 85/97] Change canvas rendering to use the aspect ratio of the canvas and generalize 5:4 rendering as AspectTallerThanWide --- src/g_shared/shared_sbar.cpp | 2 +- src/r_main.cpp | 6 +++--- src/r_utility.cpp | 14 +++++++++++--- src/r_utility.h | 2 +- src/v_draw.cpp | 6 +++--- src/v_video.cpp | 25 ++++++++++++++++--------- src/v_video.h | 2 +- 7 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 22171a4bb..f66ec187d 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -300,7 +300,7 @@ void DBaseStatusBar::SetScaled (bool scale, bool force) ST_X = 0; ST_Y = VirticalResolution - RelTop; float aspect = ActiveRatio(SCREENWIDTH, SCREENHEIGHT); - if (!Is54Aspect(aspect)) + if (!AspectTallerThanWide(aspect)) { // Normal resolution ::ST_Y = Scale (ST_Y, SCREENHEIGHT, VirticalResolution); } diff --git a/src/r_main.cpp b/src/r_main.cpp index 6094f70de..040b57b71 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -318,7 +318,7 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, virtwidth = virtwidth2 = fullWidth; virtheight = virtheight2 = fullHeight; - if (Is54Aspect(trueratio)) + if (AspectTallerThanWide(trueratio)) { virtheight2 = virtheight2 * AspectMultiplier(trueratio) / 48; } @@ -327,7 +327,7 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, virtwidth2 = virtwidth2 * AspectMultiplier(trueratio) / 48; } - if (Is54Aspect(WidescreenRatio)) + if (AspectTallerThanWide(WidescreenRatio)) { virtheight = virtheight * AspectMultiplier(WidescreenRatio) / 48; } @@ -948,7 +948,7 @@ void R_RenderViewToCanvas (AActor *actor, DCanvas *canvas, RenderTarget = canvas; bRenderingToCanvas = true; - R_SetWindow (12, width, height, height); + R_SetWindow (12, width, height, height, true); viewwindowx = x; viewwindowy = y; viewactive = true; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 76cf05e9b..ebe36dc9d 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -198,7 +198,7 @@ void R_SetViewSize (int blocks) // //========================================================================== -void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) +void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, bool renderingToCanvas) { float trueratio; @@ -220,7 +220,15 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) freelookviewheight = ((setblocks*fullHeight)/10)&~7; } - WidescreenRatio = ActiveRatio (fullWidth, fullHeight, &trueratio); + if (renderingToCanvas) + { + WidescreenRatio = fullWidth / (float)fullHeight; + trueratio = WidescreenRatio; + } + else + { + WidescreenRatio = ActiveRatio(fullWidth, fullHeight, &trueratio); + } DrawFSHUD = (windowSize == 11); @@ -229,7 +237,7 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) centery = viewheight/2; centerx = viewwidth/2; - if (Is54Aspect(WidescreenRatio)) + if (AspectTallerThanWide(WidescreenRatio)) { centerxwide = centerx; } diff --git a/src/r_utility.h b/src/r_utility.h index e9fd436e5..09a8b5667 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -95,7 +95,7 @@ void R_ExecuteSetViewSize (void); // Called by M_Responder. void R_SetViewSize (int blocks); -void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight); +void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, bool renderingToCanvas = false); extern void R_FreePastViewers (); diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 3075cd92d..4677c4b08 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -874,7 +874,7 @@ void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h, double right = x + w; double bottom = y + h; - if (myratio > 1.4f) + if (myratio > 1.334f) { // The target surface is either 16:9 or 16:10, so expand the // specified virtual size to avoid undesired stretching of the // image. Does not handle non-4:3 virtual sizes. I'll worry about @@ -887,7 +887,7 @@ void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h, x = x * Width / vwidth; w = right * Width / vwidth - x; } - if (Is54Aspect(myratio)) + if (AspectTallerThanWide(myratio)) { // The target surface is 5:4 y = (y - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5; h = (bottom - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5 - y; @@ -950,7 +950,7 @@ void DCanvas::FillBorder (FTexture *img) return; } int bordtop, bordbottom, bordleft, bordright, bord; - if (Is54Aspect(myratio)) + if (AspectTallerThanWide(myratio)) { // Screen is taller than it is wide bordleft = bordright = 0; bord = Height - Height * AspectMultiplier(myratio) / 48; diff --git a/src/v_video.cpp b/src/v_video.cpp index 710d8b1cf..af190d372 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1362,7 +1362,7 @@ void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int real int cx1, cy1, cx2, cy2; ratio = ActiveRatio(realwidth, realheight); - if (Is54Aspect(ratio)) + if (AspectTallerThanWide(ratio)) { cwidth = realwidth; cheight = realheight * AspectMultiplier(ratio) / 48; @@ -1703,29 +1703,36 @@ int CheckRatio (int width, int height, int *trueratio) int AspectBaseWidth(float aspect) { - return !Is54Aspect(aspect) ? (int)round(240.0f * aspect * 3.0f) : 960; + return (int)round(240.0f * aspect * 3.0f); } int AspectBaseHeight(float aspect) { - return !Is54Aspect(aspect) ? (int)round(200.0f * (320.0f / (240.0f * aspect)) * 3.0f) : 640; + if (!AspectTallerThanWide(aspect)) + return (int)round(200.0f * (320.0f / (AspectBaseWidth(aspect) / 3.0f)) * 3.0f); + else + return (int)round((200.0f * (4.0f / 3.0f)) / aspect * 3.0f); } double AspectPspriteOffset(float aspect) { - return !Is54Aspect(aspect) ? 0.0 : 6.5; + if (!AspectTallerThanWide(aspect)) + return 0.0; + else + return ((4.0 / 3.0) / aspect - 1.0) * 97.5; } int AspectMultiplier(float aspect) { - return !Is54Aspect(aspect) ? (int)round(320.0f / (240.0f * aspect) * 48.0f) : 48 * 15 / 16; + if (!AspectTallerThanWide(aspect)) + return (int)round(320.0f / (AspectBaseWidth(aspect) / 3.0f) * 48.0f); + else + return (int)round(200.0f / (AspectBaseHeight(aspect) / 3.0f) * 48.0f); } -bool Is54Aspect(float aspect) +bool AspectTallerThanWide(float aspect) { - // The 5:4 aspect ratio redefined all the values to mean something else.. - // Limit the range this is active to try prevent square cam textures inheriting this madness. - return aspect > 1.1f && aspect < 1.3f; + return aspect < 1.333f; } void IVideo::DumpAdapters () diff --git a/src/v_video.h b/src/v_video.h index 26d45d9a0..7317c9d1a 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -525,7 +525,7 @@ int AspectBaseWidth(float aspect); int AspectBaseHeight(float aspect); double AspectPspriteOffset(float aspect); int AspectMultiplier(float aspect); -bool Is54Aspect(float aspect); +bool AspectTallerThanWide(float aspect); EXTERN_CVAR(Int, uiscale); From f1bca9d20e7d36b3057cc9faee7da213d9cbedd0 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Tue, 13 Sep 2016 20:10:06 -0400 Subject: [PATCH 86/97] The old DirectX setup is required to utilize v140_xp. Revert "- removed DirectX setup from CMakeLists for Visual Studio" This reverts commit 954ac8ce5e607e7811a91717e0e1cfe5126d820a. --- src/CMakeLists.txt | 86 ++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bb5f21308..7f1554f44 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -114,59 +114,49 @@ if( WIN32 ) set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) set( NASM_NAMES nasmw nasm ) - if( NOT MSVC ) - find_path( D3D_INCLUDE_DIR d3d9.h - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Include ) - if( NOT D3D_INCLUDE_DIR ) - message( SEND_ERROR "Could not find DirectX 9 header files" ) - else() - include_directories( ${D3D_INCLUDE_DIR} ) - endif() - - find_path( XINPUT_INCLUDE_DIR xinput.h - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Include ) - if( NOT XINPUT_INCLUDE_DIR ) - message( WARNING "Could not find xinput.h. XInput will be disabled." ) - add_definitions( -DNO_XINPUT ) - else() - include_directories( ${XINPUT_INCLUDE_DIR} ) - endif() - - find_library( DX_dxguid_LIBRARY dxguid - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - find_library( DX_dinput8_LIBRARY dinput8 - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - - set( DX_LIBS_FOUND YES ) - if( NOT DX_dxguid_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif() - if( NOT DX_dinput8_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif() - - if( NOT DX_LIBS_FOUND ) - message( FATAL_ERROR "Could not find DirectX 9 libraries" ) - endif() - - set( DX_LIBS - "${DX_dxguid_LIBRARY}" - "${DX_dinput8_LIBRARY}" - ) + find_path( D3D_INCLUDE_DIR d3d9.h + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Include ) + if( NOT D3D_INCLUDE_DIR ) + message( SEND_ERROR "Could not find DirectX 9 header files" ) else() - set( DX_LIBS - dxguid - dinput8 - ) + include_directories( ${D3D_INCLUDE_DIR} ) + endif() + + find_path( XINPUT_INCLUDE_DIR xinput.h + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Include ) + if( NOT XINPUT_INCLUDE_DIR ) + message( WARNING "Could not find xinput.h. XInput will be disabled." ) + add_definitions( -DNO_XINPUT ) + else() + include_directories( ${XINPUT_INCLUDE_DIR} ) endif() - set( ZDOOM_LIBS ${DX_LIBS} + find_library( DX_dxguid_LIBRARY dxguid + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) + find_library( DX_dinput8_LIBRARY dinput8 + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) + + set( DX_LIBS_FOUND YES ) + if( NOT DX_dxguid_LIBRARY ) + set( DX_LIBS_FOUND NO ) + endif() + if( NOT DX_dinput8_LIBRARY ) + set( DX_LIBS_FOUND NO ) + endif() + + if( NOT DX_LIBS_FOUND ) + message( FATAL_ERROR "Could not find DirectX 9 libraries" ) + endif() + + set( ZDOOM_LIBS wsock32 winmm + "${DX_dxguid_LIBRARY}" + "${DX_dinput8_LIBRARY}" ole32 user32 gdi32 From fd53aefbf27e4ffd2423d027d10f95b3be07dead Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Tue, 13 Sep 2016 20:54:06 -0400 Subject: [PATCH 87/97] Added warning if building on Visual Studio 2015 without v140_xp. --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f0bf8293..9d7da1644 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,11 @@ list( APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ) include( CreateLaunchers ) include( FindPackageHandleStandardArgs ) +# Produce a warning if XP support will be missing. +if( MSVC14 AND NOT CMAKE_GENERATOR_TOOLSET STREQUAL "v140_xp" ) + message( WARNING "This project supports Windows XP (including XP x64), but you must set the optional toolset to v140_xp manually to have it in your build! Use -T \"v140_xp\" from the command prompt." ) +endif() + # Support cross compiling option( FORCE_CROSSCOMPILE "Turn on cross compiling." NO ) if( FORCE_CROSSCOMPILE ) From 3b2359959ef9432448c685cc727039e19d2bf26a Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Tue, 13 Sep 2016 23:06:57 -0500 Subject: [PATCH 88/97] Quakes must use their own independent falloffs.This caused discrepencies and sudden drop-outs in stacked quakes otherwise. --- src/g_shared/a_quake.cpp | 10 ++++------ src/g_shared/a_sharedglobal.h | 1 - 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index aae006ca7..63394e02a 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -291,10 +291,9 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger if (!(quake->m_Flags & QF_WAVE)) { - jiggers.Falloff = MAX(falloff, jiggers.Falloff); - jiggers.RollIntensity = MAX(r, jiggers.RollIntensity) * jiggers.Falloff; + jiggers.RollIntensity = MAX(r, jiggers.RollIntensity) * falloff; - intensity *= jiggers.Falloff; + intensity *= falloff; if (quake->m_Flags & QF_RELATIVE) { jiggers.RelIntensity.X = MAX(intensity.X, jiggers.RelIntensity.X); @@ -310,14 +309,13 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger } else { - jiggers.Falloff = MAX(falloff, jiggers.Falloff); - jiggers.RollWave = r * quake->GetModWave(quake->m_RollWave) * jiggers.Falloff * strength; + jiggers.RollWave = r * quake->GetModWave(quake->m_RollWave) * falloff * strength; intensity.X *= quake->GetModWave(quake->m_WaveSpeed.X); intensity.Y *= quake->GetModWave(quake->m_WaveSpeed.Y); intensity.Z *= quake->GetModWave(quake->m_WaveSpeed.Z); - intensity *= strength * jiggers.Falloff; + intensity *= strength * falloff; // [RH] This only gives effect to the last sine quake. I would // prefer if some way was found to make multiples coexist diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 314061f04..029653bb1 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -153,7 +153,6 @@ struct FQuakeJiggers DVector3 RelIntensity; DVector3 Offset; DVector3 RelOffset; - double Falloff; double RollIntensity, RollWave; }; From 65af26f9629149ec03df5fa3dcccc528aa920c73 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Wed, 14 Sep 2016 12:30:11 +0200 Subject: [PATCH 89/97] The VM now properly aborts on critical errors --- src/zscript/vm.h | 8 ++++++++ src/zscript/vmexec.cpp | 10 +--------- src/zscript/vmframe.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 52b354028..31136bba2 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -156,6 +156,14 @@ enum ATAG_RNG, // pointer to FRandom }; +enum EVMAbortException +{ + X_READ_NIL, + X_WRITE_NIL, + X_TOO_MANY_TRIES, + X_ARRAY_OUT_OF_BOUNDS, +}; + class VMFunction : public DObject { DECLARE_ABSTRACT_CLASS(VMFunction, DObject); diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp index 070aeb30a..454f02d03 100644 --- a/src/zscript/vmexec.cpp +++ b/src/zscript/vmexec.cpp @@ -44,7 +44,7 @@ #define ASSERTKA(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstA) #define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS) -#define THROW(x) +#define THROW(x) throw(EVMAbortException(x)) #define CMPJMP(test) \ if ((test) == (a & CMP_CHECK)) { \ @@ -54,14 +54,6 @@ pc += 1; \ } -enum -{ - X_READ_NIL, - X_WRITE_NIL, - X_TOO_MANY_TRIES, - X_ARRAY_OUT_OF_BOUNDS -}; - #define GETADDR(a,o,x) \ if (a == NULL) { THROW(x); } \ ptr = (VM_SBYTE *)a + o diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index c7d9cb87d..9f8ad7dc0 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -407,6 +407,40 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur } throw; } + catch (EVMAbortException exception) + { + if (allocated) + { + PopFrame(); + } + if (trap != nullptr) + { + *trap = nullptr; + } + + Printf("VM execution aborted: "); + switch (exception) + { + case X_READ_NIL: + Printf("tried to read from address zero."); + break; + + case X_WRITE_NIL: + Printf("tried to write to address zero."); + break; + + case X_TOO_MANY_TRIES: + Printf("too many try-catch blocks."); + break; + + case X_ARRAY_OUT_OF_BOUNDS: + Printf("array access out of bounds."); + break; + } + Printf("\n"); + + return -1; + } catch (...) { if (allocated) From cb17e109f17a36c9f1465568630cc361cf8bac74 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Wed, 14 Sep 2016 12:43:05 +0200 Subject: [PATCH 90/97] Added "division by zero" to the VM-aborting errors --- src/zscript/vm.h | 1 + src/zscript/vmexec.h | 40 ++++++++++++++++++++++++++++++++++++++++ src/zscript/vmframe.cpp | 4 ++++ 3 files changed, 45 insertions(+) diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 31136bba2..0d45ad90a 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -162,6 +162,7 @@ enum EVMAbortException X_WRITE_NIL, X_TOO_MANY_TRIES, X_ARRAY_OUT_OF_BOUNDS, + X_DIVISION_BY_ZERO, }; class VMFunction : public DObject diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index 8232340a0..42a374030 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -786,27 +786,51 @@ begin: OP(DIV_RR): ASSERTD(a); ASSERTD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = reg.d[B] / reg.d[C]; NEXTOP; OP(DIV_RK): ASSERTD(a); ASSERTD(B); ASSERTKD(C); + if (konstd[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = reg.d[B] / konstd[C]; NEXTOP; OP(DIV_KR): ASSERTD(a); ASSERTKD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = konstd[B] / reg.d[C]; NEXTOP; OP(MOD_RR): ASSERTD(a); ASSERTD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = reg.d[B] % reg.d[C]; NEXTOP; OP(MOD_RK): ASSERTD(a); ASSERTD(B); ASSERTKD(C); + if (konstd[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = reg.d[B] % konstd[C]; NEXTOP; OP(MOD_KR): ASSERTD(a); ASSERTKD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = konstd[B] % reg.d[C]; NEXTOP; @@ -981,14 +1005,26 @@ begin: OP(DIVF_RR): ASSERTF(a); ASSERTF(B); ASSERTF(C); + if (reg.f[C] == 0.) + { + THROW(X_DIVISION_BY_ZERO); + } reg.f[a] = reg.f[B] / reg.f[C]; NEXTOP; OP(DIVF_RK): ASSERTF(a); ASSERTF(B); ASSERTKF(C); + if (konstf[C] == 0.) + { + THROW(X_DIVISION_BY_ZERO); + } reg.f[a] = reg.f[B] / konstf[C]; NEXTOP; OP(DIVF_KR): ASSERTF(a); ASSERTKF(B); ASSERTF(C); + if (reg.f[C] == 0.) + { + THROW(X_DIVISION_BY_ZERO); + } reg.f[a] = konstf[B] / reg.f[C]; NEXTOP; @@ -996,6 +1032,10 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTF(C); fb = reg.f[B]; fc = reg.f[C]; Do_MODF: + if (fc == 0.) + { + THROW(X_DIVISION_BY_ZERO); + } reg.f[a] = luai_nummod(fb, fc); NEXTOP; OP(MODF_RK): diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index 9f8ad7dc0..29da0c5b9 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -436,6 +436,10 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur case X_ARRAY_OUT_OF_BOUNDS: Printf("array access out of bounds."); break; + + case X_DIVISION_BY_ZERO: + Printf("division by zero."); + break; } Printf("\n"); From 48f491cfd12ddc489faf296898f9db050e907767 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 14 Sep 2016 23:38:11 +0200 Subject: [PATCH 91/97] Fix video mode selection bug --- src/menu/videomenu.cpp | 24 ++++++++++++------------ src/v_video.cpp | 4 ++++ src/v_video.h | 4 ++++ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index 1328e2f7a..b1b4d792f 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -95,7 +95,7 @@ CUSTOM_CVAR (Int, menu_screenratios, -1, CVAR_ARCHIVE) } else { - BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); + BuildModesList (screen->VideoWidth, screen->VideoHeight, DisplayBits); } } @@ -139,7 +139,7 @@ public: DVideoModeMenu() { - SetModesMenu (SCREENWIDTH, SCREENHEIGHT, DisplayBits); + SetModesMenu (screen->VideoWidth, screen->VideoHeight, DisplayBits); } bool MenuEvent(int mkey, bool fromcontroller) @@ -163,13 +163,13 @@ public: { if (!GetSelectedSize (&NewWidth, &NewHeight)) { - NewWidth = SCREENWIDTH; - NewHeight = SCREENHEIGHT; + NewWidth = screen->VideoWidth; + NewHeight = screen->VideoHeight; } else { - OldWidth = SCREENWIDTH; - OldHeight = SCREENHEIGHT; + OldWidth = screen->VideoWidth; + OldHeight = screen->VideoHeight; OldBits = DisplayBits; NewBits = BitTranslate[DummyDepthCvar]; setmodeneeded = true; @@ -297,11 +297,11 @@ void M_RestoreMode () void M_SetDefaultMode () { // Make current resolution the default - vid_defwidth = SCREENWIDTH; - vid_defheight = SCREENHEIGHT; + vid_defwidth = screen->VideoWidth; + vid_defheight = screen->VideoHeight; vid_defbits = DisplayBits; testingmode = 0; - SetModesMenu (SCREENWIDTH, SCREENHEIGHT, DisplayBits); + SetModesMenu (screen->VideoWidth, screen->VideoHeight, DisplayBits); } @@ -314,7 +314,7 @@ void M_SetDefaultMode () void M_RefreshModesList () { - BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); + BuildModesList (screen->VideoWidth, screen->VideoHeight, DisplayBits); } void M_InitVideoModesMenu () @@ -385,8 +385,8 @@ void M_SetVideoMode() { if (!GetSelectedSize (&NewWidth, &NewHeight)) { - NewWidth = SCREENWIDTH; - NewHeight = SCREENHEIGHT; + NewWidth = screen->VideoWidth; + NewHeight = screen->VideoHeight; } else { diff --git a/src/v_video.cpp b/src/v_video.cpp index af190d372..b1f1ced9c 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -850,6 +850,9 @@ DFrameBuffer::DFrameBuffer (int width, int height) { LastMS = LastSec = FrameCount = LastCount = LastTic = 0; Accel2D = false; + + VideoWidth = width; + VideoHeight = height; } //========================================================================== @@ -1352,6 +1355,7 @@ void V_OutputResized (int width, int height) { StatusBar->ScreenSizeChanged(); } + C_NewModeAdjust(); } void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *_cx1, int *_cx2) diff --git a/src/v_video.h b/src/v_video.h index 7317c9d1a..d19a3b06e 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -422,6 +422,10 @@ public: virtual bool Is8BitMode() = 0; #endif + // The original size of the framebuffer as selected in the video menu. + int VideoWidth = 0; + int VideoHeight = 0; + protected: void DrawRateStuff (); void CopyFromBuff (BYTE *src, int srcPitch, int width, int height, BYTE *dest); From 0d27996a648a9668650f396b9de544371074f820 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 14 Sep 2016 23:38:50 +0200 Subject: [PATCH 92/97] Replace CheckRatio with AspectTallerThanWide in DrawHUD --- src/g_shared/shared_hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index e40233def..c4d8ec1ed 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -1108,7 +1108,7 @@ void DrawHUD() } else { - if (CheckRatio(SCREENWIDTH, SCREENHEIGHT) == 4) + if (AspectTallerThanWide(WidescreenRatio)) { hudheight = hudwidth * 30 / AspectMultiplier(WidescreenRatio); // BaseRatioSizes is inverted for this mode } From ac70f77e44c17115f908d85275d868ada936e582 Mon Sep 17 00:00:00 2001 From: raa-eruanna Date: Thu, 15 Sep 2016 15:09:36 -0400 Subject: [PATCH 93/97] Added the following ccmds: actorlist, actornum, monsternum, itemsnum, countitemsnum Modified the following ccmds: monster, items, countitems All commands with "num" at the end simply print a count of their respective filters, all other listed commands now print a list and a count. --- src/c_cmds.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index d72fc79a2..fa01e1b4b 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -923,10 +923,18 @@ static bool IsActorACountItem(AActor *mo) return mo->IsKindOf(RUNTIME_CLASS(AInventory)) && mo->flags&MF_SPECIAL && mo->flags&MF_COUNTITEM; } -static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const char *FilterName) +// [SP] for all actors +static bool IsActor(AActor *mo) +{ + return true; +} + +// [SP] modified - now allows showing count only, new arg must be passed. Also now still counts regardless, if lists are printed. +static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const char *FilterName, bool countOnly) { AActor *mo; const PClass *FilterClass = NULL; + int counter = 0; if (FilterName != NULL) { @@ -943,10 +951,32 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha { if ((FilterClass == NULL || mo->IsA(FilterClass)) && IsActorType(mo)) { - Printf ("%s at (%f,%f,%f)\n", - mo->GetClass()->TypeName.GetChars(), mo->X(), mo->Y(), mo->Z()); + counter++; + if (!countOnly) + Printf ("%s at (%f,%f,%f)\n", + mo->GetClass()->TypeName.GetChars(), mo->X(), mo->Y(), mo->Z()); } } + Printf("%i match(s) found.\n", counter); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- +CCMD(actorlist) // [SP] print all actors (this can get quite big?) +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActor, argv.argc() > 1 ? argv[1] : NULL, false); +} + +CCMD(actornum) // [SP] count all actors +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActor, argv.argc() > 1 ? argv[1] : NULL, true); } //----------------------------------------------------------------------------- @@ -958,7 +988,14 @@ CCMD(monster) { if (CheckCheatmode ()) return; - PrintFilteredActorList(IsActorAMonster, argv.argc() > 1 ? argv[1] : NULL); + PrintFilteredActorList(IsActorAMonster, argv.argc() > 1 ? argv[1] : NULL, false); +} + +CCMD(monsternum) // [SP] count monsters +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActorAMonster, argv.argc() > 1 ? argv[1] : NULL, true); } //----------------------------------------------------------------------------- @@ -970,7 +1007,14 @@ CCMD(items) { if (CheckCheatmode ()) return; - PrintFilteredActorList(IsActorAnItem, argv.argc() > 1 ? argv[1] : NULL); + PrintFilteredActorList(IsActorAnItem, argv.argc() > 1 ? argv[1] : NULL, false); +} + +CCMD(itemsnum) // [SP] # of any items +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActorAnItem, argv.argc() > 1 ? argv[1] : NULL, true); } //----------------------------------------------------------------------------- @@ -982,7 +1026,14 @@ CCMD(countitems) { if (CheckCheatmode ()) return; - PrintFilteredActorList(IsActorACountItem, argv.argc() > 1 ? argv[1] : NULL); + PrintFilteredActorList(IsActorACountItem, argv.argc() > 1 ? argv[1] : NULL, false); +} + +CCMD(countitemsnum) // [SP] # of counted items +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActorACountItem, argv.argc() > 1 ? argv[1] : NULL, true); } //----------------------------------------------------------------------------- From 476b727d5d99afccaf7a73935379816734500157 Mon Sep 17 00:00:00 2001 From: raa-eruanna Date: Fri, 16 Sep 2016 00:47:56 -0400 Subject: [PATCH 94/97] "actorlist" and "actornum" no longer return already-owned inventory objects --- src/c_cmds.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index fa01e1b4b..03a7495e4 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -926,7 +926,10 @@ static bool IsActorACountItem(AActor *mo) // [SP] for all actors static bool IsActor(AActor *mo) { - return true; + if (mo->IsKindOf(RUNTIME_CLASS(AInventory))) + return static_cast(mo)->Owner == NULL; // [SP] Exclude inventory-owned items + else + return true; } // [SP] modified - now allows showing count only, new arg must be passed. Also now still counts regardless, if lists are printed. From 3db7d9ad8459f36aa7c3d80594c6725edae72231 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 18 Sep 2016 12:22:56 +0200 Subject: [PATCH 95/97] - fixed: AActor::alternative was not declared as a pointer. --- src/p_mobj.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 6d8ce4418..e93b886e8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -140,6 +140,7 @@ IMPLEMENT_POINTY_CLASS (AActor) DECLARE_POINTER (master) DECLARE_POINTER (Poisoner) DECLARE_POINTER (Damage) + DECLARE_POINTER (alternative) END_POINTERS AActor::~AActor () From f1ba19073fce4af02298056b93bd78ff16313822 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 19 Sep 2016 03:36:51 +0200 Subject: [PATCH 96/97] - split Damage into two variables: DamageVal for the old constant and DamageFunc for the DECORATE function. The way this was done was a major headache inducer, requiring reconstruction of the function each time the value was changed and in general made actor damage a major hassle. There was a DECORATE wrapper to mimic the original behavior but this looked quite broken because it completely ignored the different semantics of both damage calculation types. It also made it impossible to determine if damage was a function or a value. This accessor has been reverted to what it should be, only returning the constant, which now is -1 for a damage function. I am sorry if this may break the odd mod out but a quick look over some DECORATE-heavy stuff showed that this was never combined in any of them so that accessing 'damage' in DECORATE code depended on an actual damage function. To get proper damage, a future commit will add a DECORATE function which calls AActor::GetMissileDamage. --- src/actor.h | 23 +++++- src/d_dehacked.cpp | 2 +- src/g_doom/a_bossbrain.cpp | 2 +- src/g_heretic/a_ironlich.cpp | 4 +- src/g_hexen/a_magelightning.cpp | 2 +- src/info.cpp | 2 +- src/p_acs.cpp | 2 +- src/p_map.cpp | 2 +- src/p_mobj.cpp | 115 ++++++--------------------- src/thingdef/olddecorations.cpp | 3 +- src/thingdef/thingdef.cpp | 12 +-- src/thingdef/thingdef_data.cpp | 1 + src/thingdef/thingdef_exp.h | 17 +--- src/thingdef/thingdef_expression.cpp | 74 +---------------- src/thingdef/thingdef_parse.cpp | 16 ++-- src/thingdef/thingdef_properties.cpp | 11 ++- 16 files changed, 81 insertions(+), 207 deletions(-) diff --git a/src/actor.h b/src/actor.h index 522405dd6..d804b0995 100644 --- a/src/actor.h +++ b/src/actor.h @@ -111,6 +111,8 @@ struct FPortalGroupArray; // Any questions? // + + // --- mobj.flags --- enum ActorFlag { @@ -1014,7 +1016,9 @@ public: SDWORD tics; // state tic counter FState *state; - VMFunction *Damage; // For missiles and monster railgun + //VMFunction *Damage; // For missiles and monster railgun + int DamageVal; + VMFunction *DamageFunc; int projectileKickback; ActorFlags flags; ActorFlags2 flags2; // Heretic flags @@ -1201,6 +1205,23 @@ public: FState *GetRaiseState(); void Revive(); + void SetDamage(int dmg) + { + DamageVal = dmg; + DamageFunc = nullptr; + } + + bool IsZeroDamage() const + { + return DamageVal == 0 && DamageFunc == nullptr; + } + + void RestoreDamage() + { + DamageVal = GetDefault()->DamageVal; + DamageFunc = GetDefault()->DamageFunc; + } + FState *FindState (FName label) const { return GetClass()->FindState(1, &label); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 4beb5c25a..dfa4f56f0 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -915,7 +915,7 @@ static int PatchThing (int thingy) } else if (linelen == 14 && stricmp (Line1, "Missile damage") == 0) { - info->Damage = CreateDamageFunction(val); + info->SetDamage(val); } else if (linelen == 5) { diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 5d10e0138..e6fd5f16d 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -47,7 +47,7 @@ static void BrainishExplosion (const DVector3 &pos) boom->SetState (state); } boom->effects = 0; - boom->Damage = NULL; // disables collision detection which is not wanted here + boom->SetDamage(0); // disables collision detection which is not wanted here boom->tics -= pr_brainscream() & 7; if (boom->tics < 1) boom->tics = 1; diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index 7f33fb57a..a88748407 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -115,7 +115,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) fire->target = baseFire->target; fire->Angles.Yaw = baseFire->Angles.Yaw; fire->Vel = baseFire->Vel; - fire->Damage = NULL; + fire->SetDamage(0); fire->health = (i+1) * 2; P_CheckMissileSpawn (fire, self->radius); } @@ -205,7 +205,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow) self->AddZ(9.); if (self->health == 0) { - self->Damage = self->GetDefault()->Damage; + self->RestoreDamage(); self->SetState (self->FindState("NoGrow")); } return 0; diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index b5718f4d7..896384f4e 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -340,7 +340,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LastZap) { mo->SetState (mo->FindState (NAME_Death)); mo->Vel.Z = 40; - mo->Damage = NULL; + mo->SetDamage(0); } return 0; } diff --git a/src/info.cpp b/src/info.cpp index 7198a5de4..6eeca1186 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -344,7 +344,7 @@ size_t PClassActor::PropagateMark() // Mark damage function if (Defaults != NULL) { - GC::Mark(((AActor *)Defaults)->Damage); + GC::Mark(((AActor *)Defaults)->DamageFunc); } // marked += ActorInfo->NumOwnedStates * sizeof(FState); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 67ae37771..ffac7a78f 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3791,7 +3791,7 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) break; case APROP_Damage: - actor->Damage = CreateDamageFunction(value); + actor->SetDamage(value); break; case APROP_Alpha: diff --git a/src/p_map.cpp b/src/p_map.cpp index 7316e1c96..5cc9bdf72 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1320,7 +1320,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch // [RH] What is the point of this check, again? In Hexen, it is unconditional, // but here we only do it if the missile's damage is 0. // MBF bouncer might have a non-0 damage value, but they must not deal damage on impact either. - if ((tm.thing->BounceFlags & BOUNCE_Actors) && (tm.thing->Damage == 0 || !(tm.thing->flags & MF_MISSILE))) + if ((tm.thing->BounceFlags & BOUNCE_Actors) && (tm.thing->IsZeroDamage() || !(tm.thing->flags & MF_MISSILE))) { return (tm.thing->target == thing || !(thing->flags & MF_SOLID)); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e93b886e8..d38901f1e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -139,7 +139,7 @@ IMPLEMENT_POINTY_CLASS (AActor) DECLARE_POINTER (LastHeard) DECLARE_POINTER (master) DECLARE_POINTER (Poisoner) - DECLARE_POINTER (Damage) + DECLARE_POINTER (DamageFunc) DECLARE_POINTER (alternative) END_POINTERS @@ -149,73 +149,6 @@ AActor::~AActor () // Use Destroy() instead. } -//========================================================================== -// -// CalcDamageValue -// -// Given a script function, returns an integer to represent it in a -// savegame. This encoding is compatible with previous incarnations -// where damage was an integer. -// -// 0 : use null function -// 0x40000000 : use default function -// anything else : use function that returns this number -// -//========================================================================== - -static int CalcDamageValue(VMFunction *func) -{ - if (func == NULL) - { - return 0; - } - VMScriptFunction *sfunc = dyn_cast(func); - if (sfunc == NULL) - { - return 0x40000000; - } - VMOP *op = sfunc->Code; - // If the function was created by CreateDamageFunction(), extract - // the value used to create it and return that. Otherwise, return - // indicating to use the default function. - if (op->op == OP_RETI && op->a == 0) - { - return op->i16; - } - if (op->op == OP_RET && op->a == 0 && op->b == (REGT_INT | REGT_KONST)) - { - return sfunc->KonstD[op->c]; - } - return 0x40000000; -} - -//========================================================================== -// -// UncalcDamageValue -// -// Given a damage integer, returns a script function for it. -// -//========================================================================== - -static VMFunction *UncalcDamageValue(int dmg, VMFunction *def) -{ - if (dmg == 0) - { - return NULL; - } - if ((dmg & 0xC0000000) == 0x40000000) - { - return def; - } - // Does the default version return this? If so, use it. Otherwise, - // create a new function. - if (CalcDamageValue(def) == dmg) - { - return def; - } - return CreateDamageFunction(dmg); -} - //========================================================================== // // AActor :: Serialize @@ -263,18 +196,16 @@ void AActor::Serialize(FArchive &arc) << projectilepassheight << Vel << tics - << state; - if (arc.IsStoring()) + << state + << DamageVal; + if (DamageVal == 0x40000000 || DamageVal == -1) { - int dmg; - dmg = CalcDamageValue(Damage); - arc << dmg; + DamageVal = -1; + DamageFunc = GetDefault()->DamageFunc; } else { - int dmg; - arc << dmg; - Damage = UncalcDamageValue(dmg, GetDefault()->Damage); + DamageFunc = nullptr; } P_SerializeTerrain(arc, floorterrain); arc << projectileKickback @@ -2975,8 +2906,21 @@ CCMD(utid) int AActor::GetMissileDamage (int mask, int add) { - if (Damage == NULL) + if (DamageVal >= 0) { + if (mask == 0) + { + return add * DamageVal; + } + else + { + return ((pr_missiledamage() & mask) + add) * DamageVal; + } + } + if (DamageFunc == nullptr) + { + // This should never happen + assert(false && "No damage function found"); return 0; } VMFrameStack stack; @@ -2988,22 +2932,11 @@ int AActor::GetMissileDamage (int mask, int add) results[0].IntAt(&amount); results[1].IntAt(&calculated); - if (stack.Call(Damage, ¶m, 1, results, 2) < 1) + if (stack.Call(DamageFunc, ¶m, 1, results, 2) < 1) { // No results return 0; } - if (calculated) - { - return amount; - } - else if (mask == 0) - { - return add * amount; - } - else - { - return ((pr_missiledamage() & mask) + add) * amount; - } + return amount; } void AActor::Howl () @@ -3695,7 +3628,7 @@ void AActor::Tick () // still have missiles that go straight up and down through actors without // damaging anything. // (for backwards compatibility this must check for lack of damage function, not for zero damage!) - if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && Damage != NULL) + if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && !IsZeroDamage()) { Vel.X = MinVel; } diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 5fa994262..3ea0c4788 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -496,8 +496,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Projectile && sc.Compare ("Damage")) { sc.MustGetNumber (); - FxDamageValue *x = new FxDamageValue(new FxConstant(sc.Number, sc), false); - defaults->Damage = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(x) + 1); + defaults->SetDamage(sc.Number); } else if (def == DEF_Projectile && sc.Compare ("DamageType")) { diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index dfc960627..635637149 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -348,12 +348,12 @@ static void FinishThingdef() continue; } - if (def->Damage != NULL) + if (def->DamageFunc != nullptr) { - FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->Damage - 1]; + FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->DamageFunc - 1]; VMScriptFunction *sfunc; sfunc = dmg->GetFunction(); - if (sfunc == NULL) + if (sfunc == nullptr) { FCompileContext ctx(ti); dmg = static_cast(dmg->Resolve(ctx)); @@ -365,15 +365,15 @@ static void FinishThingdef() dmg->Emit(&buildit); sfunc = buildit.MakeFunction(); sfunc->NumArgs = 1; - sfunc->Proto = NULL; ///FIXME: Need a proper prototype here + sfunc->Proto = nullptr; ///FIXME: Need a proper prototype here // Save this function in case this damage value was reused // (which happens quite easily with inheritance). dmg->SetFunction(sfunc); } } - def->Damage = sfunc; + def->DamageFunc = sfunc; - if (dump != NULL && sfunc != NULL) + if (dump != nullptr && sfunc != nullptr) { char label[64]; int labellen = mysnprintf(label, countof(label), "Function %s.Damage", diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 756c56a1a..8248634a3 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -666,4 +666,5 @@ void InitThingdef() symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed))); symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold))); symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold))); + symt.AddSymbol(new PField(NAME_Damage, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DamageVal))); } diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 2f06e085e..5fe8f252f 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -854,20 +854,6 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; -//========================================================================== -// -// FxDamage -// -//========================================================================== - -class FxDamage : public FxExpression -{ -public: - FxDamage(const FScriptPosition&); - FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); -}; - //========================================================================== // // FxArrayElement @@ -1188,12 +1174,11 @@ public: class FxDamageValue : public FxExpression { FxExpression *val; - bool Calculated; VMScriptFunction *MyFunction; public: - FxDamageValue(FxExpression *v, bool calc); + FxDamageValue(FxExpression *v); ~FxDamageValue(); FxExpression *Resolve(FCompileContext&); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 034c304c2..ce603f261 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3218,11 +3218,6 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars()); } } - // the damage property needs special handling - else if (Identifier == NAME_Damage) - { - newex = new FxDamage(ScriptPosition); - } // now check the global identifiers. else if ((sym = ctx.FindGlobal(Identifier)) != NULL) { @@ -3316,65 +3311,6 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build) } -//========================================================================== -// -// -// -//========================================================================== - -FxDamage::FxDamage(const FScriptPosition &pos) -: FxExpression(pos) -{ -} - -//========================================================================== -// -// FxDamage :: Resolve -// -//========================================================================== - -FxExpression *FxDamage::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - ValueType = TypeSInt32; - return this; -} - -//========================================================================== -// -// FxDamage :: Emit -// -// Call this actor's damage function, if it has one -// -//========================================================================== - -ExpEmit FxDamage::Emit(VMFunctionBuilder *build) -{ - ExpEmit dmgval(build, REGT_INT); - - // Get damage function - ExpEmit dmgfunc(build, REGT_POINTER); - build->Emit(OP_LO, dmgfunc.RegNum, 0/*self*/, build->GetConstantInt(myoffsetof(AActor, Damage))); - - // If it's non-null... - build->Emit(OP_EQA_K, 1, dmgfunc.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC)); - size_t nulljump = build->Emit(OP_JMP, 0); - - // ...call it - build->Emit(OP_PARAM, 0, REGT_POINTER, 0/*self*/); - build->Emit(OP_CALL, dmgfunc.RegNum, 1, 1); - build->Emit(OP_RESULT, 0, REGT_INT, dmgval.RegNum); - size_t notnulljump = build->Emit(OP_JMP, 0); - - // Otherwise, use 0 - build->BackpatchToHere(nulljump); - build->EmitLoadInt(dmgval.RegNum, 0); - build->BackpatchToHere(notnulljump); - - return dmgval; -} - - //========================================================================== // // @@ -5225,18 +5161,12 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) // //========================================================================== -FxDamageValue::FxDamageValue(FxExpression *v, bool calc) +FxDamageValue::FxDamageValue(FxExpression *v) : FxExpression(v->ScriptPosition) { val = v; ValueType = TypeVoid; - Calculated = calc; MyFunction = NULL; - - if (!calc) - { - assert(v->isConstant() && "Non-calculated damage must be constant"); - } } FxDamageValue::~FxDamageValue() @@ -5272,7 +5202,7 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) assert(emitval.RegType == REGT_INT); build->Emit(OP_RET, 0, REGT_INT | (emitval.Konst ? REGT_KONST : 0), emitval.RegNum); } - build->Emit(OP_RETI, 1 | RET_FINAL, Calculated); + build->Emit(OP_RETI, 1 | RET_FINAL, true); return ExpEmit(); } diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index b99f1a384..963165ab1 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -865,19 +865,21 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau if (sc.CheckString ("(")) { - x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info)), true); + conv.i = -1; + params.Push(conv); + x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info))); sc.MustGetStringName(")"); + conv.exp = x; + params.Push(conv); + } else { sc.MustGetNumber(); - if (sc.Number != 0) - { - x = new FxDamageValue(new FxConstant(sc.Number, bag.ScriptPosition), false); - } + conv.i = sc.Number; + params.Push(conv); + conv.exp = nullptr; } - conv.exp = x; - params.Push(conv); } break; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index f6ad511af..52194435b 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -636,7 +636,8 @@ DEFINE_PROPERTY(threshold, I, Actor) //========================================================================== DEFINE_PROPERTY(damage, X, Actor) { - PROP_EXP_PARM(id, 0); + PROP_INT_PARM(dmgval, 0); + PROP_EXP_PARM(id, 1); // Damage can either be a single number, in which case it is subject // to the original damage calculation rules. Or, it can be an expression @@ -646,13 +647,15 @@ DEFINE_PROPERTY(damage, X, Actor) // Store this expression here for now. It will be converted to a function // later once all actors have been processed. - if (id == NULL) + defaults->DamageVal = dmgval; + + if (id == nullptr) { - defaults->Damage = NULL; + defaults->DamageFunc = nullptr; } else { - defaults->Damage = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1); + defaults->DamageFunc = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1); } } From 3eb1af6957541fa8ac021d9aa8aaf8218e8c9d6a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 19 Sep 2016 03:45:22 +0200 Subject: [PATCH 97/97] - added a GetMissileDamage function to DECORATE which can be used to properly retrieve an actor's damage value. The damage property should be considered deprecated inside expressions from now on. --- src/thingdef/thingdef_codeptr.cpp | 32 +++++++++++++++++++++++++++++++ wadsrc/static/actors/actor.txt | 1 + 2 files changed, 33 insertions(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 642f132af..21551364b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -231,6 +231,38 @@ DEFINE_ACTION_FUNCTION(AActor, CheckClass) return 0; } +//========================================================================== +// +// CheckClass +// +// NON-ACTION function to calculate missile damage for the given actor +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, GetMissileDamage) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(mask); + PARAM_INT(add) + PARAM_INT_OPT(pick_pointer) { pick_pointer = AAPTR_DEFAULT; } + + self = COPY_AAPTR(self, pick_pointer); + if (self == NULL) + { + ret->SetInt(0); + } + else + { + ret->SetInt(self->GetMissileDamage(mask, add)); + } + return 1; + } + return 0; +} + //========================================================================== // // IsPointerEqual diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index b8bbcab14..b8b805219 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -53,6 +53,7 @@ ACTOR Actor native //: Thinker native int CountProximity(class classname, float distance, int flags = 0, int ptr = AAPTR_DEFAULT); native float GetSpriteAngle(int ptr = AAPTR_DEFAULT); native float GetSpriteRotation(int ptr = AAPTR_DEFAULT); + native int GetMissileDamage(int mask, int add, int ptr = AAPTR_DEFAULT); // Action functions // Meh, MBF redundant functions. Only for DeHackEd support.