From 6665ac583728033c6cfa09eb9ec4dc1c8544ac7e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 25 Nov 2014 16:49:27 +0100 Subject: [PATCH 01/32] - fixed: With P_ExplodeMissile now working properly it is no longer valid to terminate a looping sound in a missile's death state because it now gets called after the death sound has been started. --- wadsrc/static/actors/strife/crusader.txt | 2 +- wadsrc/static/actors/strife/strifebishop.txt | 2 +- wadsrc/static/actors/strife/strifeweapons.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wadsrc/static/actors/strife/crusader.txt b/wadsrc/static/actors/strife/crusader.txt index 7f7a0d0c5..eb1ceec6d 100644 --- a/wadsrc/static/actors/strife/crusader.txt +++ b/wadsrc/static/actors/strife/crusader.txt @@ -99,7 +99,7 @@ ACTOR CrusaderMissile Loop Death: SMIS A 0 Bright A_SetTranslucent(1,1) - SMIS A 5 Bright A_StopSoundEx("Voice") + SMIS A 5 Bright SMIS B 5 Bright SMIS C 4 Bright SMIS DEFG 2 Bright diff --git a/wadsrc/static/actors/strife/strifebishop.txt b/wadsrc/static/actors/strife/strifebishop.txt index dcedf7f58..6f38247fb 100644 --- a/wadsrc/static/actors/strife/strifebishop.txt +++ b/wadsrc/static/actors/strife/strifebishop.txt @@ -85,7 +85,7 @@ ACTOR BishopMissile Loop Death: SMIS A 0 Bright A_SetTranslucent(1,1) - SMIS A 0 Bright A_StopSoundEx("Voice") + SMIS A 0 Bright // State left for savegame compatibility SMIS A 5 Bright A_Explode(64,64,1,1) SMIS B 5 Bright SMIS C 4 Bright diff --git a/wadsrc/static/actors/strife/strifeweapons.txt b/wadsrc/static/actors/strife/strifeweapons.txt index deea01a52..3b256e226 100644 --- a/wadsrc/static/actors/strife/strifeweapons.txt +++ b/wadsrc/static/actors/strife/strifeweapons.txt @@ -390,7 +390,7 @@ ACTOR MiniMissile Loop Death: SMIS A 0 Bright A_SetTranslucent(1,1) - SMIS A 0 Bright A_StopSoundEx("Voice") + SMIS A 0 Bright // State left for savegame compatibility SMIS A 5 Bright A_Explode(64,64,1,1) SMIS B 5 Bright SMIS C 4 Bright From 29ecbac96378dc1e5b43d640e12d5f27819b2620 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 25 Nov 2014 17:00:17 +0100 Subject: [PATCH 02/32] - fixed: The demo buffer was allocated with conflicting methods, because M_ReadFile used new whereas the rest of the demo code assumed malloc. Added a new M_ReadFileMalloc function to handle this case without rewriting other things. --- src/g_game.cpp | 2 +- src/m_misc.cpp | 26 ++++++++++++++++++++++++++ src/m_misc.h | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 734500e55..beec9435a 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2636,7 +2636,7 @@ void G_DoPlayDemo (void) { FixPathSeperator (defdemoname); DefaultExtension (defdemoname, ".lmp"); - M_ReadFile (defdemoname, &demobuffer); + M_ReadFileMalloc (defdemoname, &demobuffer); } demo_p = demobuffer; diff --git a/src/m_misc.cpp b/src/m_misc.cpp index c550c4593..7f4fa482d 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -137,6 +137,32 @@ int M_ReadFile (char const *name, BYTE **buffer) return length; } +// +// M_ReadFile (same as above but use malloc instead of new to allocate the buffer.) +// +int M_ReadFileMalloc (char const *name, BYTE **buffer) +{ + int handle, count, length; + struct stat fileinfo; + BYTE *buf; + + handle = open (name, O_RDONLY | O_BINARY, 0666); + if (handle == -1) + I_Error ("Couldn't read file %s", name); + if (fstat (handle,&fileinfo) == -1) + I_Error ("Couldn't read file %s", name); + length = fileinfo.st_size; + buf = (BYTE*)M_Malloc(length); + count = read (handle, buf, length); + close (handle); + + if (count < length) + I_Error ("Couldn't read file %s", name); + + *buffer = buf; + return length; +} + //--------------------------------------------------------------------------- // // PROC M_FindResponseFile diff --git a/src/m_misc.h b/src/m_misc.h index 90844221f..9599306de 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -33,6 +33,7 @@ extern FGameConfigFile *GameConfig; bool M_WriteFile (char const *name, void *source, int length); int M_ReadFile (char const *name, BYTE **buffer); +int M_ReadFileMalloc (char const *name, BYTE **buffer); void M_FindResponseFile (void); // [RH] M_ScreenShot now accepts a filename parameter. From cc4e66f976ab93c6d88d8721b3011238a551fe26 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 25 Nov 2014 16:44:12 +0100 Subject: [PATCH 03/32] - Fix the division by 0, improve comments. - Avoid doing the division if the result would be outside the ]0,1<<24[ range: -- if the numerator is nonpositive, ie <=0, truncate the result to 0, -- if the numerator is greater or equal than the denominator, the result will be outside the allowed range, hence truncate the result to 1<<24. -- otherwise, the result will be inside the range. Knowing that the denominator is greater than the numerator, if the numerator has the last 24 bits non zero, the denominator can't be less than 1<<24, hence the denominator won't be truncated to 0. - Add comment details to help who doesn't know math. Big deal! --- src/p_map.cpp | 56 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index c0e5c3baa..b3718ce71 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -737,18 +737,50 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) { // Find the point on the line closest to the actor's center, and use // that to calculate openings // [EP] Use 64 bit integers in order to keep the exact result of the - // multiplication, because in the worst case, which is by the map limit - // (32767 units, which is 2147418112 in fixed_t notation), the result - // would occupy 62 bits (if I consider also the addition with another - // and possible 62 bit value, it's 63 bits). - // This privilege could not be available if the starting data would be - // 64 bit long. - // With this, the division is exact as the 32 bit float counterpart, - // though I don't know why I had to discard the first 24 bits from the - // divisor. - SQWORD r_num = ((SQWORD(tm.x - ld->v1->x)*ld->dx) + (SQWORD(tm.y - ld->v1->y)*ld->dy)); - SQWORD r_den = (SQWORD(ld->dx)*ld->dx + SQWORD(ld->dy)*ld->dy) / (1 << 24); - fixed_t r = (fixed_t)(r_num / r_den); + // multiplication, because in the case the vertexes have both the + // distance coordinates equal to the map limit (32767 units, which is + // 2147418112 in fixed_t notation), the product result would occupy + // 62 bits and the sum of two products would occupy 63 bits + // in the worst case. If instead the vertexes are very close (1 in + // fixed_t notation, which is 1.52587890625e-05 in float notation), the + // product and the sum can be 1 in the worst case, which is very tiny. + SQWORD r_num = ((SQWORD(tm.x - ld->v1->x)*ld->dx) + + (SQWORD(tm.y - ld->v1->y)*ld->dy)); + // The denominator is always positive. Use this to avoid useless + // calculations. + SQWORD r_den = (SQWORD(ld->dx)*ld->dx + SQWORD(ld->dy)*ld->dy); + fixed_t r = 0; + if (r_num <= 0) { + // [EP] The numerator is less or equal to zero, hence the closest + // point on the line is the first vertex. Truncate the result to 0. + r = 0; + } else if (r_num >= r_den) { + // [EP] The division is greater or equal to 1, hence the closest + // point on the line is the second vertex. Truncate the result to + // 1 << 24. + r = (1 << 24); + } else { + // [EP] Deal with the limited bits. The original formula is: + // r = (r_num << 24) / r_den, + // but r_num might be big enough to make the shift overflow. + // Since the numerator can't be saved in a 128bit integer, + // the denominator must be right shifted. If the denominator is + // less than (1 << 24), there would be a division by zero. + // Thanks to the fact that in this code path the denominator is less + // than the numerator, it's possible to avoid this bad situation by + // just checking the last 24 bits of the numerator. + if ((r_num >> (63-24)) != 0) { + // [EP] In fact, if the numerator is greater than + // (1 << (63-24)), the denominator must be greater than + // (1 << (63-24)), hence the denominator won't be zero after + // the right shift by 24 places. + r = (r_num)/(r_den >> 24); + } else { + // [EP] Having the last 24 bits all zero allows right shifting + // the numerator by 24 bits. + r = (r_num << 24)/r_den; + } + } /* Printf ("%d:%d: %d (%d %d %d %d) (%d %d %d %d)\n", level.time, ld-lines, r, ld->frontsector->floorplane.a, ld->frontsector->floorplane.b, From 8fbed78c21b2b8dce13fa3fbc1b434d34c7d71e8 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 25 Nov 2014 19:15:25 +0100 Subject: [PATCH 04/32] - Add new function for the new slope calculations. Fixed also two MSVC warnings. --- src/p_map.cpp | 110 +++++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index b3718ce71..604015700 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -74,6 +74,69 @@ TArray spechit; // Temporary holder for thing_sectorlist threads msecnode_t* sector_list = NULL; // phares 3/16/98 +//========================================================================== +// +// GetCoefficientClosestPointInLine24 +// +// Formula: (dotProduct(ldv1 - tm, ld) << 24) / dotProduct(ld, ld) +// with: ldv1 = (ld->v1->x, ld->v1->y), tm = (tm.x, tm.y) +// and ld = (ld->dx, ld->dy) +// Returns truncated to range [0, 1 << 24]. +// +//========================================================================== + +static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm) +{ + // [EP] Use 64 bit integers in order to keep the exact result of the + // multiplication, because in the case the vertexes have both the + // distance coordinates equal to the map limit (32767 units, which is + // 2147418112 in fixed_t notation), the product result would occupy + // 62 bits and the sum of two products would occupy 63 bits + // in the worst case. If instead the vertexes are very close (1 in + // fixed_t notation, which is 1.52587890625e-05 in float notation), the + // product and the sum can be 1 in the worst case, which is very tiny. + + SQWORD r_num = ((SQWORD(tm.x - ld->v1->x)*ld->dx) + + (SQWORD(tm.y - ld->v1->y)*ld->dy)); + + // The denominator is always positive. Use this to avoid useless + // calculations. + SQWORD r_den = (SQWORD(ld->dx)*ld->dx + SQWORD(ld->dy)*ld->dy); + + if (r_num <= 0) { + // [EP] The numerator is less or equal to zero, hence the closest + // point on the line is the first vertex. Truncate the result to 0. + return 0; + } + + if (r_num >= r_den) { + // [EP] The division is greater or equal to 1, hence the closest + // point on the line is the second vertex. Truncate the result to + // 1 << 24. + return (1 << 24); + } + + // [EP] Deal with the limited bits. The original formula is: + // r = (r_num << 24) / r_den, + // but r_num might be big enough to make the shift overflow. + // Since the numerator can't be saved in a 128bit integer, + // the denominator must be right shifted. If the denominator is + // less than (1 << 24), there would be a division by zero. + // Thanks to the fact that in this code path the denominator is greater + // than the numerator, it's possible to avoid this bad situation by + // just checking the last 24 bits of the numerator. + if ((r_num >> (63-24)) != 0) { + // [EP] In fact, if the numerator is greater than + // (1 << (63-24)), the denominator must be greater than + // (1 << (63-24)), hence the denominator won't be zero after + // the right shift by 24 places. + return (fixed_t)(r_num/(r_den >> 24)); + } + // [EP] Having the last 24 bits all zero allows right shifting + // the numerator by 24 bits. + return (fixed_t)((r_num << 24)/r_den); +} + //========================================================================== // // PIT_FindFloorCeiling @@ -736,51 +799,8 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) else { // Find the point on the line closest to the actor's center, and use // that to calculate openings - // [EP] Use 64 bit integers in order to keep the exact result of the - // multiplication, because in the case the vertexes have both the - // distance coordinates equal to the map limit (32767 units, which is - // 2147418112 in fixed_t notation), the product result would occupy - // 62 bits and the sum of two products would occupy 63 bits - // in the worst case. If instead the vertexes are very close (1 in - // fixed_t notation, which is 1.52587890625e-05 in float notation), the - // product and the sum can be 1 in the worst case, which is very tiny. - SQWORD r_num = ((SQWORD(tm.x - ld->v1->x)*ld->dx) + - (SQWORD(tm.y - ld->v1->y)*ld->dy)); - // The denominator is always positive. Use this to avoid useless - // calculations. - SQWORD r_den = (SQWORD(ld->dx)*ld->dx + SQWORD(ld->dy)*ld->dy); - fixed_t r = 0; - if (r_num <= 0) { - // [EP] The numerator is less or equal to zero, hence the closest - // point on the line is the first vertex. Truncate the result to 0. - r = 0; - } else if (r_num >= r_den) { - // [EP] The division is greater or equal to 1, hence the closest - // point on the line is the second vertex. Truncate the result to - // 1 << 24. - r = (1 << 24); - } else { - // [EP] Deal with the limited bits. The original formula is: - // r = (r_num << 24) / r_den, - // but r_num might be big enough to make the shift overflow. - // Since the numerator can't be saved in a 128bit integer, - // the denominator must be right shifted. If the denominator is - // less than (1 << 24), there would be a division by zero. - // Thanks to the fact that in this code path the denominator is less - // than the numerator, it's possible to avoid this bad situation by - // just checking the last 24 bits of the numerator. - if ((r_num >> (63-24)) != 0) { - // [EP] In fact, if the numerator is greater than - // (1 << (63-24)), the denominator must be greater than - // (1 << (63-24)), hence the denominator won't be zero after - // the right shift by 24 places. - r = (r_num)/(r_den >> 24); - } else { - // [EP] Having the last 24 bits all zero allows right shifting - // the numerator by 24 bits. - r = (r_num << 24)/r_den; - } - } + fixed_t r = GetCoefficientClosestPointInLine24(ld, tm); + /* Printf ("%d:%d: %d (%d %d %d %d) (%d %d %d %d)\n", level.time, ld-lines, r, ld->frontsector->floorplane.a, ld->frontsector->floorplane.b, From 629f3c1a8acd25affcd201ec36d9192d1c66565d Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 25 Nov 2014 19:22:56 +0100 Subject: [PATCH 05/32] - Oops comment typo. --- src/p_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 604015700..3097ae824 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -132,8 +132,8 @@ static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm // the right shift by 24 places. return (fixed_t)(r_num/(r_den >> 24)); } - // [EP] Having the last 24 bits all zero allows right shifting - // the numerator by 24 bits. + // [EP] Having the last 24 bits all zero allows left shifting + // the numerator by 24 bits without overflow. return (fixed_t)((r_num << 24)/r_den); } From 08570ec48ead6dfd77a9f58dc3897ff045a64a34 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 25 Nov 2014 13:24:35 -0600 Subject: [PATCH 06/32] - Added flags for A_Fade functions: - FTF_REMOVE: Removes the actor when the alpha hits a certain level. - - A_FadeIn - 1.0 - - A_FadeOut - 0.0 - - A_FadeTo - Alpha target level reached - FTF_CLAMP: Automatically fixes the alpha so it won't leave the range [0.0, 1.0]. --- src/thingdef/thingdef_codeptr.cpp | 39 ++++++++++++++++++++++++------ wadsrc/static/actors/actor.txt | 6 ++--- wadsrc/static/actors/constants.txt | 7 ++++++ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index a668e589b..5629edd9e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2354,18 +2354,33 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) // Fades the actor in // //=========================================================================== + +enum FadeFlags +{ + FTF_REMOVE = 1 << 0, + FTF_CLAMP = 1 << 1, +}; + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) { ACTION_PARAM_START(1); ACTION_PARAM_FIXED(reduce, 0); + ACTION_PARAM_INT(flags, 1); if (reduce == 0) { - reduce = FRACUNIT/10; + reduce = FRACUNIT / 10; } self->RenderStyle.Flags &= ~STYLEF_Alpha1; self->alpha += reduce; - // Should this clamp alpha to 1.0? + + if (self->alpha >= (FRACUNIT * 1)) + { + if (flags & FTF_CLAMP) + self->alpha = (FRACUNIT * 1); + if (flags & FTF_REMOVE) + self->Destroy(); + } } //=========================================================================== @@ -2379,7 +2394,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) { ACTION_PARAM_START(2); ACTION_PARAM_FIXED(reduce, 0); - ACTION_PARAM_BOOL(remove, 1); + ACTION_PARAM_INT(flags, 1); if (reduce == 0) { @@ -2387,9 +2402,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) } self->RenderStyle.Flags &= ~STYLEF_Alpha1; self->alpha -= reduce; - if (self->alpha <= 0 && remove) + if (self->alpha <= 0) { - self->Destroy(); + if (flags & FTF_CLAMP) + self->alpha = 0; + if (flags & FTF_REMOVE) + self->Destroy(); } } @@ -2406,7 +2424,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) ACTION_PARAM_START(3); ACTION_PARAM_FIXED(target, 0); ACTION_PARAM_FIXED(amount, 1); - ACTION_PARAM_BOOL(remove, 2); + ACTION_PARAM_INT(flags, 2); self->RenderStyle.Flags &= ~STYLEF_Alpha1; @@ -2428,7 +2446,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) self->alpha = target; } } - if (self->alpha == target && remove) + if (flags & FTF_CLAMP) + { + if (self->alpha > (FRACUNIT * 1)) + self->alpha = (FRACUNIT * 1); + else if (self->alpha < 0) + self->alpha = 0; + } + if (self->alpha == target && (flags & FTF_REMOVE)) { self->Destroy(); } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 468b0f7b5..c8e689dae 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -222,9 +222,9 @@ ACTOR Actor native //: Thinker action native A_Log(string whattoprint); action native A_LogInt(int whattoprint); action native A_SetTranslucent(float alpha, int style = 0); - action native A_FadeIn(float reduce = 0.1); - action native A_FadeOut(float reduce = 0.1, bool remove = true); - action native A_FadeTo(float target, float amount = 0.1, bool remove = false); + action native A_FadeIn(float reduce = 0.1, int flags = 0); + action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true + action native A_FadeTo(float target, float amount = 0.1, int flags = 0); action native A_SetScale(float scalex, float scaley = 0); action native A_SetMass(int mass); action native A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index d9da11b2d..22914fbfc 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -405,6 +405,13 @@ enum RMVF_EVERYTHING = 1 << 3, }; +// Flags for A_Fade* +enum +{ + FTF_REMOVE = 1 << 0, + FTF_CLAMP = 1 << 1, +}; + // This is only here to provide one global variable for testing. native int testglobalvar; From e1fdcdfb93c532e5f32d53a02ccf36773bb23784 Mon Sep 17 00:00:00 2001 From: khokh2001 Date: Fri, 28 Nov 2014 04:07:33 +0900 Subject: [PATCH 07/32] opl3 emulator update --- src/oplsynth/nukedopl3.cpp | 1222 ++++++++++++++++-------------------- src/oplsynth/nukedopl3.h | 222 +++++-- 2 files changed, 695 insertions(+), 749 deletions(-) diff --git a/src/oplsynth/nukedopl3.cpp b/src/oplsynth/nukedopl3.cpp index 90673d855..a520f68e1 100644 --- a/src/oplsynth/nukedopl3.cpp +++ b/src/oplsynth/nukedopl3.cpp @@ -23,11 +23,11 @@ Feedback and Rhythm part calculation information. forums.submarine.org.uk(carbon14, opl3): Tremolo and phase generator calculation information. - OPLx decapsulated(Matthew Gambrell and Olli Niemitalo): + OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): OPL2 ROMs. */ -//version 1.4.2 +//version 1.5 /* Changelog: v1.1: @@ -52,6 +52,8 @@ (Not released) v1.4.2: Version for ZDoom. + v1.5: + Optimizations */ @@ -78,152 +80,17 @@ #include #include "nukedopl3.h" -// Channel types - -enum { - ch_4op2, - ch_2op, - ch_4op, - ch_drum -}; - -// Envelope generator states - -enum { - eg_off, - eg_attack, - eg_decay, - eg_sustain, - eg_release -}; - -// Envelope key types - -enum { - egk_norm = 1, - egk_drum = 2 -}; - -// -// logsin table -// - -static const Bit16u logsinrom[256] = { - 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, - 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, - 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, - 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, - 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, - 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, - 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, - 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, - 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, - 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, - 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, - 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, - 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, - 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, - 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, - 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 -}; - -// -// exp table -// - -static const Bit16u exprom[256] = { - 0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a, - 0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a, - 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b, - 0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be, - 0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4, - 0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c, - 0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167, - 0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4, - 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4, - 0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227, - 0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d, - 0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5, - 0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302, - 0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351, - 0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4, - 0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa -}; - -// -// freq mult table multiplied by 2 -// -// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 -// - -static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 }; - -// -// ksl table -// - -static const Bit8u kslrom[16] = { 0, 64, 80, 90, 96, 102, 106, 110, 112, 116, 118, 120, 122, 124, 126, 127 }; - -static const Bit8u kslshift[4] = { 8, 1, 2, 0 }; - -// -// LFO vibrato -// - -static const Bit8u vib_table[8] = { 3, 1, 0, 1, 3, 1, 0, 1 }; -static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 }; - -// -// envelope generator constants -// - -static const Bit8u eg_incstep[3][4][8] = { - { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, - { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 1, 1, 0, 1 }, { 1, 1, 1, 1, 1, 1, 0, 1 } }, - { { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } } -}; - -// -// address decoding -// - -static const Bit8s ad_slot[0x20] = { 0, 2, 4, 1, 3, 5, -1, -1, 6, 8, 10, 7, 9, 11, -1, -1, 12, 14, 16, 13, 15, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - -static const Bit8u op_offset[18] = { 0x00, 0x03, 0x01, 0x04, 0x02, 0x05, 0x08, 0x0b, 0x09, 0x0c, 0x0a, 0x0d, 0x10, 0x13, 0x11, 0x14, 0x12, 0x15 }; - - - -static const Bit8u eg_incdesc[16] = { - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2 -}; - -static const Bit8s eg_incsh[16] = { - 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2 -}; - -typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); -typedef void(*envelope_genfunc)(slot *slott); - -// -// Phase generator -// - -void PG_Generate(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - channel *chan = &opl->Channels[op / 2]; - Bit16u fnum = chan->f_number; - if (slt->vibrato) { - Bit8u fnum_high = chan->f_number >> (7 + vib_table[opl->vib_pos] + (!opl->dvb)); - fnum += fnum_high * vibsgn_table[opl->vib_pos]; - } - slt->PG_pos += (((fnum << chan->block) >> 1) * mt[slt->mult]) >> 1; -} - // // Envelope generator // +typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); +typedef void(*envelope_genfunc)(opl_slot *slott); + Bit16s envelope_calcexp(Bit32u level) { + if (level > 0x1fff) { + level = 0x1fff; + } return ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 1) >> (level >> 8); } @@ -352,12 +219,12 @@ envelope_sinfunc envelope_sin[8] = { envelope_calcsin7 }; -void envelope_gen_off(slot *slott); -void envelope_gen_change(slot *slott); -void envelope_gen_attack(slot *slott); -void envelope_gen_decay(slot *slott); -void envelope_gen_sustain(slot *slott); -void envelope_gen_release(slot *slott); +void envelope_gen_off(opl_slot *slott); +void envelope_gen_change(opl_slot *slott); +void envelope_gen_attack(opl_slot *slott); +void envelope_gen_decay(opl_slot *slott); +void envelope_gen_sustain(opl_slot *slott); +void envelope_gen_release(opl_slot *slott); envelope_genfunc envelope_gen[6] = { envelope_gen_off, @@ -377,222 +244,215 @@ enum envelope_gen_num { envelope_gen_num_change = 5 }; -void envelope_gen_off(slot *slott) { - slott->EG_out = 0x1ff; -} - -void envelope_gen_change(slot *slott) { - slott->eg_gen = slott->eg_gennext; -} - -void envelope_gen_attack(slot *slott) { - slott->EG_out += ((~slott->EG_out) *slott->eg_inc) >> 3; - if (slott->EG_out < 0x00) { - slott->EG_out = 0x00; - } - if (slott->EG_out == 0x00) { - slott->eg_gen = envelope_gen_num_change; - slott->eg_gennext = envelope_gen_num_decay; - } -} - -void envelope_gen_decay(slot *slott) { - slott->EG_out += slott->eg_inc; - if (slott->EG_out >= slott->EG_sl << 4) { - slott->eg_gen = envelope_gen_num_change; - slott->eg_gennext = envelope_gen_num_sustain; - } -} - -void envelope_gen_sustain(slot *slott) { - if (!slott->EG_type) { - envelope_gen_release(slott); - } -} - -void envelope_gen_release(slot *slott) { - slott->EG_out += slott->eg_inc; - if (slott->EG_out >= 0x1ff) { - slott->eg_gen = envelope_gen_num_change; - slott->eg_gennext = envelope_gen_num_off; - } -} - -Bit8u EG_CalcRate(chip *opl, Bit8u op, Bit8u rate) { - slot *slt = &opl->OPs[op]; - channel *chan = &opl->Channels[op / 2]; - if (rate == 0x00) { +Bit8u envelope_calc_rate(opl_slot *slot, Bit8u reg_rate) { + if (reg_rate == 0x00) { return 0x00; } - Bit8u rof = slt->ksr ? chan->ksv : (chan->ksv >> 2); - Bit8u rat = (rate << 2) + rof; - if (rat > 0x3c) { - rat = 0x3c; + Bit8u rate = (reg_rate << 2) + (slot->reg_ksr ? slot->channel->ksv : (slot->channel->ksv >> 2)); + if (rate > 0x3c) { + rate = 0x3c; } - return rat; + return rate; } -void envelope_calc(chip *opl, Bit8u op) { - slot *slott = &opl->OPs[op]; - Bit16u timer = opl->timer; - Bit8u rate_h, rate_l; - Bit8u rate; - Bit8u reg_rate = 0;; - switch (slott->eg_gen) { +void envelope_update_ksl(opl_slot *slot) { + Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 1) - ((slot->channel->block ^ 0x07) << 5) - 0x20; + if (ksl < 0) { + ksl = 0; + } + slot->eg_ksl = (Bit8u)ksl; +} + +void envelope_update_rate(opl_slot *slot) { + switch (slot->eg_gen) { + case envelope_gen_num_off: + slot->eg_rate = 0; + break; case envelope_gen_num_attack: - reg_rate = slott->EG_ar; + slot->eg_rate = envelope_calc_rate(slot, slot->reg_ar); break; case envelope_gen_num_decay: - reg_rate = slott->EG_dr; + slot->eg_rate = envelope_calc_rate(slot, slot->reg_dr); break; case envelope_gen_num_sustain: case envelope_gen_num_release: - reg_rate = slott->EG_rr; + slot->eg_rate = envelope_calc_rate(slot, slot->reg_rr); break; } - rate = EG_CalcRate(opl, op, reg_rate); - rate_h = rate >> 2; - rate_l = rate & 3; +} + +void envelope_gen_off(opl_slot *slot) { + slot->eg_rout = 0x1ff; +} + +void envelope_gen_change(opl_slot *slot) { + slot->eg_gen = slot->eg_gennext; + envelope_update_rate(slot); +} + +void envelope_gen_attack(opl_slot *slot) { + slot->eg_rout += ((~slot->eg_rout) *slot->eg_inc) >> 3; + if (slot->eg_rout < 0x00) { + slot->eg_rout = 0x00; + } + if (!slot->eg_rout) { + slot->eg_gen = envelope_gen_num_change; + slot->eg_gennext = envelope_gen_num_decay; + } +} + +void envelope_gen_decay(opl_slot *slot) { + slot->eg_rout += slot->eg_inc; + if (slot->eg_rout >= slot->reg_sl << 4) { + slot->eg_gen = envelope_gen_num_change; + slot->eg_gennext = envelope_gen_num_sustain; + } +} + +void envelope_gen_sustain(opl_slot *slot) { + if (!slot->reg_type) { + envelope_gen_release(slot); + } +} + +void envelope_gen_release(opl_slot *slot) { + slot->eg_rout += slot->eg_inc; + if (slot->eg_rout >= 0x1ff) { + slot->eg_gen = envelope_gen_num_change; + slot->eg_gennext = envelope_gen_num_off; + } +} + +void envelope_calc(opl_slot *slot) { + Bit8u rate_h, rate_l; + rate_h = slot->eg_rate >> 2; + rate_l = slot->eg_rate & 3; Bit8u inc = 0; - if (slott->eg_gen == envelope_gen_num_attack && rate_h == 0x0f) { + if (slot->eg_gen == envelope_gen_num_attack && rate_h == 0x0f) { inc = 8; } else if (eg_incsh[rate_h] > 0) { - if ((timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l][((timer) >> eg_incsh[rate_h]) & 0x07]; + if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) { + inc = eg_incstep[eg_incdesc[rate_h]][rate_l][((slot->chip->timer) >> eg_incsh[rate_h]) & 0x07]; } } else { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l][timer & 0x07] << (-eg_incsh[rate_h]); + inc = eg_incstep[eg_incdesc[rate_h]][rate_l][slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); } - slott->eg_inc = inc; - envelope_gen[slott->eg_gen](slott); + slot->eg_inc = inc; + envelope_gen[slot->eg_gen](slot); + slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; } -void EG_UpdateKSL(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - channel *chan = &opl->Channels[op / 2]; - Bit8u fnum_high = (chan->f_number >> 6) & 0x0f; - Bit16s ksl = (kslrom[fnum_high] << 1) - ((chan->block ^ 0x07) << 5) - 0x20; - if (ksl < 0x00) { - ksl = 0x00; +void eg_keyon(opl_slot *slot, Bit8u type) { + if (!slot->key) { + slot->eg_gen = envelope_gen_num_change; + slot->eg_gennext = envelope_gen_num_attack; + slot->pg_phase = 0x00; } - slt->EG_ksl = ksl >> kslshift[slt->ksl]; + slot->key |= type; } -void EG_Generate(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - envelope_calc(opl, op); - slt->EG_mout = slt->EG_out + slt->EG_ksl + (slt->EG_tl << 2); - if (slt->tremolo) { - slt->EG_mout += opl->trem_val; - } - if (slt->EG_mout > 0x1ff) { - slt->EG_mout = 0x1ff; - } -} - -void EG_KeyOn(chip *opl, Bit8u op, Bit8u type) { - slot *slt = &opl->OPs[op]; - if (!slt->key) { - slt->EG_state = eg_attack; - slt->eg_gen = envelope_gen_num_change; - slt->eg_gennext = envelope_gen_num_attack; - slt->PG_pos = 0; - } - slt->key |= type; -} - -void EG_KeyOff(chip *opl, Bit8u op, Bit8u type) { - slot *slt = &opl->OPs[op]; - if (slt->key) { - slt->key &= (~type); - if (slt->key == 0x00) { - slt->EG_state = eg_release; - slt->eg_gen = envelope_gen_num_change; - slt->eg_gennext = envelope_gen_num_release; +void eg_keyoff(opl_slot *slot, Bit8u type) { + if (slot->key) { + slot->key &= (~type); + if (!slot->key) { + slot->eg_gen = envelope_gen_num_change; + slot->eg_gennext = envelope_gen_num_release; } } } +// +// Phase Generator +// + +void pg_generate(opl_slot *slot) { + Bit16u f_num = slot->channel->f_num; + if (slot->reg_vib) { + Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10)&0x07] + (0x01 - slot->chip->dvb)); + f_num += f_num_high * vibsgn_table[(slot->chip->timer >> 10) & 0x07]; + } + slot->pg_phase += (((f_num << slot->channel->block) >> 1) * mt[slot->reg_mult]) >> 1; +} + // // Noise Generator // -void N_Generate(chip *opl) { - if (opl->noise & 1) { - opl->noise ^= 0x800302; +void n_generate(opl_chip *chip) { + if (chip->noise & 0x01) { + chip->noise ^= 0x800302; } - opl->noise >>= 1; + chip->noise >>= 1; } // -// Operator(Slot) +// Slot // -void OP_Update20(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - slt->tremolo = (opl->opl_memory[0x20 + slt->offset] >> 7); - slt->vibrato = (opl->opl_memory[0x20 + slt->offset] >> 6) & 0x01; - slt->EG_type = (opl->opl_memory[0x20 + slt->offset] >> 5) & 0x01; - slt->ksr = (opl->opl_memory[0x20 + slt->offset] >> 4) & 0x01; - slt->mult = (opl->opl_memory[0x20 + slt->offset]) & 0x0f; +void slot_write20(opl_slot *slot,Bit8u data) { + if ((data >> 7) & 0x01) { + slot->trem = &slot->chip->tremval; + } + else { + slot->trem = (Bit8u*)&slot->chip->zeromod; + } + slot->reg_vib = (data >> 6) & 0x01; + slot->reg_type = (data >> 5) & 0x01; + slot->reg_ksr = (data >> 4) & 0x01; + slot->reg_mult = data & 0x0f; + envelope_update_rate(slot); } -void OP_Update40(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - slt->EG_tl = (opl->opl_memory[0x40 + slt->offset]) & 0x3f; - slt->ksl = (opl->opl_memory[0x40 + slt->offset] >> 6) & 0x03; - EG_UpdateKSL(opl, op); +void slot_write40(opl_slot *slot, Bit8u data) { + slot->reg_ksl = (data >> 6) & 0x03; + slot->reg_tl = data & 0x3f; + envelope_update_ksl(slot); } -void OP_Update60(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - slt->EG_dr = (opl->opl_memory[0x60 + slt->offset]) & 0x0f; - slt->EG_ar = (opl->opl_memory[0x60 + slt->offset] >> 4) & 0x0f; +void slot_write60(opl_slot *slot, Bit8u data) { + slot->reg_ar = (data >> 4) & 0x0f; + slot->reg_dr = data & 0x0f; + envelope_update_rate(slot); } -void OP_Update80(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - slt->EG_rr = (opl->opl_memory[0x80 + slt->offset]) & 0x0f; - slt->EG_sl = (opl->opl_memory[0x80 + slt->offset] >> 4) & 0x0f; - if (slt->EG_sl == 0x0f) { - slt->EG_sl = 0x1f; +void slot_write80(opl_slot *slot, Bit8u data) { + slot->reg_sl = (data >> 4) & 0x0f; + if (slot->reg_sl == 0x0f) { + slot->reg_sl = 0x1f; + } + slot->reg_rr = data & 0x0f; + envelope_update_rate(slot); +} + +void slot_writee0(opl_slot *slot, Bit8u data) { + slot->reg_wf = data & 0x07; + if (slot->chip->newm == 0x00) { + slot->reg_wf &= 0x03; } } -void OP_UpdateE0(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - slt->waveform = opl->opl_memory[0xe0 + slt->offset] & 0x07; - if (!opl->newm) { - slt->waveform &= 0x03; +void slot_generatephase(opl_slot *slot, Bit16u phase) { + slot->out = envelope_sin[slot->reg_wf](phase, slot->eg_out); +} + +void slot_generate(opl_slot *slot) { + slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); +} + +void slot_generatezm(opl_slot *slot) { + slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9), slot->eg_out); +} + +void slot_calgfb(opl_slot *slot) { + slot->prout[1] = slot->prout[0]; + slot->prout[0] = slot->out; + if (slot->channel->fb != 0x00) { + slot->fbmod = (slot->prout[0] + slot->prout[1]) >> (0x09 - slot->channel->fb); } -} - -void OP_GeneratePhase(chip *opl, Bit8u op, Bit16u phase) { - slot *slt = &opl->OPs[op]; - slt->out = envelope_sin[slt->waveform](phase, slt->EG_out); -} - -void OP_Generate(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - slt->out = envelope_sin[slt->waveform]((Bit16u)((slt->PG_pos >> 9) + (*slt->mod)), slt->EG_mout); -} - -void OP_GenerateZM(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - slt->out = envelope_sin[slt->waveform]((Bit16u)(slt->PG_pos >> 9), slt->EG_mout); -} - -void OP_CalcFB(chip *opl, Bit8u op) { - slot *slt = &opl->OPs[op]; - channel *chan = &opl->Channels[op / 2]; - slt->prevout[1] = slt->prevout[0]; - slt->prevout[0] = slt->out; - if (chan->feedback) { - slt->fbmod = (slt->prevout[0] + slt->prevout[1]) >> chan->feedback; - } else { - slt->fbmod = 0; + else { + slot->fbmod = 0; } } @@ -600,301 +460,319 @@ void OP_CalcFB(chip *opl, Bit8u op) { // Channel // -void CH_UpdateRhythm(chip *opl) { - opl->rhythm = (opl->opl_memory[0xbd] & 0x3f); - if (opl->rhythm & 0x20) { - for (Bit8u i = 6; i < 9; i++) { - opl->Channels[i].chtype = ch_drum; +void chan_setupalg(opl_channel *channel); + +void chan_updaterhythm(opl_chip *chip, Bit8u data) { + chip->rhy = data & 0x3f; + if (chip->rhy & 0x20) { + chip->channel[6].out[0] = &chip->slot[13].out; + chip->channel[6].out[1] = &chip->slot[13].out; + chip->channel[6].out[2] = &chip->zeromod; + chip->channel[6].out[3] = &chip->zeromod; + chip->channel[7].out[0] = &chip->slot[14].out; + chip->channel[7].out[1] = &chip->slot[14].out; + chip->channel[7].out[2] = &chip->slot[15].out; + chip->channel[7].out[3] = &chip->slot[15].out; + chip->channel[8].out[0] = &chip->slot[16].out; + chip->channel[8].out[1] = &chip->slot[16].out; + chip->channel[8].out[2] = &chip->slot[17].out; + chip->channel[8].out[3] = &chip->slot[17].out; + for (Bit8u chnum = 6; chnum < 9; chnum++) { + chip->channel[chnum].chtype = ch_drum; } - //HH - if (opl->rhythm & 0x01) { - EG_KeyOn(opl, 14, egk_drum); - } else { - EG_KeyOff(opl, 14, egk_drum); + //hh + if (chip->rhy & 0x01) { + eg_keyon(&chip->slot[14], egk_drum); } - //TC - if (opl->rhythm & 0x02) { - EG_KeyOn(opl, 17, egk_drum); - } else { - EG_KeyOff(opl, 17, egk_drum); + else { + eg_keyoff(&chip->slot[14], egk_drum); } - //TOM - if (opl->rhythm & 0x04) { - EG_KeyOn(opl, 16, egk_drum); - } else { - EG_KeyOff(opl, 16, egk_drum); + //tc + if (chip->rhy & 0x02) { + eg_keyon(&chip->slot[17], egk_drum); } - //SD - if (opl->rhythm & 0x08) { - EG_KeyOn(opl, 15, egk_drum); - } else { - EG_KeyOff(opl, 15, egk_drum); + else { + eg_keyoff(&chip->slot[17], egk_drum); } - //BD - if (opl->rhythm & 0x10) { - EG_KeyOn(opl, 12, egk_drum); - EG_KeyOn(opl, 13, egk_drum); - } else { - EG_KeyOff(opl, 12, egk_drum); - EG_KeyOff(opl, 13, egk_drum); + //tom + if (chip->rhy & 0x04) { + eg_keyon(&chip->slot[16], egk_drum); } - } else { - for (Bit8u i = 6; i < 9; i++) { - opl->Channels[i].chtype = ch_2op; + else { + eg_keyoff(&chip->slot[16], egk_drum); + } + //sd + if (chip->rhy & 0x08) { + eg_keyon(&chip->slot[15], egk_drum); + } + else { + eg_keyoff(&chip->slot[15], egk_drum); + } + //bd + if (chip->rhy & 0x10) { + eg_keyon(&chip->slot[12], egk_drum); + eg_keyon(&chip->slot[13], egk_drum); + } + else { + eg_keyoff(&chip->slot[12], egk_drum); + eg_keyoff(&chip->slot[13], egk_drum); + } + } + else { + for (Bit8u chnum = 6; chnum < 9; chnum++) { + chip->channel[chnum].chtype = ch_2op; + chan_setupalg(&chip->channel[chnum]); } } } -void CH_UpdateAB0(chip *opl, Bit8u ch) { - channel *chan = &opl->Channels[ch]; - if (opl->newm && chan->chtype == ch_4op2) { +void chan_writea0(opl_channel *channel, Bit8u data) { + if (channel->chip->newm && channel->chtype == ch_4op2) { return; } - Bit16u f_number = (opl->opl_memory[0xa0 + chan->offset]) | (((opl->opl_memory[0xb0 + chan->offset]) & 0x03) << 8); - Bit8u block = ((opl->opl_memory[0xb0 + chan->offset]) >> 2) & 0x07; - Bit8u ksv = block * 2 | ((f_number >> (9 - opl->nts)) & 0x01); - chan->f_number = f_number; - chan->block = block; - chan->ksv = ksv; - EG_UpdateKSL(opl, ch * 2); - EG_UpdateKSL(opl, ch * 2 + 1); - OP_Update60(opl, ch * 2); - OP_Update60(opl, ch * 2 + 1); - OP_Update80(opl, ch * 2); - OP_Update80(opl, ch * 2 + 1); - if (opl->newm && chan->chtype == ch_4op) { - chan = &opl->Channels[ch + 3]; - chan->f_number = f_number; - chan->block = block; - chan->ksv = ksv; - EG_UpdateKSL(opl, (ch + 3) * 2); - EG_UpdateKSL(opl, (ch + 3) * 2 + 1); - OP_Update60(opl, (ch + 3) * 2); - OP_Update60(opl, (ch + 3) * 2 + 1); - OP_Update80(opl, (ch + 3) * 2); - OP_Update80(opl, (ch + 3) * 2 + 1); + channel->f_num = (channel->f_num & 0x300) | data; + channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); + envelope_update_ksl(channel->slots[0]); + envelope_update_ksl(channel->slots[1]); + envelope_update_rate(channel->slots[0]); + envelope_update_rate(channel->slots[1]); + if (channel->chip->newm && channel->chtype == ch_4op) { + channel->pair->f_num = channel->f_num; + channel->pair->ksv = channel->ksv; + envelope_update_ksl(channel->pair->slots[0]); + envelope_update_ksl(channel->pair->slots[1]); + envelope_update_rate(channel->pair->slots[0]); + envelope_update_rate(channel->pair->slots[1]); } } -void CH_SetupAlg(chip *opl, Bit8u ch) { - channel *chan = &opl->Channels[ch]; - if (chan->alg & 0x08) { +void chan_writeb0(opl_channel *channel, Bit8u data) { + if (channel->chip->newm && channel->chtype == ch_4op2) { return; } - if (chan->alg & 0x04) { - switch (chan->alg & 0x03) { - case 0: - opl->OPs[(ch - 3) * 2].mod = &opl->OPs[(ch - 3) * 2].fbmod; - opl->OPs[(ch - 3) * 2 + 1].mod = &opl->OPs[(ch - 3) * 2].out; - opl->OPs[ch * 2].mod = &opl->OPs[(ch - 3) * 2 + 1].out; - opl->OPs[ch * 2 + 1].mod = &opl->OPs[ch * 2].out; - break; - case 1: - opl->OPs[(ch - 3) * 2].mod = &opl->OPs[(ch - 3) * 2].fbmod; - opl->OPs[(ch - 3) * 2 + 1].mod = &opl->OPs[(ch - 3) * 2].out; - opl->OPs[ch * 2].mod = &opl->zm; - opl->OPs[ch * 2 + 1].mod = &opl->OPs[ch * 2].out; - break; - case 2: - opl->OPs[(ch - 3) * 2].mod = &opl->OPs[(ch - 3) * 2].fbmod; - opl->OPs[(ch - 3) * 2 + 1].mod = &opl->zm; - opl->OPs[ch * 2].mod = &opl->OPs[(ch - 3) * 2 + 1].out; - opl->OPs[ch * 2 + 1].mod = &opl->OPs[ch * 2].out; - break; - case 3: - opl->OPs[(ch - 3) * 2].mod = &opl->OPs[(ch - 3) * 2].fbmod; - opl->OPs[(ch - 3) * 2 + 1].mod = &opl->zm; - opl->OPs[ch * 2].mod = &opl->OPs[(ch - 3) * 2 + 1].out; - opl->OPs[ch * 2 + 1].mod = &opl->zm; - break; - } - } else { - switch (chan->alg & 0x01) { - case 0: - opl->OPs[ch * 2].mod = &opl->OPs[ch * 2].fbmod; - opl->OPs[ch * 2 + 1].mod = &opl->OPs[ch * 2].out; - break; - case 1: - opl->OPs[ch * 2].mod = &opl->OPs[ch * 2].fbmod; - opl->OPs[ch * 2 + 1].mod = &opl->zm; - break; - } + channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); + channel->block = (data >> 2) & 0x07; + channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); + envelope_update_ksl(channel->slots[0]); + envelope_update_ksl(channel->slots[1]); + envelope_update_rate(channel->slots[0]); + envelope_update_rate(channel->slots[1]); + if (channel->chip->newm && channel->chtype == ch_4op) { + channel->pair->f_num = channel->f_num; + channel->pair->block = channel->block; + channel->pair->ksv = channel->ksv; + envelope_update_ksl(channel->pair->slots[0]); + envelope_update_ksl(channel->pair->slots[1]); + envelope_update_rate(channel->pair->slots[0]); + envelope_update_rate(channel->pair->slots[1]); } } -void CH_UpdateC0(chip *opl, Bit8u ch) { - channel *chan = &opl->Channels[ch]; - Bit8u fb = (opl->opl_memory[0xc0 + chan->offset] & 0x0e) >> 1; - chan->feedback = fb ? (9 - fb) : 0; - chan->con = opl->opl_memory[0xc0 + chan->offset] & 0x01; - chan->alg = chan->con; - if (opl->newm) { - if (chan->chtype == ch_4op) { - channel *chan1 = &opl->Channels[ch + 3]; - chan1->alg = 0x04 | (chan->con << 1) | (chan1->con); - chan->alg = 0x08; - CH_SetupAlg(opl, ch + 3); - } else if (chan->chtype == ch_4op2) { - channel *chan1 = &opl->Channels[ch - 3]; - chan->alg = 0x04 | (chan1->con << 1) | (chan->con); - chan1->alg = 0x08; - CH_SetupAlg(opl, ch); - } else { - CH_SetupAlg(opl, ch); - } - } else { - CH_SetupAlg(opl, ch); - } - if (opl->newm) { - chan->cha = ((opl->opl_memory[0xc0 + chan->offset] >> 4) & 0x01) ? ~0 : 0; - chan->chb = ((opl->opl_memory[0xc0 + chan->offset] >> 5) & 0x01) ? ~0 : 0; - chan->chc = ((opl->opl_memory[0xc0 + chan->offset] >> 6) & 0x01) ? ~0 : 0; - chan->chd = ((opl->opl_memory[0xc0 + chan->offset] >> 7) & 0x01) ? ~0 : 0; - } else { - opl->Channels[ch].cha = opl->Channels[ch].chb = ~0; - opl->Channels[ch].chc = opl->Channels[ch].chd = 0; - } -} - -void CH_Set2OP(chip *opl) { - for (Bit8u i = 0; i < 18; i++) { - opl->Channels[i].chtype = ch_2op; - CH_UpdateC0(opl, i); - } -} - -void CH_Set4OP(chip *opl) { - for (Bit8u i = 0; i < 3; i++) { - if ((opl->opl_memory[0x104] >> i) & 0x01) { - opl->Channels[i].chtype = ch_4op; - opl->Channels[i + 3].chtype = ch_4op2; - CH_UpdateC0(opl, i); - CH_UpdateC0(opl, i + 3); - } - if ((opl->opl_memory[0x104] >> (i + 3)) & 0x01) { - opl->Channels[i + 9].chtype = ch_4op; - opl->Channels[i + 3 + 9].chtype = ch_4op2; - CH_UpdateC0(opl, i + 9); - CH_UpdateC0(opl, i + 3 + 9); - } - } -} - -void CH_GenerateRhythm(chip *opl) { - if (opl->rhythm & 0x20) { - channel *chan6 = &opl->Channels[6]; - channel *chan7 = &opl->Channels[7]; - channel *chan8 = &opl->Channels[8]; - slot *slt12 = &opl->OPs[12]; - slot *slt13 = &opl->OPs[13]; - slot *slt14 = &opl->OPs[14]; - slot *slt15 = &opl->OPs[15]; - slot *slt16 = &opl->OPs[16]; - slot *slt17 = &opl->OPs[17]; - //BD - OP_Generate(opl, 12); - OP_Generate(opl, 13); - chan6->out = slt13->out * 2; - Bit16u P14 = (slt14->PG_pos >> 9) & 0x3ff; - Bit16u P17 = (slt17->PG_pos >> 9) & 0x3ff; - Bit16u phase = 0; - // HH TC Phase bit - Bit16u PB = ((P14 & 0x08) | (((P14 >> 5) ^ P14) & 0x04) | (((P17 >> 2) ^ P17) & 0x08)) ? 0x01 : 0x00; - //HH - phase = (PB << 9) | (0x34 << ((PB ^ (opl->noise & 0x01) << 1))); - OP_GeneratePhase(opl, 14, phase); - //SD - phase = (0x100 << ((P14 >> 8) & 0x01)) ^ ((opl->noise & 0x01) << 8); - OP_GeneratePhase(opl, 15, phase); - //TT - OP_GenerateZM(opl, 16); - //TC - phase = 0x100 | (PB << 9); - OP_GeneratePhase(opl, 17, phase); - chan7->out = (slt14->out + slt15->out) * 2; - chan8->out = (slt16->out + slt17->out) * 2; - } -} - -void CH_Generate(chip *opl, Bit8u ch) { - channel *chan = &opl->Channels[ch]; - if (chan->chtype == ch_drum) { +void chan_setupalg(opl_channel *channel) { + if (channel->chtype == ch_drum) { return; } - if (chan->alg & 0x08) { - chan->out = 0; + if (channel->alg & 0x08) { return; - } else if (chan->alg & 0x04) { - OP_Generate(opl, (ch - 3) * 2); - OP_Generate(opl, (ch - 3) * 2 + 1); - OP_Generate(opl, ch * 2); - OP_Generate(opl, ch * 2 + 1); - switch (chan->alg & 0x03) { - case 0: - chan->out = opl->OPs[ch * 2 + 1].out; + } + if (channel->alg & 0x04) { + channel->pair->out[0] = &channel->chip->zeromod; + channel->pair->out[1] = &channel->chip->zeromod; + channel->pair->out[2] = &channel->chip->zeromod; + channel->pair->out[3] = &channel->chip->zeromod; + switch (channel->alg & 0x03) { + case 0x00: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->slots[1]->out; + channel->out[1] = &channel->chip->zeromod; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; break; - case 1: - chan->out = opl->OPs[(ch - 3) * 2 + 1].out + opl->OPs[ch * 2 + 1].out; + case 0x01: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; + channel->slots[0]->mod = &channel->chip->zeromod; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->pair->slots[1]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; break; - case 2: - chan->out = opl->OPs[(ch - 3) * 2].out + opl->OPs[ch * 2 + 1].out; + case 0x02: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->chip->zeromod; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->pair->slots[0]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; break; - case 3: - chan->out = opl->OPs[(ch - 3) * 2].out + opl->OPs[ch * 2].out + opl->OPs[ch * 2 + 1].out; + case 0x03: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->chip->zeromod; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->chip->zeromod; + channel->out[0] = &channel->pair->slots[0]->out; + channel->out[1] = &channel->slots[0]->out; + channel->out[2] = &channel->slots[1]->out; + channel->out[3] = &channel->chip->zeromod; break; } } else { - OP_Generate(opl, ch * 2); - OP_Generate(opl, ch * 2 + 1); - switch (chan->alg & 0x01) { - case 0: - chan->out = opl->OPs[ch * 2 + 1].out; + switch (channel->alg & 0x01) { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->slots[1]->out; + channel->out[1] = &channel->chip->zeromod; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; break; - case 1: - chan->out = opl->OPs[ch * 2].out + opl->OPs[ch * 2 + 1].out; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + channel->out[0] = &channel->slots[0]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; break; } } } -void CH_Enable(chip *opl, Bit8u ch) { - channel *chan = &opl->Channels[ch]; - if (opl->newm) { - if (chan->chtype == ch_4op) { - EG_KeyOn(opl, ch * 2, egk_norm); - EG_KeyOn(opl, ch * 2 + 1, egk_norm); - EG_KeyOn(opl, (ch + 3) * 2, egk_norm); - EG_KeyOn(opl, (ch + 3) * 2 + 1, egk_norm); +void chan_writec0(opl_channel *channel, Bit8u data) { + channel->fb = (data & 0x0e) >> 1; + channel->con = data & 0x01; + channel->alg = channel->con; + if (channel->chip->newm) { + if (channel->chtype == ch_4op) { + channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); + channel->alg = 0x08; + chan_setupalg(channel->pair); } - else if (chan->chtype == ch_2op || chan->chtype == ch_drum) { - EG_KeyOn(opl, ch * 2, egk_norm); - EG_KeyOn(opl, ch * 2 + 1, egk_norm); + else if (channel->chtype == ch_4op2) { + channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); + channel->pair->alg = 0x08; + chan_setupalg(channel); + } + else { + chan_setupalg(channel); } } else { - EG_KeyOn(opl, ch * 2, egk_norm); - EG_KeyOn(opl, ch * 2 + 1, egk_norm); + chan_setupalg(channel); + } + if (channel->chip->newm) { + channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; + channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; + } + else { + channel->cha = channel->chb = ~0; } } -void CH_Disable(chip *opl, Bit8u ch) { - channel *chan = &opl->Channels[ch]; - if (opl->newm) { - if (chan->chtype == ch_4op) { - EG_KeyOff(opl, ch * 2, egk_norm); - EG_KeyOff(opl, ch * 2 + 1, egk_norm); - EG_KeyOff(opl, (ch + 3) * 2, egk_norm); - EG_KeyOff(opl, (ch + 3) * 2 + 1, egk_norm); +void chan_generaterhythm(opl_chip *chip) { + if (chip->rhy & 0x20) { + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + slot_generate(channel6->slots[0]); + slot_generate(channel6->slots[1]); + Bit16u phase14 = channel7->slots[0]->pg_phase & 0x3ff; + Bit16u phase17 = channel8->slots[1]->pg_phase & 0x3ff; + Bit16u phase = 0x00; + //hh tc phase bit + Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //hh + phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); + slot_generatephase(channel7->slots[0], phase); + //sd + phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); + slot_generatephase(channel7->slots[1], phase); + //tt + slot_generatezm(channel8->slots[0]); + //tc + phase = 0x100 | (phasebit << 9); + slot_generatephase(channel8->slots[1], phase); + } +} + +void chan_generate(opl_channel *channel) { + if (channel->chtype == ch_drum) { + return; + } + if (channel->alg & 0x08) { + return; + } + if (channel->alg & 0x04) { + slot_generate(channel->pair->slots[0]); + slot_generate(channel->pair->slots[1]); + slot_generate(channel->slots[0]); + slot_generate(channel->slots[1]); + } + else { + slot_generate(channel->slots[0]); + slot_generate(channel->slots[1]); + } +} + +void chan_enable(opl_channel *channel) { + if (channel->chip->newm) { + if (channel->chtype == ch_4op) { + eg_keyon(channel->slots[0], egk_norm); + eg_keyon(channel->slots[1], egk_norm); + eg_keyon(channel->pair->slots[0], egk_norm); + eg_keyon(channel->pair->slots[1], egk_norm); } - else if (chan->chtype == ch_2op || chan->chtype == ch_drum) { - EG_KeyOff(opl, ch * 2, egk_norm); - EG_KeyOff(opl, ch * 2 + 1, egk_norm); + else if (channel->chtype == ch_2op || channel->chtype == ch_drum) { + eg_keyon(channel->slots[0], egk_norm); + eg_keyon(channel->slots[1], egk_norm); } } else { - EG_KeyOff(opl, ch * 2, egk_norm); - EG_KeyOff(opl, ch * 2 + 1, egk_norm); + eg_keyon(channel->slots[0], egk_norm); + eg_keyon(channel->slots[1], egk_norm); + } +} + +void chan_disable(opl_channel *channel) { + if (channel->chip->newm) { + if (channel->chtype == ch_4op) { + eg_keyoff(channel->slots[0], egk_norm); + eg_keyoff(channel->slots[1], egk_norm); + eg_keyoff(channel->pair->slots[0], egk_norm); + eg_keyoff(channel->pair->slots[1], egk_norm); + } + else if (channel->chtype == ch_2op || channel->chtype == ch_drum) { + eg_keyoff(channel->slots[0], egk_norm); + eg_keyoff(channel->slots[1], egk_norm); + } + } + else { + eg_keyoff(channel->slots[0], egk_norm); + eg_keyoff(channel->slots[1], egk_norm); + } +} + +void chan_set4op(opl_chip *chip, Bit8u data) { + for (Bit8u bit = 0; bit < 6; bit++) { + Bit8u chnum = bit; + if (bit >= 3) { + chnum += 9 - 3; + } + if ((data >> bit) & 0x01) { + chip->channel[chnum].chtype = ch_4op; + chip->channel[chnum + 3].chtype = ch_4op2; + } + else { + chip->channel[chnum].chtype = ch_2op; + chip->channel[chnum + 3].chtype = ch_2op; + } } } @@ -909,99 +787,52 @@ Bit16s limshort(Bit32s a) { } void NukedOPL3::Reset() { - for (Bit8u i = 0; i < 36; i++) { - opl3.OPs[i].PG_pos = 0; - opl3.OPs[i].PG_inc = 0; - opl3.OPs[i].EG_out = 0x1ff; - opl3.OPs[i].EG_mout = 0x1ff; - opl3.OPs[i].eg_inc = 0; - opl3.OPs[i].eg_gen = 0; - opl3.OPs[i].eg_gennext = 0; - opl3.OPs[i].EG_ksl = 0; - opl3.OPs[i].EG_ar = 0; - opl3.OPs[i].EG_dr = 0; - opl3.OPs[i].EG_sl = 0; - opl3.OPs[i].EG_rr = 0; - opl3.OPs[i].EG_state = eg_off; - opl3.OPs[i].EG_type = 0; - opl3.OPs[i].out = 0; - opl3.OPs[i].prevout[0] = 0; - opl3.OPs[i].prevout[1] = 0; - opl3.OPs[i].fbmod = 0; - opl3.OPs[i].offset = op_offset[i % 18] + ((i > 17) << 8); - opl3.OPs[i].mult = 0; - opl3.OPs[i].vibrato = 0; - opl3.OPs[i].tremolo = 0; - opl3.OPs[i].ksr = 0; - opl3.OPs[i].EG_tl = 0; - opl3.OPs[i].ksl = 0; - opl3.OPs[i].key = 0; - opl3.OPs[i].waveform = 0; + memset(&opl3, 0, sizeof(opl_chip)); + for (Bit8u slotnum = 0; slotnum < 36; slotnum++) { + opl3.slot[slotnum].channel = &opl3.channel[slotnum / 2]; + opl3.slot[slotnum].chip = &opl3; + opl3.slot[slotnum].mod = &opl3.zeromod; + opl3.slot[slotnum].eg_rout = 0x1ff; + opl3.slot[slotnum].eg_out = 0x1ff; + opl3.slot[slotnum].eg_gen = envelope_gen_num_off; + opl3.slot[slotnum].eg_gennext = envelope_gen_num_off; + opl3.slot[slotnum].trem = (Bit8u*)&opl3.zeromod; } - for (Bit8u i = 0; i < 9; i++) { - opl3.Channels[i].con = 0; - opl3.Channels[i + 9].con = 0; - opl3.Channels[i].chtype = ch_2op; - opl3.Channels[i + 9].chtype = ch_2op; - opl3.Channels[i].alg = 0; - opl3.Channels[i + 9].alg = 0; - opl3.Channels[i].offset = i; - opl3.Channels[i + 9].offset = 0x100 + i; - opl3.Channels[i].feedback = 0; - opl3.Channels[i + 9].feedback = 0; - opl3.Channels[i].out = 0; - opl3.Channels[i + 9].out = 0; - opl3.Channels[i].cha = ~0; - opl3.Channels[i + 9].cha = ~0; - opl3.Channels[i].chb = ~0; - opl3.Channels[i + 9].chb = ~0; - opl3.Channels[i].chc = 0; - opl3.Channels[i + 9].chc = 0; - opl3.Channels[i].chd = 0; - opl3.Channels[i + 9].chd = 0; - opl3.Channels[i].out = 0; - opl3.Channels[i + 9].out = 0; - opl3.Channels[i].f_number = 0; - opl3.Channels[i + 9].f_number = 0; - opl3.Channels[i].block = 0; - opl3.Channels[i + 9].block = 0; - opl3.Channels[i].ksv = 0; - opl3.Channels[i + 9].ksv = 0; - opl3.Channels[i].panl = (float)CENTER_PANNING_POWER; - opl3.Channels[i + 9].panl = (float)CENTER_PANNING_POWER; - opl3.Channels[i].panr = (float)CENTER_PANNING_POWER; - opl3.Channels[i + 9].panr = (float)CENTER_PANNING_POWER; + for (Bit8u channum = 0; channum < 18; channum++) { + opl3.channel[channum].slots[0] = &opl3.slot[2 * channum]; + opl3.channel[channum].slots[1] = &opl3.slot[2 * channum + 1]; + if ((channum % 9) < 3) { + opl3.channel[channum].pair = &opl3.channel[channum + 3]; + } + else if ((channum % 9) < 6) { + opl3.channel[channum].pair = &opl3.channel[channum - 3]; + } + opl3.channel[channum].chip = &opl3; + opl3.channel[channum].out[0] = &opl3.zeromod; + opl3.channel[channum].out[1] = &opl3.zeromod; + opl3.channel[channum].out[2] = &opl3.zeromod; + opl3.channel[channum].out[3] = &opl3.zeromod; + opl3.channel[channum].chtype = ch_2op; + opl3.channel[channum].cha = ~0; + opl3.channel[channum].chb = ~0; + opl3.channel[channum].fcha = 1.0; + opl3.channel[channum].fchb = 1.0; + chan_setupalg(&opl3.channel[channum]); } - memset(opl3.opl_memory, 0, 0x200); - opl3.newm = 0; - opl3.nts = 0; - opl3.rhythm = 0; - opl3.dvb = 0; - opl3.dam = 0; opl3.noise = 0x306600; - opl3.vib_pos = 0; - opl3.timer = 0; - opl3.trem_inc = 0; - opl3.trem_tval = 0; - opl3.trem_dir = 0; - opl3.trem_val = 0; - opl3.zm = 0; - CH_Set2OP(&opl3); } void NukedOPL3::WriteReg(int reg, int v) { v &= 0xff; reg &= 0x1ff; - Bit8u highbank = (reg >> 8) & 0x01; + Bit8u high = (reg >> 8) & 0x01; Bit8u regm = reg & 0xff; - opl3.opl_memory[reg & 0x1ff] = v; switch (regm & 0xf0) { case 0x00: - if (highbank) { + if (high) { switch (regm & 0x0f) { case 0x04: - CH_Set2OP(&opl3); - CH_Set4OP(&opl3); + chan_set4op(&opl3, v); break; case 0x05: opl3.newm = v & 0x01; @@ -1019,57 +850,57 @@ void NukedOPL3::WriteReg(int reg, int v) { case 0x20: case 0x30: if (ad_slot[regm & 0x1f] >= 0) { - OP_Update20(&opl3, 18 * highbank + ad_slot[regm & 0x1f]); + slot_write20(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); } break; case 0x40: case 0x50: if (ad_slot[regm & 0x1f] >= 0) { - OP_Update40(&opl3, 18 * highbank + ad_slot[regm & 0x1f]); + slot_write40(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); } break; case 0x60: case 0x70: if (ad_slot[regm & 0x1f] >= 0) { - OP_Update60(&opl3, 18 * highbank + ad_slot[regm & 0x1f]); + slot_write60(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); } break; case 0x80: case 0x90: if (ad_slot[regm & 0x1f] >= 0) { - OP_Update80(&opl3, 18 * highbank + ad_slot[regm & 0x1f]); + slot_write80(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v);; } break; case 0xe0: case 0xf0: if (ad_slot[regm & 0x1f] >= 0) { - OP_UpdateE0(&opl3, 18 * highbank + ad_slot[regm & 0x1f]); + slot_writee0(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); } break; case 0xa0: if ((regm & 0x0f) < 9) { - CH_UpdateAB0(&opl3, 9 * highbank + (regm & 0x0f)); + chan_writea0(&opl3.channel[9 * high + (regm & 0x0f)], v); } break; case 0xb0: - if (regm == 0xbd && !highbank) { + if (regm == 0xbd && !high) { opl3.dam = v >> 7; opl3.dvb = (v >> 6) & 0x01; - CH_UpdateRhythm(&opl3); + chan_updaterhythm(&opl3, v); } else if ((regm & 0x0f) < 9) { - CH_UpdateAB0(&opl3, 9 * highbank + (regm & 0x0f)); + chan_writeb0(&opl3.channel[9 * high + (regm & 0x0f)], v); if (v & 0x20) { - CH_Enable(&opl3, 9 * highbank + (regm & 0x0f)); + chan_enable(&opl3.channel[9 * high + (regm & 0x0f)]); } else { - CH_Disable(&opl3, 9 * highbank + (regm & 0x0f)); + chan_disable(&opl3.channel[9 * high + (regm & 0x0f)]); } } break; case 0xc0: if ((regm & 0x0f) < 9) { - CH_UpdateC0(&opl3, 9 * highbank + (regm & 0x0f)); + chan_writec0(&opl3.channel[9 * high + (regm & 0x0f)], v); } break; } @@ -1077,54 +908,55 @@ void NukedOPL3::WriteReg(int reg, int v) { void NukedOPL3::Update(float* sndptr, int numsamples) { Bit32s outa, outb; - Bit8u ii = 0; for (Bit32u i = 0; i < (Bit32u)numsamples; i++) { outa = 0; outb = 0; - for (ii = 0; ii < 36; ii++) { - OP_CalcFB(&opl3, ii); + for (Bit8u ii = 0; ii < 36; ii++) { + slot_calgfb(&opl3.slot[ii]); } - CH_GenerateRhythm(&opl3); - for (ii = 0; ii < 18; ii++) { - CH_Generate(&opl3, ii); + chan_generaterhythm(&opl3); + for (Bit8u ii = 0; ii < 18; ii++) { + chan_generate(&opl3.channel[ii]); + Bit16s accm = 0; + for (Bit8u jj = 0; jj < 4; jj++) { + accm += *opl3.channel[ii].out[jj]; + } if (FullPan) { - outa += (Bit16s)(opl3.Channels[ii].out * opl3.Channels[ii].panl); - outb += (Bit16s)(opl3.Channels[ii].out * opl3.Channels[ii].panr); + outa += (Bit16s)(accm * opl3.channel[ii].fcha); + outb += (Bit16s)(accm * opl3.channel[ii].fchb); } else { - outa += (Bit16s)(opl3.Channels[ii].out & opl3.Channels[ii].cha); - outb += (Bit16s)(opl3.Channels[ii].out & opl3.Channels[ii].chb); + outa += (Bit16s)(accm & opl3.channel[ii].cha); + outb += (Bit16s)(accm & opl3.channel[ii].chb); } } - for (ii = 0; ii < 36; ii++) { - EG_Generate(&opl3, ii); - PG_Generate(&opl3, ii); - } - N_Generate(&opl3); - opl3.trem_inc++; - if (!(opl3.trem_inc & 0x3f)) { - if (!opl3.trem_dir) { - if (opl3.trem_tval == 105) { - opl3.trem_tval--; - opl3.trem_dir = 1; - } - else { - opl3.trem_tval++; - } - } - else { - if (opl3.trem_tval == 0) { - opl3.trem_tval++; - opl3.trem_dir = 0; - } - else { - opl3.trem_tval--; - } - } - opl3.trem_val = (opl3.trem_tval >> 2) >> ((!opl3.dam) << 1); + for (Bit8u ii = 0; ii < 36; ii++) { + envelope_calc(&opl3.slot[ii]); + pg_generate(&opl3.slot[ii]); } + n_generate(&opl3); opl3.timer++; - opl3.vib_pos = (opl3.timer >> 10) & 0x07; + if (!(opl3.timer & 0x3f)) { + if (!opl3.tremdir) { + if (opl3.tremtval == 105) { + opl3.tremtval--; + opl3.tremdir = 1; + } + else { + opl3.tremtval++; + } + } + else { + if (opl3.tremtval == 0) { + opl3.tremtval++; + opl3.tremdir = 0; + } + else { + opl3.tremtval--; + } + } + opl3.tremval = (opl3.tremtval >> 2) >> ((1 - opl3.dam) << 1); + } *sndptr++ += (float)(outa / 10240.0); *sndptr++ += (float)(outb / 10240.0); } @@ -1132,8 +964,8 @@ void NukedOPL3::Update(float* sndptr, int numsamples) { void NukedOPL3::SetPanning(int c, float left, float right) { if (FullPan) { - opl3.Channels[c].panl = left; - opl3.Channels[c].panr = right; + opl3.channel[c].fcha = left; + opl3.channel[c].fchb = right; } } @@ -1144,4 +976,4 @@ NukedOPL3::NukedOPL3(bool stereo) { OPLEmul *NukedOPL3Create(bool stereo) { return new NukedOPL3(stereo); -} +} \ No newline at end of file diff --git a/src/oplsynth/nukedopl3.h b/src/oplsynth/nukedopl3.h index 15f264c1a..ccf37fe14 100644 --- a/src/oplsynth/nukedopl3.h +++ b/src/oplsynth/nukedopl3.h @@ -5,12 +5,12 @@ * 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 @@ -23,11 +23,11 @@ Feedback and Rhythm part calculation information. forums.submarine.org.uk(carbon14, opl3): Tremolo and phase generator calculation information. - OPLx decapsulated(Matthew Gambrell and Olli Niemitalo): + OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): OPL2 ROMs. */ -//version 1.4.2 +//version 1.5 #include "opl.h" #include "muslib.h" @@ -41,74 +41,188 @@ typedef SWORD Bit16s; typedef BYTE Bit8u; typedef SBYTE Bit8s; -struct channel { - Bit8u con; - Bit8u chtype; - Bit8u alg; - Bit16u offset; - Bit8u feedback; - Bit16u cha, chb, chc, chd; - Bit16s out; - Bit16u f_number; - Bit8u block; - Bit8u ksv; - float panl; - float panr; +// Channel types + +enum { + ch_2op = 0, + ch_4op = 1, + ch_4op2 = 2, + ch_drum = 3 }; -struct slot { - Bit32u PG_pos; - Bit32u PG_inc; - Bit16s EG_out; +// Envelope key types + +enum { + egk_norm = 0x01, + egk_drum = 0x02 +}; + + +// +// logsin table +// + +static const Bit16u logsinrom[256] = { + 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, + 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, + 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, + 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, + 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, + 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, + 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, + 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, + 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, + 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, + 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, + 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, + 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, + 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, + 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, + 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 +}; + +// +// exp table +// + +static const Bit16u exprom[256] = { + 0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a, + 0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a, + 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b, + 0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be, + 0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4, + 0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c, + 0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167, + 0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4, + 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4, + 0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227, + 0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d, + 0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5, + 0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302, + 0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351, + 0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4, + 0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa +}; + +// +// freq mult table multiplied by 2 +// +// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 +// + +static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 }; + +// +// ksl table +// + +static const Bit8u kslrom[16] = { 0, 64, 80, 90, 96, 102, 106, 110, 112, 116, 118, 120, 122, 124, 126, 127 }; + +static const Bit8u kslshift[4] = { 8, 1, 2, 0 }; + +// +// LFO vibrato +// + +static const Bit8u vib_table[8] = { 3, 1, 0, 1, 3, 1, 0, 1 }; +static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 }; + +// +// envelope generator constants +// + +static const Bit8u eg_incstep[3][4][8] = { + { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, + { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 1, 1, 0, 1 }, { 1, 1, 1, 1, 1, 1, 0, 1 } }, + { { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } } +}; + +static const Bit8u eg_incdesc[16] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2 +}; + +static const Bit8s eg_incsh[16] = { + 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2 +}; + +// +// address decoding +// + +static const Bit8s ad_slot[0x20] = { 0, 2, 4, 1, 3, 5, -1, -1, 6, 8, 10, 7, 9, 11, -1, -1, 12, 14, 16, 13, 15, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + + +struct opl_chip; +struct opl_slot; +struct opl_channel; + +struct opl_slot { + opl_channel *channel; + opl_chip *chip; + Bit16s out; + Bit16s fbmod; + Bit16s *mod; + Bit16s prout[2]; + Bit16s eg_rout; + Bit16s eg_out; Bit8u eg_inc; Bit8u eg_gen; Bit8u eg_gennext; - Bit16u EG_mout; - Bit8u EG_ksl; - Bit8u EG_ar; - Bit8u EG_dr; - Bit8u EG_sl; - Bit8u EG_rr; - Bit8u EG_state; - Bit8u EG_type; - Bit16s out; - Bit16s *mod; - Bit16s prevout[2]; - Bit16s fbmod; - Bit16u offset; - Bit8u mult; - Bit8u vibrato; - Bit8u tremolo; - Bit8u ksr; - Bit8u EG_tl; - Bit8u ksl; + Bit8u eg_rate; + Bit8u eg_ksl; + Bit8u *trem; + Bit8u reg_vib; + Bit8u reg_type; + Bit8u reg_ksr; + Bit8u reg_mult; + Bit8u reg_ksl; + Bit8u reg_tl; + Bit8u reg_ar; + Bit8u reg_dr; + Bit8u reg_sl; + Bit8u reg_rr; + Bit8u reg_wf; Bit8u key; - Bit8u waveform; + Bit32u pg_phase; }; +struct opl_channel { + opl_slot *slots[2]; + opl_channel *pair; + opl_chip *chip; + Bit16s *out[4]; + Bit8u chtype; + Bit16u f_num; + Bit8u block; + Bit8u fb; + Bit8u con; + Bit8u alg; + Bit8u ksv; + Bit16u cha, chb; + float fcha, fchb; +}; -struct chip { - Bit8u opl_memory[0x200]; +struct opl_chip { + opl_channel channel[18]; + opl_slot slot[36]; + Bit16u timer; Bit8u newm; Bit8u nts; - Bit8u rhythm; Bit8u dvb; Bit8u dam; + Bit8u rhy; + Bit8u vibpos; + Bit8u tremval; + Bit8u tremtval; + Bit8u tremdir; Bit32u noise; - Bit16u vib_pos; - Bit16u timer; - Bit8u trem_inc; - Bit8u trem_tval; - Bit8u trem_dir; - Bit8u trem_val; - channel Channels[18]; - slot OPs[36]; - Bit16s zm; + Bit16s zeromod; }; + class NukedOPL3 : public OPLEmul { private: - chip opl3; + opl_chip opl3; bool FullPan; public: void Reset(); From 94f08aa593b180c22318e88d1ae925f91139f2b1 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Thu, 27 Nov 2014 15:12:33 -0600 Subject: [PATCH 08/32] - Added: Boolean to specify if A_Raise functions should perform CopyFriendliness based upon who raised it. By default, this is false. --- src/p_lnspec.cpp | 4 ++-- src/p_local.h | 2 +- src/p_things.cpp | 8 +++++++- src/thingdef/thingdef_codeptr.cpp | 28 ++++++++++++++++++++++------ wadsrc/static/actors/actor.txt | 6 +++--- 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 0d74b4d42..67215cf41 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1510,7 +1510,7 @@ FUNC(LS_Thing_Raise) if (arg0==0) { - ok = P_Thing_Raise (it); + ok = P_Thing_Raise (it,NULL); } else { @@ -1518,7 +1518,7 @@ FUNC(LS_Thing_Raise) while ( (target = iterator.Next ()) ) { - ok |= P_Thing_Raise(target); + ok |= P_Thing_Raise(target,NULL); } } return ok; diff --git a/src/p_local.h b/src/p_local.h index dec80ecaa..c0a754e25 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -171,7 +171,7 @@ bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog); int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type); void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool add, bool setbob); void P_RemoveThing(AActor * actor); -bool P_Thing_Raise(AActor *thing); +bool P_Thing_Raise(AActor *thing, AActor *raiser); bool P_Thing_CanRaise(AActor *thing); const PClass *P_GetSpawnableType(int spawnnum); diff --git a/src/p_things.cpp b/src/p_things.cpp index 0189848e4..63173564c 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -412,7 +412,7 @@ void P_RemoveThing(AActor * actor) } -bool P_Thing_Raise(AActor *thing) +bool P_Thing_Raise(AActor *thing, AActor *raiser) { FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) @@ -445,6 +445,12 @@ bool P_Thing_Raise(AActor *thing) thing->Revive(); + if (raiser != NULL) + { + // Let's copy the friendliness of the one who raised it. + thing->CopyFriendliness(raiser, false); + } + thing->SetState (RaiseState); return true; } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 5629edd9e..a620f0080 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3761,11 +3761,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) // A_RaiseMaster // //=========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseMaster) { + ACTION_PARAM_START(1); + ACTION_PARAM_BOOL(copy, 0); + if (self->master != NULL) { - P_Thing_Raise(self->master); + if (copy) + P_Thing_Raise(self->master, self); + else + P_Thing_Raise(self->master, NULL); } } @@ -3774,8 +3780,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) // A_RaiseChildren // //=========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseChildren) { + ACTION_PARAM_START(1); + ACTION_PARAM_BOOL(copy, 0); TThinkerIterator it; AActor *mo; @@ -3783,7 +3791,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) { if (mo->master == self) { - P_Thing_Raise(mo); + if (copy) + P_Thing_Raise(mo, self); + else + P_Thing_Raise(mo, NULL); } } } @@ -3793,8 +3804,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) // A_RaiseSiblings // //=========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseSiblings) { + ACTION_PARAM_START(1); + ACTION_PARAM_BOOL(copy, 0); TThinkerIterator it; AActor *mo; @@ -3804,7 +3817,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) { if (mo->master == self->master && mo != self) { - P_Thing_Raise(mo); + if (copy) + P_Thing_Raise(mo, self); + else + P_Thing_Raise(mo, NULL); } } } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index c8e689dae..2f97c2a71 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -241,9 +241,9 @@ ACTOR Actor native //: Thinker action native A_KillMaster(name damagetype = "none", int flags = 0); action native A_KillChildren(name damagetype = "none", int flags = 0); action native A_KillSiblings(name damagetype = "none", int flags = 0); - action native A_RaiseMaster(); - action native A_RaiseChildren(); - action native A_RaiseSiblings(); + action native A_RaiseMaster(bool copy = 0); + action native A_RaiseChildren(bool copy = 0); + action native A_RaiseSiblings(bool copy = 0); action native A_CheckFloor(state label); action native A_CheckCeiling(state label); action native A_PlayerSkinCheck(state label); From a418f564e98eccfbff70f29156ee61ac7d72304a Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Fri, 28 Nov 2014 16:34:42 +1300 Subject: [PATCH 09/32] Fixed message duplication in logs - Any printed hud messages would have duplicate entries in logs. --- src/c_console.cpp | 14 -------------- src/p_acs.cpp | 7 ------- 2 files changed, 21 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index c6fe58749..e3e3d98fe 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1554,13 +1554,6 @@ void C_MidPrint (FFont *font, const char *msg) AddToConsole (-1, bar1); AddToConsole (-1, msg); AddToConsole (-1, bar3); - if (Logfile) - { - fputs (logbar, Logfile); - fputs (msg, Logfile); - fputs (logbar, Logfile); - fflush (Logfile); - } StatusBar->AttachMessage (new DHUDMessage (font, msg, 1.5f, 0.375f, 0, 0, (EColorRange)PrintColors[PRINTLEVELS], con_midtime), MAKE_ID('C','N','T','R')); @@ -1578,13 +1571,6 @@ void C_MidPrintBold (FFont *font, const char *msg) AddToConsole (-1, bar2); AddToConsole (-1, msg); AddToConsole (-1, bar3); - if (Logfile) - { - fputs (logbar, Logfile); - fputs (msg, Logfile); - fputs (logbar, Logfile); - fflush (Logfile); - } StatusBar->AttachMessage (new DHUDMessage (font, msg, 1.5f, 0.375f, 0, 0, (EColorRange)PrintColors[PRINTLEVELS+1], con_midtime), MAKE_ID('C','N','T','R')); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 2ff70c9e3..866087688 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -7725,13 +7725,6 @@ scriptwait: AddToConsole (-1, consolecolor); AddToConsole (-1, work); AddToConsole (-1, bar); - if (Logfile) - { - fputs (logbar, Logfile); - fputs (work, Logfile); - fputs (logbar, Logfile); - fflush (Logfile); - } } } } From e7da849f77765fc0ddf8db9ba4453b0f6e553f74 Mon Sep 17 00:00:00 2001 From: ChillyDoom Date: Sat, 29 Nov 2014 17:03:58 +0000 Subject: [PATCH 10/32] - Moved bot specific functions into DBot. --- src/b_bot.cpp | 4 +- src/b_bot.h | 71 ++++++------ src/b_func.cpp | 200 +++++++++++++++++----------------- src/b_move.cpp | 123 +++++++++++---------- src/b_think.cpp | 284 +++++++++++++++++++++++------------------------- src/p_mobj.cpp | 4 +- 6 files changed, 335 insertions(+), 351 deletions(-) diff --git a/src/b_bot.cpp b/src/b_bot.cpp index d2acdcab6..05cac045b 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -66,7 +66,7 @@ void DBot::Serialize (FArchive &arc) arc << savedyaw << savedpitch; } - else if (SaveVersion >= 4516) + else { arc << player; } @@ -105,7 +105,7 @@ void DBot::Tick () BotThinkCycles.Clock(); bglobal.m_Thinking = true; - bglobal.Think (player->mo, &netcmds[player - players][((gametic + 1)/ticdup)%BACKUPTICS]); + Think (); bglobal.m_Thinking = false; BotThinkCycles.Unclock(); } diff --git a/src/b_bot.h b/src/b_bot.h index 7740e5e00..69a2f7774 100644 --- a/src/b_bot.h +++ b/src/b_bot.h @@ -89,7 +89,7 @@ public: void ClearPlayer (int playernum, bool keepTeam); - //(B_Game.c) + //(b_game.cpp) void Main (); void Init (); void End(); @@ -99,23 +99,16 @@ public: bool LoadBots (); void ForgetBots (); - //(B_Func.c) - bool Check_LOS (AActor *mobj1, AActor *mobj2, angle_t vangle); + //(b_func.cpp) void StartTravel (); void FinishTravel (); + bool IsLeader (player_t *player); + void SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum); + fixed_t FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd); + bool SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm); - //(B_Think.c) - void Think (AActor *actor, ticcmd_t *cmd); - void WhatToGet (AActor *actor, AActor *item); - - //(B_move.c) - void Roam (AActor *actor, ticcmd_t *cmd); - bool Move (AActor *actor, ticcmd_t *cmd); - bool TryWalk (AActor *actor, ticcmd_t *cmd); - void NewChaseDir (AActor *actor, ticcmd_t *cmd); + //(b_move.cpp) bool CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cmd); - void TurnToAng (AActor *actor); - void Pitch (AActor *actor, AActor *target); bool IsDangerous (sector_t *sec); TArray getspawned; //Array of bots (their names) which should be spawned when starting a game. @@ -132,24 +125,9 @@ public: bool m_Thinking; private: - //(B_Game.c) + //(b_game.cpp) bool DoAddBot (BYTE *info, botskill_t skill); - //(B_Func.c) - bool Reachable (AActor *actor, AActor *target); - void Dofire (AActor *actor, ticcmd_t *cmd); - bool IsLeader (player_t *player); - AActor *Choose_Mate (AActor *bot); - AActor *Find_enemy (AActor *bot); - void SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum); - fixed_t FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd); - angle_t FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd); - bool SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm); - - //(B_Think.c) - void ThinkForMove (AActor *actor, ticcmd_t *cmd); - void Set_enemy (AActor *actor); - protected: bool ctf; int loaded_bots; @@ -168,13 +146,17 @@ public: void Serialize (FArchive &arc); void Tick (); + //(b_think.cpp) + void WhatToGet (AActor *item); + + //(b_func.cpp) + bool Check_LOS (AActor *to, angle_t vangle); + player_t *player; angle_t angle; // The wanted angle that the bot try to get every tic. // (used to get a smooth view movement) TObjPtr dest; // Move Destination. TObjPtr prev; // Previous move destination. - - TObjPtr enemy; // The dead meat. TObjPtr missile; // A threatening missile that needs to be avoided. TObjPtr mate; // Friend (used for grouping in teamplay or coop). @@ -204,6 +186,27 @@ public: fixed_t oldx; fixed_t oldy; + +private: + //(B_think.cpp) + void Think (); + void ThinkForMove (ticcmd_t *cmd); + void Set_enemy (); + + //(B_func.cpp) + bool Reachable (AActor *target); + void Dofire (ticcmd_t *cmd); + AActor *Choose_Mate (); + AActor *Find_enemy (); + angle_t FireRox (AActor *enemy, ticcmd_t *cmd); + + //(b_move.cpp) + void Roam (ticcmd_t *cmd); + bool Move (ticcmd_t *cmd); + bool TryWalk (ticcmd_t *cmd); + void NewChaseDir (ticcmd_t *cmd); + void TurnToAng (); + void Pitch (AActor *target); }; @@ -220,7 +223,3 @@ EXTERN_CVAR (Bool, bot_watersplash) EXTERN_CVAR (Bool, bot_chat) #endif // __B_BOT_H__ - - - - diff --git a/src/b_func.cpp b/src/b_func.cpp index 349155a81..7165d2cc1 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -24,24 +24,23 @@ static FRandom pr_botdofire ("BotDoFire"); -//Checks TRUE reachability from -//one looker to another. First mobj (looker) is looker. -bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget) +//Checks TRUE reachability from bot to a looker. +bool DBot::Reachable (AActor *rtarget) { - if (looker == rtarget) + if (player->mo == rtarget) return false; if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) - rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y)) - < looker->height) //Where rtarget is, looker can't be. + < player->mo->height) //Where rtarget is, player->mo can't be. return false; - sector_t *last_s = looker->Sector; - fixed_t last_z = last_s->floorplane.ZatPoint (looker->x, looker->y); - fixed_t estimated_dist = P_AproxDistance (looker->x - rtarget->x, looker->y - rtarget->y); + sector_t *last_s = player->mo->Sector; + fixed_t last_z = last_s->floorplane.ZatPoint (player->mo->x, player->mo->y); + fixed_t estimated_dist = P_AproxDistance (player->mo->x - rtarget->x, player->mo->y - rtarget->y); bool reachable = true; - FPathTraverse it(looker->x+looker->velx, looker->y+looker->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS); + FPathTraverse it(player->mo->x+player->mo->velx, player->mo->y+player->mo->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS); intercept_t *in; while ((in = it.Next())) { @@ -55,8 +54,8 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget) frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST); dist = FixedMul (frac, MAX_TRAVERSE_DIST); - hitx = it.Trace().x + FixedMul (looker->velx, frac); - hity = it.Trace().y + FixedMul (looker->vely, frac); + hitx = it.Trace().x + FixedMul (player->mo->velx, frac); + hity = it.Trace().y + FixedMul (player->mo->vely, frac); if (in->isaline) { @@ -76,7 +75,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget) if (!bglobal.IsDangerous (s) && //Any nukage/lava? (floorheight <= (last_z+MAXMOVEHEIGHT) && ((ceilingheight == floorheight && line->special) - || (ceilingheight - floorheight) >= looker->height))) //Does it fit? + || (ceilingheight - floorheight) >= player->mo->height))) //Does it fit? { last_z = floorheight; last_s = s; @@ -95,7 +94,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget) } thing = in->d.thing; - if (thing == looker) //Can't reach self in this case. + if (thing == player->mo) //Can't reach self in this case. continue; if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT))) { @@ -115,16 +114,16 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget) //if these conditions are true, the function returns true. //GOOD TO KNOW is that the player's view angle //in doom is 90 degrees infront. -bool FCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle) +bool DBot::Check_LOS (AActor *to, angle_t vangle) { - if (!P_CheckSight (from, to, SF_SEEPASTBLOCKEVERYTHING)) + if (!P_CheckSight (player->mo, to, SF_SEEPASTBLOCKEVERYTHING)) return false; // out of sight if (vangle == ANGLE_MAX) return true; if (vangle == 0) return false; //Looker seems to be blind. - return (angle_t)abs (R_PointToAngle2 (from->x, from->y, to->x, to->y) - from->angle) <= vangle/2; + return (angle_t)abs (R_PointToAngle2 (player->mo->x, player->mo->y, to->x, to->y) - player->mo->angle) <= vangle/2; } //------------------------------------- @@ -132,7 +131,7 @@ bool FCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle) //------------------------------------- //The bot will check if it's time to fire //and do so if that is the case. -void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd) +void DBot::Dofire (ticcmd_t *cmd) { bool no_fire; //used to prevent bot from pumping rockets into nearby walls. int aiming_penalty=0; //For shooting at shading target, if screen is red, MAKEME: When screen red. @@ -140,49 +139,48 @@ void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd) fixed_t dist; angle_t an; int m; - AActor *enemy = actor->player->Bot->enemy; if (!enemy || !(enemy->flags & MF_SHOOTABLE) || enemy->health <= 0) return; - if (actor->player->ReadyWeapon == NULL) + if (player->ReadyWeapon == NULL) return; - if (actor->player->damagecount > actor->player->Bot->skill.isp) + if (player->damagecount > skill.isp) { - actor->player->Bot->first_shot = true; + first_shot = true; return; } //Reaction skill thing. - if (actor->player->Bot->first_shot && - !(actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_REACTION_SKILL_THING)) + if (first_shot && + !(player->ReadyWeapon->WeaponFlags & WIF_BOT_REACTION_SKILL_THING)) { - actor->player->Bot->t_react = (100-actor->player->Bot->skill.reaction+1)/((pr_botdofire()%3)+3); + t_react = (100-skill.reaction+1)/((pr_botdofire()%3)+3); } - actor->player->Bot->first_shot = false; - if (actor->player->Bot->t_react) + first_shot = false; + if (t_react) return; //MAKEME: Decrease the rocket suicides even more. no_fire = true; - //actor->player->angle = R_PointToAngle2(actor->x, actor->y, actor->player->enemy->x, actor->player->enemy->y); + //angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y); //Distance to enemy. - dist = P_AproxDistance ((actor->x + actor->velx) - (enemy->x + enemy->velx), - (actor->y + actor->vely) - (enemy->y + enemy->vely)); + dist = P_AproxDistance ((player->mo->x + player->mo->velx) - (enemy->x + enemy->velx), + (player->mo->y + player->mo->vely) - (enemy->y + enemy->vely)); //FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go. - if (actor->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON) + if (player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON) { - if ((actor->player->ReadyWeapon->ProjectileType != NULL)) + if ((player->ReadyWeapon->ProjectileType != NULL)) { - if (actor->player->ReadyWeapon->CheckAmmo (AWeapon::PrimaryFire, false, true)) + if (player->ReadyWeapon->CheckAmmo (AWeapon::PrimaryFire, false, true)) { // This weapon can fire a projectile and has enough ammo to do so goto shootmissile; } - else if (!(actor->player->ReadyWeapon->WeaponFlags & WIF_AMMO_OPTIONAL)) + else if (!(player->ReadyWeapon->WeaponFlags & WIF_AMMO_OPTIONAL)) { // Ammo is required, so don't shoot. This is for weapons that shoot // missiles that die at close range, such as the powered-up Phoneix Rod. @@ -195,51 +193,51 @@ void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd) no_fire = (dist > (MELEERANGE*4)); } } - else if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_BFG) + else if (player->ReadyWeapon->WeaponFlags & WIF_BOT_BFG) { //MAKEME: This should be smarter. - if ((pr_botdofire()%200)<=actor->player->Bot->skill.reaction) - if(Check_LOS(actor, actor->player->Bot->enemy, SHOOTFOV)) + if ((pr_botdofire()%200)<=skill.reaction) + if(Check_LOS(enemy, SHOOTFOV)) no_fire = false; } - else if (actor->player->ReadyWeapon->ProjectileType != NULL) + else if (player->ReadyWeapon->ProjectileType != NULL) { - if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) + if (player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) { //Special rules for RL - an = FireRox (actor, enemy, cmd); + an = FireRox (enemy, cmd); if(an) { - actor->player->Bot->angle = an; + angle = an; //have to be somewhat precise. to avoid suicide. - if (abs (actor->player->Bot->angle - actor->angle) < 12*ANGLE_1) + if (abs (angle - player->mo->angle) < 12*ANGLE_1) { - actor->player->Bot->t_rocket = 9; + t_rocket = 9; no_fire = false; } } } // prediction aiming shootmissile: - dist = P_AproxDistance (actor->x - enemy->x, actor->y - enemy->y); - m = dist / GetDefaultByType (actor->player->ReadyWeapon->ProjectileType)->Speed; - SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1); - actor->player->Bot->angle = R_PointToAngle2 (actor->x, actor->y, body1->x, body1->y); - if (Check_LOS (actor, enemy, SHOOTFOV)) + dist = P_AproxDistance (player->mo->x - enemy->x, player->mo->y - enemy->y); + m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed; + bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1); + angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y); + if (Check_LOS (enemy, SHOOTFOV)) no_fire = false; } else { //Other weapons, mostly instant hit stuff. - actor->player->Bot->angle = R_PointToAngle2 (actor->x, actor->y, enemy->x, enemy->y); + angle = R_PointToAngle2 (player->mo->x, player->mo->y, enemy->x, enemy->y); aiming_penalty = 0; if (enemy->flags & MF_SHADOW) aiming_penalty += (pr_botdofire()%25)+10; - if (enemy->Sector->lightlevelplayer->powers & PW_INFRARED)*/) + if (enemy->Sector->lightlevelpowers & PW_INFRARED)*/) aiming_penalty += pr_botdofire()%40;//Dark - if (actor->player->damagecount) - aiming_penalty += actor->player->damagecount; //Blood in face makes it hard to aim - aiming_value = actor->player->Bot->skill.aiming - aiming_penalty; + if (player->damagecount) + aiming_penalty += player->damagecount; //Blood in face makes it hard to aim + aiming_value = skill.aiming - aiming_penalty; if (aiming_value <= 0) aiming_value = 1; m = ((SHOOTFOV/2)-(aiming_value*SHOOTFOV/200)); //Higher skill is more accurate @@ -248,18 +246,18 @@ shootmissile: if (m) { - if (actor->player->Bot->increase) - actor->player->Bot->angle += m; + if (increase) + angle += m; else - actor->player->Bot->angle -= m; + angle -= m; } - if (abs (actor->player->Bot->angle - actor->angle) < 4*ANGLE_1) + if (abs (angle - player->mo->angle) < 4*ANGLE_1) { - actor->player->Bot->increase = !actor->player->Bot->increase; + increase = !increase; } - if (Check_LOS (actor, enemy, (SHOOTFOV/2))) + if (Check_LOS (enemy, (SHOOTFOV/2))) no_fire = false; } if (!no_fire) //If going to fire weapon @@ -267,7 +265,7 @@ shootmissile: cmd->ucmd.buttons |= BT_ATTACK; } //Prevents bot from jerking, when firing automatic things with low skill. - //actor->angle = R_PointToAngle2(actor->x, actor->y, actor->player->enemy->x, actor->player->enemy->y); + //player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y); } bool FCajunMaster::IsLeader (player_t *player) @@ -287,7 +285,7 @@ bool FCajunMaster::IsLeader (player_t *player) //This function is called every //tick (for each bot) to set //the mate (teammate coop mate). -AActor *FCajunMaster::Choose_Mate (AActor *bot) +AActor *DBot::Choose_Mate () { int count; fixed_t closest_dist, test; @@ -295,20 +293,20 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot) AActor *observer; //is mate alive? - if (bot->player->Bot->mate) + if (mate) { - if (bot->player->Bot->mate->health <= 0) - bot->player->Bot->mate = NULL; + if (mate->health <= 0) + mate = NULL; else - bot->player->Bot->last_mate = bot->player->Bot->mate; + last_mate = mate; } - if (bot->player->Bot->mate) //Still is.. - return bot->player->Bot->mate; + if (mate) //Still is.. + return mate; //Check old_mates status. - if (bot->player->Bot->last_mate) - if (bot->player->Bot->last_mate->health <= 0) - bot->player->Bot->last_mate = NULL; + if (last_mate) + if (last_mate->health <= 0) + last_mate = NULL; target = NULL; closest_dist = FIXED_MAX; @@ -324,17 +322,17 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot) if (playeringame[count] && client->mo - && bot != client->mo - && (bot->IsTeammate (client->mo) || !deathmatch) + && player->mo != client->mo + && (player->mo->IsTeammate (client->mo) || !deathmatch) && client->mo->health > 0 && client->mo != observer - && ((bot->health/2) <= client->mo->health || !deathmatch) - && !IsLeader(client)) //taken? + && ((player->mo->health/2) <= client->mo->health || !deathmatch) + && !bglobal.IsLeader(client)) //taken? { - if (P_CheckSight (bot, client->mo, SF_IGNOREVISIBILITY)) + if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY)) { - test = P_AproxDistance (client->mo->x - bot->x, - client->mo->y - bot->y); + test = P_AproxDistance (client->mo->x - player->mo->x, + client->mo->y - player->mo->y); if (test < closest_dist) { @@ -347,15 +345,15 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot) /* //Make a introducing to mate. - if(target && target!=bot->player->last_mate) + if(target && target!=last_mate) { if((P_Random()%(200*bglobal.botnum))<3) { - bot->player->chat = c_teamup; + chat = c_teamup; if(target->bot) - strcpy(bot->player->c_target, botsingame[target->bot_id]); + strcpy(c_target, botsingame[target->bot_id]); else if(target->player) - strcpy(bot->player->c_target, player_names[target->play_id]); + strcpy(c_target, player_names[target->play_id]); } } */ @@ -365,7 +363,7 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot) } //MAKEME: Make this a smart decision -AActor *FCajunMaster::Find_enemy (AActor *bot) +AActor *DBot::Find_enemy () { int count; fixed_t closest_dist, temp; //To target. @@ -375,15 +373,15 @@ AActor *FCajunMaster::Find_enemy (AActor *bot) if (!deathmatch) { // [RH] Take advantage of the Heretic/Hexen code to be a little smarter - return P_RoughMonsterSearch (bot, 20); + return P_RoughMonsterSearch (player->mo, 20); } //Note: It's hard to ambush a bot who is not alone - if (bot->player->Bot->allround || bot->player->Bot->mate) + if (allround || mate) vangle = ANGLE_MAX; else vangle = ENEMY_SCAN_FOV; - bot->player->Bot->allround = false; + allround = false; target = NULL; closest_dist = FIXED_MAX; @@ -396,21 +394,21 @@ AActor *FCajunMaster::Find_enemy (AActor *bot) { player_t *client = &players[count]; if (playeringame[count] - && !bot->IsTeammate (client->mo) + && !player->mo->IsTeammate (client->mo) && client->mo != observer && client->mo->health > 0 - && bot != client->mo) + && player->mo != client->mo) { - if (Check_LOS (bot, client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up. - //if(P_CheckSight(bot, players[count].mo)) + if (Check_LOS (client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up. + //if(P_CheckSight(player->mo, players[count].mo)) { - temp = P_AproxDistance (client->mo->x - bot->x, - client->mo->y - bot->y); + temp = P_AproxDistance (client->mo->x - player->mo->x, + client->mo->y - player->mo->y); //Too dark? if (temp > DARK_DIST && client->mo->Sector->lightlevel < WHATS_DARK /*&& - bot->player->Powers & PW_INFRARED*/) + player->Powers & PW_INFRARED*/) continue; if (temp < closest_dist) @@ -494,16 +492,16 @@ fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd) return dist; } -angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd) +angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) { fixed_t dist; angle_t ang; AActor *actor; int m; - SetBodyAt (bot->x + FixedMul(bot->velx, 5*FRACUNIT), - bot->y + FixedMul(bot->vely, 5*FRACUNIT), - bot->z + (bot->height / 2), 2); + bglobal.SetBodyAt (player->mo->x + FixedMul(player->mo->velx, 5*FRACUNIT), + player->mo->y + FixedMul(player->mo->vely, 5*FRACUNIT), + player->mo->z + (player->mo->height / 2), 2); actor = bglobal.body2; @@ -513,16 +511,16 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd) //Predict. m = (((dist+1)/FRACUNIT) / GetDefaultByName("Rocket")->Speed); - SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)), - enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1); + bglobal.SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)), + enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1); dist = P_AproxDistance(actor->x-bglobal.body1->x, actor->y-bglobal.body1->y); //try the predicted location if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile { FCheckPosition tm; - if (SafeCheckPosition (bot, actor->x, actor->y, tm)) + if (bglobal.SafeCheckPosition (player->mo, actor->x, actor->y, tm)) { - if (FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST) + if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST) { ang = R_PointToAngle2 (actor->x, actor->y, bglobal.body1->x, bglobal.body1->y); return ang; @@ -532,9 +530,9 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd) //Try fire straight. if (P_CheckSight (actor, enemy, 0)) { - if (FakeFire (bot, enemy, cmd) >= SAFE_SELF_MISDIST) + if (bglobal.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST) { - ang = R_PointToAngle2(bot->x, bot->y, enemy->x, enemy->y); + ang = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); return ang; } } diff --git a/src/b_move.cpp b/src/b_move.cpp index f020cf4fc..fd0405457 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -27,57 +27,57 @@ static FRandom pr_botnewchasedir ("BotNewChaseDir"); extern dirtype_t opposite[9]; extern dirtype_t diags[4]; -//Called while the bot moves after its player->dest mobj +//Called while the bot moves after its dest mobj //which can be a weapon/enemy/item whatever. -void FCajunMaster::Roam (AActor *actor, ticcmd_t *cmd) +void DBot::Roam (ticcmd_t *cmd) { int delta; - if (Reachable(actor, actor->player->Bot->dest)) + if (Reachable(dest)) { // Straight towards it. - actor->player->Bot->angle = R_PointToAngle2(actor->x, actor->y, actor->player->Bot->dest->x, actor->player->Bot->dest->y); + angle = R_PointToAngle2(player->mo->x, player->mo->y, dest->x, dest->y); } - else if (actor->movedir < 8) // turn towards movement direction if not there yet + else if (player->mo->movedir < 8) // turn towards movement direction if not there yet { - actor->player->Bot->angle &= (angle_t)(7<<29); - delta = actor->player->Bot->angle - (actor->movedir << 29); + angle &= (angle_t)(7<<29); + delta = angle - (player->mo->movedir << 29); if (delta > 0) - actor->player->Bot->angle -= ANG45; + angle -= ANG45; else if (delta < 0) - actor->player->Bot->angle += ANG45; + angle += ANG45; } // chase towards destination. - if (--actor->movecount < 0 || !Move (actor, cmd)) + if (--player->mo->movecount < 0 || !Move (cmd)) { - NewChaseDir (actor, cmd); + NewChaseDir (cmd); } } -bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd) +bool DBot::Move (ticcmd_t *cmd) { fixed_t tryx, tryy; bool try_ok; int good; - if (actor->movedir == DI_NODIR) + if (player->mo->movedir == DI_NODIR) return false; - if ((unsigned)actor->movedir >= 8) + if ((unsigned)player->mo->movedir >= 8) I_Error ("Weird bot movedir!"); - tryx = actor->x + 8*xspeed[actor->movedir]; - tryy = actor->y + 8*yspeed[actor->movedir]; + tryx = player->mo->x + 8*xspeed[player->mo->movedir]; + tryy = player->mo->y + 8*yspeed[player->mo->movedir]; - try_ok = CleanAhead (actor, tryx, tryy, cmd); + try_ok = bglobal.CleanAhead (player->mo, tryx, tryy, cmd); if (!try_ok) //Anything blocking that could be opened etc.. { if (!spechit.Size ()) return false; - actor->movedir = DI_NODIR; + player->mo->movedir = DI_NODIR; good = 0; line_t *ld; @@ -86,16 +86,16 @@ bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd) { bool tryit = true; - if (ld->special == Door_LockedRaise && !P_CheckKeys (actor, ld->args[3], false)) + if (ld->special == Door_LockedRaise && !P_CheckKeys (player->mo, ld->args[3], false)) tryit = false; - else if (ld->special == Generic_Door && !P_CheckKeys (actor, ld->args[4], false)) + else if (ld->special == Generic_Door && !P_CheckKeys (player->mo, ld->args[4], false)) tryit = false; if (tryit && - (P_TestActivateLine (ld, actor, 0, SPAC_Use) || - P_TestActivateLine (ld, actor, 0, SPAC_Push))) + (P_TestActivateLine (ld, player->mo, 0, SPAC_Use) || + P_TestActivateLine (ld, player->mo, 0, SPAC_Push))) { - good |= ld == actor->BlockingLine ? 1 : 2; + good |= ld == player->mo->BlockingLine ? 1 : 2; } } if (good && ((pr_botopendoor() >= 203) ^ (good & 1))) @@ -113,16 +113,16 @@ bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd) return true; } -bool FCajunMaster::TryWalk (AActor *actor, ticcmd_t *cmd) +bool DBot::TryWalk (ticcmd_t *cmd) { - if (!Move (actor, cmd)) + if (!Move (cmd)) return false; - actor->movecount = pr_bottrywalk() & 60; + player->mo->movecount = pr_bottrywalk() & 60; return true; } -void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd) +void DBot::NewChaseDir (ticcmd_t *cmd) { fixed_t deltax; fixed_t deltay; @@ -134,7 +134,7 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd) dirtype_t turnaround; - if (!actor->player->Bot->dest) + if (!dest) { #ifndef BOT_RELEASE_COMPILE Printf ("Bot tried move without destination\n"); @@ -142,11 +142,11 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd) return; } - olddir = (dirtype_t)actor->movedir; + olddir = (dirtype_t)player->mo->movedir; turnaround = opposite[olddir]; - deltax = actor->player->Bot->dest->x - actor->x; - deltay = actor->player->Bot->dest->y - actor->y; + deltax = dest->x - player->mo->x; + deltay = dest->y - player->mo->y; if (deltax > 10*FRACUNIT) d[1] = DI_EAST; @@ -165,8 +165,8 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd) // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { - actor->movedir = diags[((deltay<0)<<1)+(deltax>0)]; - if (actor->movedir != turnaround && TryWalk(actor, cmd)) + player->mo->movedir = diags[((deltay<0)<<1)+(deltax>0)]; + if (player->mo->movedir != turnaround && TryWalk(cmd)) return; } @@ -186,16 +186,16 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd) if (d[1]!=DI_NODIR) { - actor->movedir = d[1]; - if (TryWalk (actor, cmd)) + player->mo->movedir = d[1]; + if (TryWalk (cmd)) return; } if (d[2]!=DI_NODIR) { - actor->movedir = d[2]; + player->mo->movedir = d[2]; - if (TryWalk(actor, cmd)) + if (TryWalk(cmd)) return; } @@ -203,9 +203,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd) // so pick another direction. if (olddir!=DI_NODIR) { - actor->movedir = olddir; + player->mo->movedir = olddir; - if (TryWalk(actor, cmd)) + if (TryWalk(cmd)) return; } @@ -218,9 +218,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd) { if (tdir!=turnaround) { - actor->movedir = tdir; + player->mo->movedir = tdir; - if (TryWalk(actor, cmd)) + if (TryWalk(cmd)) return; } } @@ -233,9 +233,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd) { if (tdir!=turnaround) { - actor->movedir = tdir; + player->mo->movedir = tdir; - if (TryWalk(actor, cmd)) + if (TryWalk(cmd)) return; } } @@ -243,12 +243,12 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd) if (turnaround != DI_NODIR) { - actor->movedir = turnaround; - if (TryWalk(actor, cmd)) + player->mo->movedir = turnaround; + if (TryWalk(cmd)) return; } - actor->movedir = DI_NODIR; // can not move + player->mo->movedir = DI_NODIR; // can not move } @@ -307,48 +307,48 @@ bool FCajunMaster::CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cm #define MAXTURN (15*ANGLE_1) //Max degrees turned in one tic. Lower is smother but may cause the bot not getting where it should = crash #define TURNSENS 3 //Higher is smoother but slower turn. -void FCajunMaster::TurnToAng (AActor *actor) +void DBot::TurnToAng () { int maxturn = MAXTURN; - if (actor->player->ReadyWeapon != NULL) + if (player->ReadyWeapon != NULL) { - if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) + if (player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) { - if (actor->player->Bot->t_roam && !actor->player->Bot->missile) + if (t_roam && !missile) { //Keep angle that where when shot where decided. return; } } - if(actor->player->Bot->enemy) - if(!actor->player->Bot->dest) //happens when running after item in combat situations, or normal, prevents weak turns - if(actor->player->ReadyWeapon->ProjectileType == NULL && !(actor->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON)) - if(Check_LOS(actor, actor->player->Bot->enemy, SHOOTFOV+5*ANGLE_1)) + if(enemy) + if(!dest) //happens when running after item in combat situations, or normal, prevents weak turns + if(player->ReadyWeapon->ProjectileType == NULL && !(player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON)) + if(Check_LOS(enemy, SHOOTFOV+5*ANGLE_1)) maxturn = 3; } - int distance = actor->player->Bot->angle - actor->angle; + int distance = angle - player->mo->angle; - if (abs (distance) < OKAYRANGE && !actor->player->Bot->enemy) + if (abs (distance) < OKAYRANGE && !enemy) return; distance /= TURNSENS; if (abs (distance) > maxturn) distance = distance < 0 ? -maxturn : maxturn; - actor->angle += distance; + player->mo->angle += distance; } -void FCajunMaster::Pitch (AActor *actor, AActor *target) +void DBot::Pitch (AActor *target) { double aim; double diff; - diff = target->z - actor->z; - aim = atan (diff / (double)P_AproxDistance (actor->x - target->x, actor->y - target->y)); - actor->pitch = -(int)(aim * ANGLE_180/M_PI); + diff = target->z - player->mo->z; + aim = atan (diff / (double)P_AproxDistance (player->mo->x - target->x, player->mo->y - target->y)); + player->mo->pitch = -(int)(aim * ANGLE_180/M_PI); } //Checks if a sector is dangerous. @@ -371,4 +371,3 @@ bool FCajunMaster::IsDangerous (sector_t *sec) || special == Damage_InstantDeath || special == sDamage_SuperHellslime; } - diff --git a/src/b_think.cpp b/src/b_think.cpp index e5ee8775c..34baeee9c 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -24,47 +24,49 @@ static FRandom pr_botmove ("BotMove"); //This function is called each tic for each bot, //so this is what the bot does. -void FCajunMaster::Think (AActor *actor, ticcmd_t *cmd) +void DBot::Think () { + ticcmd_t *cmd = &netcmds[player - players][((gametic + 1)/ticdup)%BACKUPTICS]; + memset (cmd, 0, sizeof(*cmd)); - if (actor->player->Bot->enemy && actor->player->Bot->enemy->health <= 0) - actor->player->Bot->enemy = NULL; + if (enemy && enemy->health <= 0) + enemy = NULL; - if (actor->health > 0) //Still alive + if (player->mo->health > 0) //Still alive { if (teamplay || !deathmatch) - actor->player->Bot->mate = Choose_Mate (actor); + mate = Choose_Mate (); - angle_t oldyaw = actor->angle; - int oldpitch = actor->pitch; + angle_t oldyaw = player->mo->angle; + int oldpitch = player->mo->pitch; - Set_enemy (actor); - ThinkForMove (actor, cmd); - TurnToAng (actor); + Set_enemy (); + ThinkForMove (cmd); + TurnToAng (); - cmd->ucmd.yaw = (short)((actor->angle - oldyaw) >> 16) / ticdup; - cmd->ucmd.pitch = (short)((oldpitch - actor->pitch) >> 16); + cmd->ucmd.yaw = (short)((player->mo->angle - oldyaw) >> 16) / ticdup; + cmd->ucmd.pitch = (short)((oldpitch - player->mo->pitch) >> 16); if (cmd->ucmd.pitch == -32768) cmd->ucmd.pitch = -32767; cmd->ucmd.pitch /= ticdup; - actor->angle = oldyaw + (cmd->ucmd.yaw << 16) * ticdup; - actor->pitch = oldpitch - (cmd->ucmd.pitch << 16) * ticdup; + player->mo->angle = oldyaw + (cmd->ucmd.yaw << 16) * ticdup; + player->mo->pitch = oldpitch - (cmd->ucmd.pitch << 16) * ticdup; } - if (actor->player->Bot->t_active) actor->player->Bot->t_active--; - if (actor->player->Bot->t_strafe) actor->player->Bot->t_strafe--; - if (actor->player->Bot->t_react) actor->player->Bot->t_react--; - if (actor->player->Bot->t_fight) actor->player->Bot->t_fight--; - if (actor->player->Bot->t_rocket) actor->player->Bot->t_rocket--; - if (actor->player->Bot->t_roam) actor->player->Bot->t_roam--; + if (t_active) t_active--; + if (t_strafe) t_strafe--; + if (t_react) t_react--; + if (t_fight) t_fight--; + if (t_rocket) t_rocket--; + if (t_roam) t_roam--; //Respawn ticker - if (actor->player->Bot->t_respawn) + if (t_respawn) { - actor->player->Bot->t_respawn--; + t_respawn--; } - else if (actor->health <= 0) + else if (player->mo->health <= 0) { // Time to respawn cmd->ucmd.buttons |= BT_USE; } @@ -72,62 +74,57 @@ void FCajunMaster::Think (AActor *actor, ticcmd_t *cmd) //how the bot moves. //MAIN movement function. -void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd) +void DBot::ThinkForMove (ticcmd_t *cmd) { - player_t *b; fixed_t dist; bool stuck; int r; - b = actor->player; - if (b->Bot == NULL) - return; - stuck = false; - dist = b->Bot->dest ? P_AproxDistance(actor->x-b->Bot->dest->x, actor->y-b->Bot->dest->y) : 0; + dist = dest ? P_AproxDistance(player->mo->x-dest->x, player->mo->y-dest->y) : 0; - if (b->Bot->missile && - ((!b->Bot->missile->velx || !b->Bot->missile->vely) || !Check_LOS(actor, b->Bot->missile, SHOOTFOV*3/2))) + if (missile && + ((!missile->velx || !missile->vely) || !Check_LOS(missile, SHOOTFOV*3/2))) { - b->Bot->sleft = !b->Bot->sleft; - b->Bot->missile = NULL; //Probably ended its travel. + sleft = !sleft; + missile = NULL; //Probably ended its travel. } - if (actor->pitch > 0) - actor->pitch -= 80; - else if (actor->pitch <= -60) - actor->pitch += 80; + if (player->mo->pitch > 0) + player->mo->pitch -= 80; + else if (player->mo->pitch <= -60) + player->mo->pitch += 80; //HOW TO MOVE: - if (b->Bot->missile && (P_AproxDistance(actor->x-b->Bot->missile->x, actor->y-b->Bot->missile->y)mo->x-missile->x, player->mo->y-missile->y)Bot->missile); - actor->player->Bot->angle = R_PointToAngle2(actor->x, actor->y, b->Bot->missile->x, b->Bot->missile->y); - cmd->ucmd.sidemove = b->Bot->sleft ? -SIDERUN : SIDERUN; + Pitch (missile); + angle = R_PointToAngle2(player->mo->x, player->mo->y, missile->x, missile->y); + cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN; cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best. - if ((P_AproxDistance(actor->x-b->Bot->oldx, actor->y-b->Bot->oldy)<50000) - && b->Bot->t_strafe<=0) + if ((P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000) + && t_strafe<=0) { - b->Bot->t_strafe = 5; - b->Bot->sleft = !b->Bot->sleft; + t_strafe = 5; + sleft = !sleft; } //If able to see enemy while avoiding missile, still fire at enemy. - if (b->Bot->enemy && Check_LOS (actor, b->Bot->enemy, SHOOTFOV)) - Dofire (actor, cmd); //Order bot to fire current weapon + if (enemy && Check_LOS (enemy, SHOOTFOV)) + Dofire (cmd); //Order bot to fire current weapon } - else if (b->Bot->enemy && P_CheckSight (actor, b->Bot->enemy, 0)) //Fight! + else if (enemy && P_CheckSight (player->mo, enemy, 0)) //Fight! { - Pitch (actor, b->Bot->enemy); + Pitch (enemy); //Check if it's more important to get an item than fight. - if (b->Bot->dest && (b->Bot->dest->flags&MF_SPECIAL)) //Must be an item, that is close enough. + if (dest && (dest->flags&MF_SPECIAL)) //Must be an item, that is close enough. { -#define is(x) b->Bot->dest->IsKindOf (PClass::FindClass (#x)) +#define is(x) dest->IsKindOf (PClass::FindClass (#x)) if ( ( - (actor->health < b->Bot->skill.isp && + (player->mo->health < skill.isp && (is (Medikit) || is (Stimpack) || is (Soulsphere) || @@ -140,78 +137,78 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd) is (Megasphere) ) || dist < (GETINCOMBAT/4) || - (b->ReadyWeapon == NULL || b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON) + (player->ReadyWeapon == NULL || player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON) ) - && (dist < GETINCOMBAT || (b->ReadyWeapon == NULL || b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) - && Reachable (actor, b->Bot->dest)) + && (dist < GETINCOMBAT || (player->ReadyWeapon == NULL || player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) + && Reachable (dest)) #undef is { goto roam; //Pick it up, no matter the situation. All bonuses are nice close up. } } - b->Bot->dest = NULL; //To let bot turn right + dest = NULL; //To let bot turn right - if (b->ReadyWeapon != NULL && !(b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) - actor->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting. + if (player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) + player->mo->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting. - if (!(b->Bot->enemy->flags3 & MF3_ISMONSTER)) - b->Bot->t_fight = AFTERTICS; + if (!(enemy->flags3 & MF3_ISMONSTER)) + t_fight = AFTERTICS; - if (b->Bot->t_strafe <= 0 && - (P_AproxDistance(actor->x-b->Bot->oldx, actor->y-b->Bot->oldy)<50000 + if (t_strafe <= 0 && + (P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000 || ((pr_botmove()%30)==10)) ) { stuck = true; - b->Bot->t_strafe = 5; - b->Bot->sleft = !b->Bot->sleft; + t_strafe = 5; + sleft = !sleft; } - b->Bot->angle = R_PointToAngle2(actor->x, actor->y, b->Bot->enemy->x, b->Bot->enemy->y); + angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); - if (b->ReadyWeapon == NULL || - P_AproxDistance(actor->x-b->Bot->enemy->x, actor->y-b->Bot->enemy->y) > - b->ReadyWeapon->MoveCombatDist) + if (player->ReadyWeapon == NULL || + P_AproxDistance(player->mo->x-enemy->x, player->mo->y-enemy->y) > + player->ReadyWeapon->MoveCombatDist) { // If a monster, use lower speed (just for cooler apperance while strafing down doomed monster) - cmd->ucmd.forwardmove = (b->Bot->enemy->flags3 & MF3_ISMONSTER) ? FORWARDWALK : FORWARDRUN; + cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? FORWARDWALK : FORWARDRUN; } else if (!stuck) //Too close, so move away. { // If a monster, use lower speed (just for cooler apperance while strafing down doomed monster) - cmd->ucmd.forwardmove = (b->Bot->enemy->flags3 & MF3_ISMONSTER) ? -FORWARDWALK : -FORWARDRUN; + cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? -FORWARDWALK : -FORWARDRUN; } //Strafing. - if (b->Bot->enemy->flags3 & MF3_ISMONSTER) //It's just a monster so take it down cool. + if (enemy->flags3 & MF3_ISMONSTER) //It's just a monster so take it down cool. { - cmd->ucmd.sidemove = b->Bot->sleft ? -SIDEWALK : SIDEWALK; + cmd->ucmd.sidemove = sleft ? -SIDEWALK : SIDEWALK; } else { - cmd->ucmd.sidemove = b->Bot->sleft ? -SIDERUN : SIDERUN; + cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN; } - Dofire (actor, cmd); //Order bot to fire current weapon + Dofire (cmd); //Order bot to fire current weapon } - else if (b->Bot->mate && !b->Bot->enemy && (!b->Bot->dest || b->Bot->dest==b->Bot->mate)) //Follow mate move. + else if (mate && !enemy && (!dest || dest==mate)) //Follow mate move. { fixed_t matedist; - Pitch (actor, b->Bot->mate); + Pitch (mate); - if (!Reachable (actor, b->Bot->mate)) + if (!Reachable (mate)) { - if (b->Bot->mate == b->Bot->dest && pr_botmove.Random() < 32) + if (mate == dest && pr_botmove.Random() < 32) { // [RH] If the mate is the dest, pick a new dest sometimes - b->Bot->dest = NULL; + dest = NULL; } goto roam; } - actor->player->Bot->angle = R_PointToAngle2(actor->x, actor->y, b->Bot->mate->x, b->Bot->mate->y); + angle = R_PointToAngle2(player->mo->x, player->mo->y, mate->x, mate->y); - matedist = P_AproxDistance(actor->x - b->Bot->mate->x, actor->y - b->Bot->mate->y); + matedist = P_AproxDistance(player->mo->x - mate->x, player->mo->y - mate->y); if (matedist > (FRIEND_DIST*2)) cmd->ucmd.forwardmove = FORWARDRUN; else if (matedist > FRIEND_DIST) @@ -221,42 +218,42 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd) } else //Roam after something. { - b->Bot->first_shot = true; + first_shot = true; ///// roam: ///// - if (b->Bot->enemy && Check_LOS (actor, b->Bot->enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it. - Dofire (actor, cmd); //Order bot to fire current weapon + if (enemy && Check_LOS (enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it. + Dofire (cmd); //Order bot to fire current weapon - if (b->Bot->dest && !(b->Bot->dest->flags&MF_SPECIAL) && b->Bot->dest->health < 0) + if (dest && !(dest->flags&MF_SPECIAL) && dest->health < 0) { //Roaming after something dead. - b->Bot->dest = NULL; + dest = NULL; } - if (b->Bot->dest == NULL) + if (dest == NULL) { - if (b->Bot->t_fight && b->Bot->enemy) //Enemy/bot has jumped around corner. So what to do? + if (t_fight && enemy) //Enemy/bot has jumped around corner. So what to do? { - if (b->Bot->enemy->player) + if (enemy->player) { - if (((b->Bot->enemy->player->ReadyWeapon != NULL && b->Bot->enemy->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) || - (pr_botmove()%100)>b->Bot->skill.isp) && b->ReadyWeapon != NULL && !(b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) - b->Bot->dest = b->Bot->enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy. - else //hide while b->t_fight, but keep view at enemy. - b->Bot->angle = R_PointToAngle2(actor->x, actor->y, b->Bot->enemy->x, b->Bot->enemy->y); + if (((enemy->player->ReadyWeapon != NULL && enemy->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) || + (pr_botmove()%100)>skill.isp) && player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) + dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy. + else //hide while t_fight, but keep view at enemy. + angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); } //Just a monster, so kill it. else - b->Bot->dest = b->Bot->enemy; + dest = enemy; - //VerifFavoritWeapon(actor->player); //Dont know why here.., but it must be here, i know the reason, but not why at this spot, uh. + //VerifFavoritWeapon(player); //Dont know why here.., but it must be here, i know the reason, but not why at this spot, uh. } else //Choose a distant target. to get things going. { r = pr_botmove(); if (r < 128) { - TThinkerIterator it (STAT_INVENTORY, firstthing); + TThinkerIterator it (STAT_INVENTORY, bglobal.firstthing); AInventory *item = it.Next(); if (item != NULL || (item = it.Next()) != NULL) @@ -271,60 +268,53 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd) { item = it.Next(); } - firstthing = item; - b->Bot->dest = item; + bglobal.firstthing = item; + dest = item; } } - else if (b->Bot->mate && (r < 179 || P_CheckSight(actor, b->Bot->mate))) + else if (mate && (r < 179 || P_CheckSight(player->mo, mate))) { - b->Bot->dest = b->Bot->mate; + dest = mate; } else if ((playeringame[(r&(MAXPLAYERS-1))]) && players[(r&(MAXPLAYERS-1))].mo->health > 0) { - b->Bot->dest = players[(r&(MAXPLAYERS-1))].mo; + dest = players[(r&(MAXPLAYERS-1))].mo; } } - if (b->Bot->dest) + if (dest) { - b->Bot->t_roam = MAXROAM; + t_roam = MAXROAM; } } - if (b->Bot->dest) + if (dest) { //Bot has a target so roam after it. - Roam (actor, cmd); + Roam (cmd); } } //End of movement main part. - if (!b->Bot->t_roam && b->Bot->dest) + if (!t_roam && dest) { - b->Bot->prev = b->Bot->dest; - b->Bot->dest = NULL; + prev = dest; + dest = NULL; } - if (b->Bot->t_fight<(AFTERTICS/2)) - actor->flags |= MF_DROPOFF; + if (t_fight<(AFTERTICS/2)) + player->mo->flags |= MF_DROPOFF; - b->Bot->oldx = actor->x; - b->Bot->oldy = actor->y; + oldx = player->mo->x; + oldy = player->mo->y; } //BOT_WhatToGet // //Determines if the bot will roam after an item or not. -void FCajunMaster::WhatToGet (AActor *actor, AActor *item) +void DBot::WhatToGet (AActor *item) { - player_t *b = actor->player; - - if (b == NULL) - { - return; - } - #define typeis(x) item->IsKindOf (PClass::FindClass (#x)) if ((item->renderflags & RF_INVISIBLE) //Under respawn and away. - || item == b->Bot->prev) + || item == prev) { return; } @@ -338,7 +328,7 @@ void FCajunMaster::WhatToGet (AActor *actor, AActor *item) // FIXME AWeapon *heldWeapon; - heldWeapon = static_cast (b->mo->FindInventory (item->GetClass())); + heldWeapon = static_cast (player->mo->FindInventory (item->GetClass())); if (heldWeapon != NULL) { if (!weapgiveammo) @@ -354,39 +344,38 @@ void FCajunMaster::WhatToGet (AActor *actor, AActor *item) { AAmmo *ammo = static_cast (item); const PClass *parent = ammo->GetParentAmmo (); - AInventory *holdingammo = b->mo->FindInventory (parent); + AInventory *holdingammo = player->mo->FindInventory (parent); if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount) { return; } } - else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && actor->health >= deh.MaxSoulsphere) + else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere) return; - else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && actor->health >= deh.MaxHealth /*MAXHEALTH*/) + else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= deh.MaxHealth /*MAXHEALTH*/) return; - if ((b->Bot->dest == NULL || - !(b->Bot->dest->flags & MF_SPECIAL)/* || - !Reachable (actor, b->dest)*/)/* && - Reachable (actor, item)*/) // Calling Reachable slows this down tremendously + if ((dest == NULL || + !(dest->flags & MF_SPECIAL)/* || + !Reachable (dest)*/)/* && + Reachable (item)*/) // Calling Reachable slows this down tremendously { - b->Bot->prev = b->Bot->dest; - b->Bot->dest = item; - b->Bot->t_roam = MAXROAM; + prev = dest; + dest = item; + t_roam = MAXROAM; } } -void FCajunMaster::Set_enemy (AActor *actor) +void DBot::Set_enemy () { AActor *oldenemy; - AActor **enemy = &actor->player->Bot->enemy; - if (*enemy - && (*enemy)->health > 0 - && P_CheckSight (actor, *enemy)) + if (enemy + && enemy->health > 0 + && P_CheckSight (player->mo, enemy)) { - oldenemy = *enemy; + oldenemy = enemy; } else { @@ -395,15 +384,14 @@ void FCajunMaster::Set_enemy (AActor *actor) // [RH] Don't even bother looking for a different enemy if this is not deathmatch // and we already have an existing enemy. - if (deathmatch || !*enemy) + if (deathmatch || !enemy) { - actor->player->Bot->allround = !!*enemy; - *enemy = NULL; - *enemy = Find_enemy(actor); - if (!*enemy) - *enemy = oldenemy; //Try go for last (it will be NULL if there wasn't anyone) + allround = !!enemy; + enemy = Find_enemy(); + if (!enemy) + enemy = oldenemy; //Try go for last (it will be NULL if there wasn't anyone) } //Verify that that enemy is really something alive that bot can kill. - if (*enemy && (((*enemy)->health < 0 || !((*enemy)->flags&MF_SHOOTABLE)) || actor->IsFriend(*enemy))) - *enemy = NULL; + if (enemy && ((enemy->health < 0 || !(enemy->flags&MF_SHOOTABLE)) || player->mo->IsFriend(enemy))) + enemy = NULL; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index cf6bccc8a..557f5fa94 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3259,7 +3259,7 @@ void AActor::Tick () else if (flags & MF_SPECIAL) { //Item pickup time //clock (BotWTG); - bglobal.WhatToGet (players[i].mo, this); + players[i].Bot->WhatToGet (this); //unclock (BotWTG); BotWTG++; } @@ -3267,7 +3267,7 @@ void AActor::Tick () { if (!players[i].Bot->missile && (flags3 & MF3_WARNBOT)) { //warn for incoming missiles. - if (target != players[i].mo && bglobal.Check_LOS (players[i].mo, this, ANGLE_90)) + if (target != players[i].mo && players[i].Bot->Check_LOS (this, ANGLE_90)) players[i].Bot->missile = this; } } From 8b88f14c96dc7a70c601fbd08c9b9cf8de546496 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Mon, 1 Dec 2014 21:04:50 -0600 Subject: [PATCH 11/32] Destroy mod-created CVars when 'restart' is invoked --- src/c_cvars.cpp | 16 ++++++++++++++++ src/c_cvars.h | 4 ++++ src/d_main.cpp | 1 + 3 files changed, 21 insertions(+) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index ce4e88632..c770bcbcf 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1515,6 +1515,22 @@ void UnlatchCVars (void) } } +void DestroyCVarsFlagged (DWORD flags) +{ + FBaseCVar *cvar = CVars; + FBaseCVar *next = cvar; + + while(cvar) + { + next = cvar->m_Next; + + if(cvar->Flags & flags) + delete cvar; + + cvar = next; + } +} + void C_SetCVarsToDefaults (void) { FBaseCVar *cvar = CVars; diff --git a/src/c_cvars.h b/src/c_cvars.h index 17d3f7b1d..ed2b16755 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -159,6 +159,7 @@ private: friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); friend FBaseCVar *FindCVarSub (const char *var_name, int namelen); friend void UnlatchCVars (void); + friend void DestroyCVarsFlagged (DWORD flags); friend void C_ArchiveCVars (FConfigFile *f, uint32 filter); friend void C_SetCVarsToDefaults (void); friend void FilterCompactCVars (TArray &cvars, uint32 filter); @@ -190,6 +191,9 @@ FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags); // Called from G_InitNew() void UnlatchCVars (void); +// Destroy CVars with the matching flags; called from CCMD(restart) +void DestroyCVarsFlagged (DWORD flags); + // archive cvars to FILE f void C_ArchiveCVars (FConfigFile *f, uint32 filter); diff --git a/src/d_main.cpp b/src/d_main.cpp index 4fea35301..2ceec3926 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2578,6 +2578,7 @@ void D_DoomMain (void) new (&gameinfo) gameinfo_t; // Reset gameinfo S_Shutdown(); // free all channels and delete playlist C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here + DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods GC::FullGC(); // perform one final garbage collection before deleting the class data PClass::ClearRuntimeData(); // clear all runtime generated class data From 3af08f19839db4d285d18d746f4f17ceb6515b2d Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Mon, 1 Dec 2014 22:03:22 -0600 Subject: [PATCH 12/32] Fixed weapon drawing rules to account for the death camera [backported from gzdoom], also fixed drawing rules for crosshair --- src/g_shared/shared_sbar.cpp | 2 +- src/r_things.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 2a18801a1..d8e113824 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1123,7 +1123,7 @@ void DBaseStatusBar::DrawCrosshair () ST_LoadCrosshair(); // Don't draw the crosshair if there is none - if (CrosshairImage == NULL || gamestate == GS_TITLELEVEL) + if (CrosshairImage == NULL || gamestate == GS_TITLELEVEL || camera->health <= 0) { return; } diff --git a/src/r_things.cpp b/src/r_things.cpp index c0475ee75..e27a5c87e 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -95,6 +95,7 @@ extern fixed_t globaluclip, globaldclip; EXTERN_CVAR (Bool, st_scale) EXTERN_CVAR(Bool, r_shadercolormaps) EXTERN_CVAR(Int, r_drawfuzz) +EXTERN_CVAR(Bool, r_deathcamera); // // Sprite rotation 0 is facing the viewer, @@ -1410,7 +1411,8 @@ void R_DrawPlayerSprites () if (!r_drawplayersprites || !camera->player || - (players[consoleplayer].cheats & CF_CHASECAM)) + (players[consoleplayer].cheats & CF_CHASECAM) || + (r_deathcamera && camera->health <= 0)) return; if(fixedlightlev < 0 && viewsector->e && viewsector->e->XFloor.lightlist.Size()) { From c631ffc5fd1abd604432ce050ec3f31d192febd1 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Wed, 3 Dec 2014 00:50:05 -0600 Subject: [PATCH 13/32] Fixed SV_SAMESPAWNSPOT behavior -- When enabled, use the p->mo->z. Otherwise, rely on ONCEILINGZ/FLOATRANDZ/ONFLOORZ w/ or w/o UsePlayerStartZ as previously done --- src/p_mobj.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 557f5fa94..749747586 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4302,12 +4302,15 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) { spawn_x = p->mo->x; spawn_y = p->mo->y; + spawn_z = p->mo->z; + spawn_angle = p->mo->angle; } else { spawn_x = mthing->x; spawn_y = mthing->y; + // Allow full angular precision but avoid roundoff errors for multiples of 45 degrees. if (mthing->angle % 45 != 0) { @@ -4321,14 +4324,14 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) { spawn_angle += 1 << ANGLETOFINESHIFT; } - } - if (GetDefaultByType(p->cls)->flags & MF_SPAWNCEILING) - spawn_z = ONCEILINGZ; - else if (GetDefaultByType(p->cls)->flags2 & MF2_SPAWNFLOAT) - spawn_z = FLOATRANDZ; - else - spawn_z = ONFLOORZ; + if (GetDefaultByType(p->cls)->flags & MF_SPAWNCEILING) + spawn_z = ONCEILINGZ; + else if (GetDefaultByType(p->cls)->flags2 & MF2_SPAWNFLOAT) + spawn_z = FLOATRANDZ; + else + spawn_z = ONFLOORZ; + } mobj = static_cast (Spawn (p->cls, spawn_x, spawn_y, spawn_z, NO_REPLACE)); From fbe14d59bba9f82a3f8968861a813553ecce3752 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 3 Dec 2014 13:05:50 +0100 Subject: [PATCH 14/32] - fixed: All powerup blend colors with an alpha of 0 were treated as 'has no color' for PowerupGivers. --- src/g_shared/a_artifacts.cpp | 3 ++- src/thingdef/thingdef_properties.cpp | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 4a2d066cd..410474f31 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -60,7 +60,8 @@ bool APowerupGiver::Use (bool pickup) } if (BlendColor != 0) { - power->BlendColor = BlendColor; + if (BlendColor.a != 0) power->BlendColor = BlendColor; + else power->BlendColor = 0; } if (Mode != NAME_None) { diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index b5fdc8e42..ec68dfb95 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -2020,15 +2020,18 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) "INVERSEMAP", "GOLDMAP", "REDMAP", "GREENMAP", "BLUEMAP", NULL }; int alpha; + bool giver; PalEntry * pBlendColor; if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pBlendColor = &((APowerup*)defaults)->BlendColor; + giver = false; } else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pBlendColor = &((APowerupGiver*)defaults)->BlendColor; + giver = true; } else { @@ -2061,7 +2064,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) else alpha = 255/3; alpha=clamp(alpha, 0, 255); - if (alpha != 0) *pBlendColor = MAKEARGB(alpha, 0, 0, 0) | color; + if (alpha != 0 || giver) *pBlendColor = MAKEARGB(alpha, 0, 0, 0) | color; else *pBlendColor = 0; } From fcc491f7351cb1732c5defd6641657b7d755bb91 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Wed, 3 Dec 2014 17:04:47 -0500 Subject: [PATCH 15/32] Make the respawn invulnerability APowerInvulnerable persist through a ClearInventory by making it undroppable --- src/p_mobj.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 557f5fa94..c3593fc6e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4445,7 +4445,8 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) { APowerup *invul = static_cast(p->mo->GiveInventoryType (RUNTIME_CLASS(APowerInvulnerable))); invul->EffectTics = 3*TICRATE; - invul->BlendColor = 0; // don't mess with the view + invul->BlendColor = 0; // don't mess with the view + invul->ItemFlags |= IF_UNDROPPABLE; // Don't drop this p->mo->effects |= FX_RESPAWNINVUL; // [RH] special effect } From e6de24a7dee333fb73b3a35682563f3008261053 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Dec 2014 22:08:39 +0100 Subject: [PATCH 16/32] - turned out that the recent change to allow cancelling a powerup blend through a powerup giver did not work well so now there's an explicit 'Powerup.Color none' to do it that works a bit differently. --- src/g_shared/a_artifacts.cpp | 2 +- src/thingdef/thingdef_properties.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 410474f31..21006776e 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -60,7 +60,7 @@ bool APowerupGiver::Use (bool pickup) } if (BlendColor != 0) { - if (BlendColor.a != 0) power->BlendColor = BlendColor; + if (BlendColor != MakeSpecialColormap(65535)) power->BlendColor = BlendColor; else power->BlendColor = 0; } if (Mode != NAME_None) diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index ec68dfb95..5b17185c4 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -2020,18 +2020,15 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) "INVERSEMAP", "GOLDMAP", "REDMAP", "GREENMAP", "BLUEMAP", NULL }; int alpha; - bool giver; PalEntry * pBlendColor; if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pBlendColor = &((APowerup*)defaults)->BlendColor; - giver = false; } else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pBlendColor = &((APowerupGiver*)defaults)->BlendColor; - giver = true; } else { @@ -2053,6 +2050,10 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) *pBlendColor = MakeSpecialColormap(v); return; } + else if (!stricmp(name, "none") && info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + { + *pBlendColor = MakeSpecialColormap(65535); + } color = V_GetColor(NULL, name); } @@ -2064,7 +2065,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) else alpha = 255/3; alpha=clamp(alpha, 0, 255); - if (alpha != 0 || giver) *pBlendColor = MAKEARGB(alpha, 0, 0, 0) | color; + if (alpha != 0) *pBlendColor = MAKEARGB(alpha, 0, 0, 0) | color; else *pBlendColor = 0; } From 8a98be00dc1165564910a4f416a6e956d4311665 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 7 Dec 2014 09:30:16 +0100 Subject: [PATCH 17/32] - fixed: ZDoom did not understand Boom's name for the Red Skull Key pickup message due to a typo. Of course, just changing the name would break many old ZDoom mods so now Boom's name is explicitly being translated into ZDoom's before setting the string. --- src/d_dehacked.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index d14015ca9..66fe2c58d 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2247,6 +2247,8 @@ static int PatchStrings (int dummy) ReplaceSpecialChars (holdstring.LockBuffer()); holdstring.UnlockBuffer(); + // Account for a discrepancy between Boom's and ZDoom's name for the red skull key pickup message + if (!stricmp(Line1, "GOTREDSKULL")) Line1 = "GOTREDSKUL"; GStrings.SetString (Line1, holdstring); DPrintf ("%s set to:\n%s\n", Line1, holdstring.GetChars()); } From 95bed868d3e320342ce3d3152f35acd1abe2167f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 7 Dec 2014 14:46:53 +0100 Subject: [PATCH 18/32] - gcc warnings suck... --- src/d_dehacked.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 66fe2c58d..41ad71472 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2248,8 +2248,9 @@ static int PatchStrings (int dummy) ReplaceSpecialChars (holdstring.LockBuffer()); holdstring.UnlockBuffer(); // Account for a discrepancy between Boom's and ZDoom's name for the red skull key pickup message - if (!stricmp(Line1, "GOTREDSKULL")) Line1 = "GOTREDSKUL"; - GStrings.SetString (Line1, holdstring); + const char *ll = Line1; + if (!stricmp(ll, "GOTREDSKULL")) ll = "GOTREDSKUL"; + GStrings.SetString (ll, holdstring); DPrintf ("%s set to:\n%s\n", Line1, holdstring.GetChars()); } From b2452b806ecb60e620cb2600cb2b9840f4a1a77d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Dec 2014 12:01:20 +0100 Subject: [PATCH 19/32] - missed a return. --- src/thingdef/thingdef_properties.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 5b17185c4..b548d4ef6 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -2053,6 +2053,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) else if (!stricmp(name, "none") && info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { *pBlendColor = MakeSpecialColormap(65535); + return; } color = V_GetColor(NULL, name); From e5340ad6375a2311c11335d2be9df9367ffa0a34 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 9 Dec 2014 12:09:36 -0600 Subject: [PATCH 20/32] - Splitting the pull request in half. - Added THRUREFLECT, MIRRORREFLECT, and AIMREFLECT. All require REFLECTIVE to work. - THRUREFLECT prevents missiles from changing course if reflected, and takes precedence over all reflective flags. - MIRRORREFLECT causes missiles to perform a direct 180 turn-around. - AIMREFLECT turns the missile back to the original shooter, and does not slow the missile down. --- src/actor.h | 7 +++- src/p_map.cpp | 29 +++++++++++++---- src/p_mobj.cpp | 59 +++++++++++++++++++++++++++------- src/thingdef/thingdef_data.cpp | 3 ++ 4 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/actor.h b/src/actor.h index f46ee7148..88cfa983e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -347,6 +347,11 @@ enum MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag. MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't. MF7_CAUSEPAIN = 0x00000400, // Damage sources with this flag can cause similar effects like ALLOWPAIN. + MF7_THRUREFLECT = 0x00000800, // Actors who are reflective cause the missiles to not slow down or change angles. + MF7_MIRRORREFLECT = 0x00001000, // Actor is turned directly 180 degrees around when reflected. + MF7_AIMREFLECT = 0x00002000, // Actor is directly reflected straight back at the one who fired the projectile. + + // --- mobj.renderflags --- @@ -859,7 +864,7 @@ public: DWORD flags4; // [RH] Even more flags! DWORD flags5; // OMG! We need another one. DWORD flags6; // Shit! Where did all the flags go? - DWORD flags7; // + DWORD flags7; // WHO WANTS TO BET ON 8!? // [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it. DWORD VisibleToTeam; diff --git a/src/p_map.cpp b/src/p_map.cpp index 3097ae824..857597089 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1283,6 +1283,16 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) { P_GiveBody(thing, -damage); } + + if ((thing->flags7 & MF7_THRUREFLECT) && (thing->flags2 & MF2_REFLECTIVE) && (tm.thing->flags & MF_MISSILE)) + { + if (tm.thing->flags2 & MF2_SEEKERMISSILE) + { + tm.thing->tracer = tm.thing->target; + } + tm.thing->target = thing; + return true; + } return false; // don't traverse any more } if (thing->flags2 & MF2_PUSHABLE && !(tm.thing->flags2 & MF2_CANNOTPUSH)) @@ -1643,7 +1653,7 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) { // Don't clip against self continue; } - if ((actor->flags & MF_MISSILE) && thing == actor->target) + if ((actor->flags & MF_MISSILE) && (thing == actor->target)) { // Don't clip against whoever shot the missile. continue; } @@ -2983,18 +2993,20 @@ bool P_BounceWall(AActor *mo) extern FRandom pr_bounce; bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) { + //Don't go through all of this if the actor is reflective and wants things to pass through them. + if (BlockingMobj && ((BlockingMobj->flags2 & MF2_REFLECTIVE) && (BlockingMobj->flags7 & MF7_THRUREFLECT))) return true; if (mo && BlockingMobj && ((mo->BounceFlags & BOUNCE_AllActors) - || ((mo->flags & MF_MISSILE) && (!(mo->flags2 & MF2_RIP) || (BlockingMobj->flags5 & MF5_DONTRIP) || ((mo->flags6 & MF6_NOBOSSRIP) && (BlockingMobj->flags2 & MF2_BOSS))) && (BlockingMobj->flags2 & MF2_REFLECTIVE)) - || ((BlockingMobj->player == NULL) && (!(BlockingMobj->flags3 & MF3_ISMONSTER))) - )) + || ((mo->flags & MF_MISSILE) && (!(mo->flags2 & MF2_RIP) + || (BlockingMobj->flags5 & MF5_DONTRIP) + || ((mo->flags6 & MF6_NOBOSSRIP) && (BlockingMobj->flags2 & MF2_BOSS))) && (BlockingMobj->flags2 & MF2_REFLECTIVE)) + || ((BlockingMobj->player == NULL) && (!(BlockingMobj->flags3 & MF3_ISMONSTER))))) { if (mo->bouncecount > 0 && --mo->bouncecount == 0) return false; if (!ontop) { fixed_t speed; - angle_t angle = R_PointToAngle2(BlockingMobj->x, - BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8); + angle_t angle = R_PointToAngle2(BlockingMobj->x,BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8); speed = P_AproxDistance(mo->velx, mo->vely); speed = FixedMul(speed, mo->wallbouncefactor); // [GZ] was 0.75, using wallbouncefactor seems more consistent mo->angle = angle; @@ -5090,6 +5102,8 @@ int P_PushUp(AActor *thing, FChangePosition *cpos) // is normally for projectiles which would have exploded by now anyway... if (thing->flags6 & MF6_THRUSPECIES && thing->GetSpecies() == intersect->GetSpecies()) continue; + if ((thing->flags & MF_MISSILE) && (intersect->flags2 & MF2_REFLECTIVE) && (intersect->flags7 & MF7_THRUREFLECT)) + continue; if (!(intersect->flags2 & MF2_PASSMOBJ) || (!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) || (intersect->flags4 & MF4_ACTLIKEBRIDGE) @@ -5098,7 +5112,8 @@ int P_PushUp(AActor *thing, FChangePosition *cpos) // Can't push bridges or things more massive than ourself return 2; } - fixed_t oldz = intersect->z; + fixed_t oldz; + oldz = intersect->z; P_AdjustFloorCeil(intersect, cpos); intersect->z = thing->z + thing->height + 1; if (P_PushUp(intersect, cpos)) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f1cfb6e28..2da365d60 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1660,6 +1660,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) int steps, step, totalsteps; fixed_t startx, starty; fixed_t oldfloorz = mo->floorz; + fixed_t oldz = mo->z; fixed_t maxmove = (mo->waterlevel < 1) || (mo->flags & MF_MISSILE) || (mo->player && mo->player->crouchoffset<-10*FRACUNIT) ? MAXMOVE : MAXMOVE/4; @@ -1949,20 +1950,53 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) } if (BlockingMobj && (BlockingMobj->flags2 & MF2_REFLECTIVE)) { - angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y); - - // Change angle for deflection/reflection - if (mo->AdjustReflectionAngle (BlockingMobj, angle)) + bool seeker = (mo->flags2 & MF2_SEEKERMISSILE) ? true : false; + // Don't change the angle if there's THRUREFLECT on the monster. + if (!(BlockingMobj->flags7 & MF7_THRUREFLECT)) { - goto explode; - } + int dir; + angle_t delta; + + if (BlockingMobj->flags7 & MF7_MIRRORREFLECT) + angle = mo->angle + ANG180; + else + angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y); - // Reflect the missile along angle - mo->angle = angle; - angle >>= ANGLETOFINESHIFT; - mo->velx = FixedMul (mo->Speed>>1, finecosine[angle]); - mo->vely = FixedMul (mo->Speed>>1, finesine[angle]); - mo->velz = -mo->velz/2; + // Change angle for deflection/reflection + // AIMREFLECT calls precedence so make sure not to bother with adjusting here if declared. + if (!(BlockingMobj->flags7 & MF7_AIMREFLECT) && (mo->AdjustReflectionAngle(BlockingMobj, angle))) + { + goto explode; + } + + // Reflect the missile along angle + if (BlockingMobj->flags7 & MF7_AIMREFLECT) + { + dir = P_FaceMobj(mo, mo->target, &delta); + if (dir) + { // Turn clockwise + mo->angle += delta; + } + else + { // Turn counter clockwise + mo->angle -= delta; + } + angle = mo->angle >> ANGLETOFINESHIFT; + mo->velx = FixedMul(mo->Speed, finecosine[angle]); + mo->vely = FixedMul(mo->Speed, finesine[angle]); + mo->velz = -mo->velz; + } + else + { + mo->angle = angle; + angle >>= ANGLETOFINESHIFT; + mo->velx = FixedMul(mo->Speed >> 1, finecosine[angle]); + mo->vely = FixedMul(mo->Speed >> 1, finesine[angle]); + mo->velz = -mo->velz / 2; + } + + + } if (mo->flags2 & MF2_SEEKERMISSILE) { mo->tracer = mo->target; @@ -2893,6 +2927,7 @@ int AActor::SpecialMissileHit (AActor *victim) bool AActor::AdjustReflectionAngle (AActor *thing, angle_t &angle) { if (flags2 & MF2_DONTREFLECT) return true; + if (thing->flags7 & MF7_THRUREFLECT) return false; // Change angle for reflection if (thing->flags4&MF4_SHIELDREFLECT) diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index e8cb91239..0bc7624a7 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -247,6 +247,9 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF7, DONTTHRUST, AActor, flags7), DEFINE_FLAG(MF7, ALLOWPAIN, AActor, flags7), DEFINE_FLAG(MF7, CAUSEPAIN, AActor, flags7), + DEFINE_FLAG(MF7, THRUREFLECT, AActor, flags7), + DEFINE_FLAG(MF7, MIRRORREFLECT, AActor, flags7), + DEFINE_FLAG(MF7, AIMREFLECT, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), From 533ae959336a4cd7a2e5c2580c70c3bf81294e70 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 9 Dec 2014 12:30:14 -0600 Subject: [PATCH 21/32] - Added three missile impact pointer changing flags. - HITTARGET, HITMASTER, and HITTRACER. - A missile that dies hitting an actor will set this impacted actor as the new target/master/tracer, depending on specifications. --- src/actor.h | 3 +++ src/p_mobj.cpp | 3 +++ src/thingdef/thingdef_data.cpp | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index f46ee7148..ecf8ad6a1 100644 --- a/src/actor.h +++ b/src/actor.h @@ -347,6 +347,9 @@ enum MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag. MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't. MF7_CAUSEPAIN = 0x00000400, // Damage sources with this flag can cause similar effects like ALLOWPAIN. + MF7_HITTARGET = 0x00004000, // The actor the projectile dies on is set to target, provided it's targetable anyway. + MF7_HITMASTER = 0x00008000, // Same as HITTARGET, except it's master instead of target. + MF7_HITTRACER = 0x00010000, // Same as HITTARGET, but for tracer. // --- mobj.renderflags --- diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f1cfb6e28..4d731f1fc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1202,6 +1202,9 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) if (target != NULL && ((target->flags & (MF_SHOOTABLE|MF_CORPSE)) || (target->flags6 & MF6_KILLED)) ) { + if (target->flags7 & MF7_HITTARGET) mo->target = target; + if (target->flags7 & MF7_HITMASTER) mo->master = target; + if (target->flags7 & MF7_HITTRACER) mo->tracer = target; if (target->flags & MF_NOBLOOD) nextstate = mo->FindState(NAME_Crash); if (nextstate == NULL) nextstate = mo->FindState(NAME_Death, NAME_Extreme); } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index e8cb91239..17c186884 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -247,7 +247,10 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF7, DONTTHRUST, AActor, flags7), DEFINE_FLAG(MF7, ALLOWPAIN, AActor, flags7), DEFINE_FLAG(MF7, CAUSEPAIN, AActor, flags7), - + DEFINE_FLAG(MF7, HITTARGET, AActor, flags7), + DEFINE_FLAG(MF7, HITMASTER, AActor, flags7), + DEFINE_FLAG(MF7, HITTRACER, AActor, flags7), + // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), DEFINE_FLAG2(FX_ROCKET, ROCKETTRAIL, AActor, effects), From c339bb33cf701a983784391ee6bd2a6051a4f68e Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Wed, 10 Dec 2014 20:55:00 +1300 Subject: [PATCH 22/32] Added cl_waitforsave - cl_waitforsave (default true) pauses the game timer when a save starts, preventing the network buffer from trying to compensate for slow saves. --- src/g_game.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/g_game.cpp b/src/g_game.cpp index beec9435a..ba53254c2 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -116,6 +116,7 @@ CVAR (Bool, chasedemo, false, 0); CVAR (Bool, storesavepic, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, longsavemessages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, save_dir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG); +CVAR (Bool, cl_waitforsave, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); EXTERN_CVAR (Float, con_midtime); //========================================================================== @@ -2147,6 +2148,9 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio filename = G_BuildSaveName ("demosave.zds", -1); } + if (cl_waitforsave) + I_FreezeTime(true); + insave = true; G_SnapshotLevel (); @@ -2156,6 +2160,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio { Printf ("Could not create savegame '%s'\n", filename.GetChars()); insave = false; + I_FreezeTime(false); return; } @@ -2232,6 +2237,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio } insave = false; + I_FreezeTime(false); } From 372f7e7002410e33b477aa275b74a74c920f861b Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 10 Dec 2014 21:11:26 +0100 Subject: [PATCH 23/32] - Various CMake fixes for two problems. 1) Don't show OSX_COCOA_BACKEND option if the host is not OSX; 2) Don't use the '-msse' compiler flag in dumb/ if the architecture does not support it. --- dumb/CMakeLists.txt | 7 ++++++- src/CMakeLists.txt | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/dumb/CMakeLists.txt b/dumb/CMakeLists.txt index 2b70ee412..9c1a69a79 100644 --- a/dumb/CMakeLists.txt +++ b/dumb/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required( VERSION 2.4 ) make_release_only() include( CheckFunctionExists ) +include( CheckCXXCompilerFlag ) # DUMB is much slower in a Debug build than a Release build, so we force a Release # build here, since we're not maintaining DUMB, only using it. @@ -104,5 +105,9 @@ add_library( dumb target_link_libraries( dumb ) if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - set_source_files_properties( src/it/filter.cpp PROPERTIES COMPILE_FLAGS -msse ) + CHECK_CXX_COMPILER_FLAG( -msse DUMB_CAN_USE_SSE ) + + if( DUMB_CAN_USE_SSE ) + set_source_files_properties( src/it/filter.cpp PROPERTIES COMPILE_FLAGS -msse ) + endif( DUMB_CAN_USE_SSE ) endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07c13c20c..2cc3bc63e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,7 +27,9 @@ endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON ) -option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON ) +if( APPLE ) + option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON ) +endif( APPLE ) if( CMAKE_SIZEOF_VOID_P MATCHES "8" ) set( X64 64 ) From 86372fce34d84e75ba424e20af677cfcfb5cd488 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 12 Dec 2014 16:19:37 -0500 Subject: [PATCH 24/32] - Added Steam detection for Stife: Veteran Edition. - Added Steam install scanning for Linux and OS X. (OS X and Win32 not yet tested.) --- src/CMakeLists.txt | 1 + src/cocoa/i_backend_cocoa.mm | 8 ++ src/d_iwad.cpp | 22 +--- src/sdl/i_steam.cpp | 217 +++++++++++++++++++++++++++++++++++ src/sdl/i_system.h | 4 + src/win32/i_system.cpp | 30 +++-- src/win32/i_system.h | 2 +- 7 files changed, 257 insertions(+), 27 deletions(-) create mode 100644 src/sdl/i_steam.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2cc3bc63e..8b924bd50 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -569,6 +569,7 @@ set( PLAT_SDL_SYSTEM_SOURCES sdl/i_cd.cpp sdl/i_main.cpp sdl/i_movie.cpp + sdl/i_steam.cpp sdl/i_system.cpp sdl/sdlvideo.cpp sdl/st_start.cpp ) diff --git a/src/cocoa/i_backend_cocoa.mm b/src/cocoa/i_backend_cocoa.mm index bd3dc3115..9085d92db 100644 --- a/src/cocoa/i_backend_cocoa.mm +++ b/src/cocoa/i_backend_cocoa.mm @@ -1619,6 +1619,14 @@ const char* I_GetBackEndName() } +FString OSX_FindApplicationSupport() +{ + NSURL *url = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil]; + if(url == nil) + return FString(); + return [[url path] UTF8String]; +} + // --------------------------------------------------------------------------- diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 6b430fa03..c03ed7a2f 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -430,27 +430,11 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, } } } -#ifdef _WIN32 - FString steam_path = I_GetSteamPath(); - if (steam_path.IsNotEmpty()) + TArray steam_path = I_GetSteamPath(); + for (i = 0; i < steam_path.Size(); ++i) { - static const char *const steam_dirs[] = - { - "doom 2/base", - "final doom/base", - "heretic shadow of the serpent riders/base", - "hexen/base", - "hexen deathkings of the dark citadel/base", - "ultimate doom/base", - "DOOM 3 BFG Edition/base/wads" - }; - steam_path += "/SteamApps/common/"; - for (i = 0; i < countof(steam_dirs); ++i) - { - CheckIWAD (steam_path + steam_dirs[i], &wads[0]); - } + CheckIWAD (steam_path[i], &wads[0]); } -#endif } if (iwadparm != NULL && !wads[0].Path.IsEmpty()) diff --git a/src/sdl/i_steam.cpp b/src/sdl/i_steam.cpp new file mode 100644 index 000000000..1da7fc5fa --- /dev/null +++ b/src/sdl/i_steam.cpp @@ -0,0 +1,217 @@ +/* +** i_steam.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2013 Braden Obrzut +** 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 "doomerrors.h" +#include "d_main.h" +#include "zstring.h" +#include "sc_man.h" + +static void PSR_FindEndBlock(FScanner &sc) +{ + int depth = 1; + do + { + if(sc.CheckToken('}')) + --depth; + else if(sc.CheckToken('{')) + ++depth; + else + sc.MustGetAnyToken(); + } + while(depth); +} +static void PSR_SkipBlock(FScanner &sc) +{ + sc.MustGetToken('{'); + PSR_FindEndBlock(sc); +} +static bool PSR_FindAndEnterBlock(FScanner &sc, const char* keyword) +{ + // Finds a block with a given keyword and then enter it (opening brace) + // Should be closed with PSR_FindEndBlock + while(sc.GetToken()) + { + if(sc.TokenType == '}') + { + sc.UnGet(); + return false; + } + + sc.TokenMustBe(TK_StringConst); + if(!sc.Compare(keyword)) + { + if(!sc.CheckToken(TK_StringConst)) + PSR_SkipBlock(sc); + } + else + { + sc.MustGetToken('{'); + return true; + } + } + return false; +} +static TArray PSR_ReadBaseInstalls(FScanner &sc) +{ + TArray result; + + // Get a list of possible install directories. + while(sc.GetToken()) + { + if(sc.TokenType == '}') + break; + + sc.TokenMustBe(TK_StringConst); + FString key(sc.String); + if(key.Left(18).CompareNoCase("BaseInstallFolder_") == 0) + { + sc.MustGetToken(TK_StringConst); + result.Push(sc.String); + } + else + { + if(sc.CheckToken('{')) + PSR_FindEndBlock(sc); + else + sc.MustGetToken(TK_StringConst); + } + } + + return result; +} +static TArray ParseSteamRegistry(const char* path) +{ + TArray dirs; + + // Read registry data + FScanner sc; + sc.OpenFile(path); + sc.SetCMode(true); + + // Find the SteamApps listing + if(PSR_FindAndEnterBlock(sc, "InstallConfigStore")) + { + if(PSR_FindAndEnterBlock(sc, "Software")) + { + if(PSR_FindAndEnterBlock(sc, "Valve")) + { + if(PSR_FindAndEnterBlock(sc, "Steam")) + { + dirs = PSR_ReadBaseInstalls(sc); + } + PSR_FindEndBlock(sc); + } + PSR_FindEndBlock(sc); + } + PSR_FindEndBlock(sc); + } + + return dirs; +} + +static struct SteamAppInfo +{ + const char* const BasePath; + const int AppID; +} AppInfo[] = +{ + /*{"doom 2/base", 2300}, + {"final doom/base", 2290}, + {"heretic shadow of the serpent riders/base", 2390}, + {"hexen/base", 2360}, + {"hexen deathkings of the dark citadel/base", 2370}, + {"ultimate doom/base", 2280}, + {"DOOM 3 BFG Edition/base/wads", 208200},*/ + {"Strife", 317040} +}; + +TArray I_GetSteamPath() +{ + TArray result; + TArray SteamInstallFolders; + + // Linux and OS X actually allow the user to install to any location, so + // we need to figure out on an app-by-app basis where the game is installed. + // To do so, we read the virtual registry. +#ifdef __APPLE__ + FString OSX_FindApplicationSupport(); + + FString regPath = OSX_FindApplicationSupport() + "/Steam/config/config.vdf"; + try + { + SteamInstallFolders = ParseSteamRegistry(regPath); + } + catch(class CDoomError &error) + { + // If we can't parse for some reason just pretend we can't find anything. + return result; + } + + SteamInstallFolders.Push(OSX_FindApplicationSupport() + "/Steam/SteamApps/common"); +#else + char* home = getenv("HOME"); + if(home != NULL && *home != '\0') + { + FString regPath; + regPath.Format("%s/.local/share/Steam/config/config.vdf", home); + try + { + SteamInstallFolders = ParseSteamRegistry(regPath); + } + catch(class CDoomError &error) + { + // If we can't parse for some reason just pretend we can't find anything. + return result; + } + + regPath.Format("%s/.local/share/Steam/SteamApps/common", home); + SteamInstallFolders.Push(regPath); + } +#endif + + for(unsigned int i = 0;i < SteamInstallFolders.Size();++i) + { + for(unsigned int app = 0;app < countof(AppInfo);++app) + { + struct stat st; + FString candidate(SteamInstallFolders[i] + "/" + AppInfo[app].BasePath); + if(stat(candidate, &st) == 0 && S_ISDIR(st.st_mode)) + result.Push(candidate); + } + } + + return result; +} diff --git a/src/sdl/i_system.h b/src/sdl/i_system.h index a3341f4c5..fa03d3c37 100644 --- a/src/sdl/i_system.h +++ b/src/sdl/i_system.h @@ -120,6 +120,10 @@ void I_SetIWADInfo (); // Pick from multiple IWADs to use int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad); +// [RH] Checks the registry for Steam's install path, so we can scan its +// directories for IWADs if the user purchased any through Steam. +TArray I_GetSteamPath(); + // The ini could not be saved at exit bool I_WriteIniFailed (); diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 4248df274..71cc42af0 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1524,20 +1524,36 @@ static bool QueryPathKey(HKEY key, const char *keypath, const char *valname, FSt // //========================================================================== -FString I_GetSteamPath() +TArray I_GetSteamPath() { + TArray result; + static const char *const steam_dirs[] = + { + "doom 2/base", + "final doom/base", + "heretic shadow of the serpent riders/base", + "hexen/base", + "hexen deathkings of the dark citadel/base", + "ultimate doom/base", + "DOOM 3 BFG Edition/base/wads", + "Strife" + }; + FString path; - if (QueryPathKey(HKEY_CURRENT_USER, "Software\\Valve\\Steam", "SteamPath", path)) + if (!QueryPathKey(HKEY_CURRENT_USER, "Software\\Valve\\Steam", "SteamPath", path)) { - return path; + if (!QueryPathKey(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", "InstallPath", path)) + return result; } - if (QueryPathKey(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", "InstallPath", path)) + path += "/SteamApps/common/"; + + for(unsigned int i = 0; i < countof(steam_dirs); ++i) { - return path; + result.Push(path + steam_dirs[i]); } - path = ""; - return path; + + return result; } //========================================================================== diff --git a/src/win32/i_system.h b/src/win32/i_system.h index 9fbf2db5c..647a08d13 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -142,7 +142,7 @@ void I_SetWndProc(); // [RH] Checks the registry for Steam's install path, so we can scan its // directories for IWADs if the user purchased any through Steam. -FString I_GetSteamPath(); +TArray I_GetSteamPath(); // Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of // giving them proper prototypes under Win32, they are just macros for From 8ee0554d567a693f7bff81e3fe8503b15ace716d Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 12 Dec 2014 16:33:49 -0500 Subject: [PATCH 25/32] - Fixed: Extra Steam paths still need steamapps/common appended to them. --- src/sdl/i_steam.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sdl/i_steam.cpp b/src/sdl/i_steam.cpp index 1da7fc5fa..f8b4c07d9 100644 --- a/src/sdl/i_steam.cpp +++ b/src/sdl/i_steam.cpp @@ -99,7 +99,7 @@ static TArray PSR_ReadBaseInstalls(FScanner &sc) if(key.Left(18).CompareNoCase("BaseInstallFolder_") == 0) { sc.MustGetToken(TK_StringConst); - result.Push(sc.String); + result.Push(FString(sc.String) + "/steamapps/common"); } else { @@ -170,6 +170,7 @@ TArray I_GetSteamPath() FString OSX_FindApplicationSupport(); FString regPath = OSX_FindApplicationSupport() + "/Steam/config/config.vdf"; + Printf("Reading %s\n", regPath.GetChars()); try { SteamInstallFolders = ParseSteamRegistry(regPath); @@ -208,6 +209,7 @@ TArray I_GetSteamPath() { struct stat st; FString candidate(SteamInstallFolders[i] + "/" + AppInfo[app].BasePath); + Printf("Checking %s\n", candidate.GetChars()); if(stat(candidate, &st) == 0 && S_ISDIR(st.st_mode)) result.Push(candidate); } From b14eded8d8f6d4e756299f43768178dbe188b4ec Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 12 Dec 2014 17:06:01 -0500 Subject: [PATCH 26/32] - Accidentally committed debuging code. --- src/sdl/i_steam.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sdl/i_steam.cpp b/src/sdl/i_steam.cpp index f8b4c07d9..23e74af5a 100644 --- a/src/sdl/i_steam.cpp +++ b/src/sdl/i_steam.cpp @@ -170,7 +170,6 @@ TArray I_GetSteamPath() FString OSX_FindApplicationSupport(); FString regPath = OSX_FindApplicationSupport() + "/Steam/config/config.vdf"; - Printf("Reading %s\n", regPath.GetChars()); try { SteamInstallFolders = ParseSteamRegistry(regPath); @@ -209,7 +208,6 @@ TArray I_GetSteamPath() { struct stat st; FString candidate(SteamInstallFolders[i] + "/" + AppInfo[app].BasePath); - Printf("Checking %s\n", candidate.GetChars()); if(stat(candidate, &st) == 0 && S_ISDIR(st.st_mode)) result.Push(candidate); } From 8c5a8c54f01a00d9ef691f60574c15d45400c13a Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sat, 13 Dec 2014 15:08:18 -0600 Subject: [PATCH 27/32] - Added rclamp(,). - Usable for DECORATE expressions. Chooses one of the two numbers placed in the field. --- src/namedef.h | 1 + src/sc_man_scanner.re | 1 + src/sc_man_tokens.h | 1 + src/thingdef/thingdef_exp.cpp | 23 ++++++++ src/thingdef/thingdef_exp.h | 21 +++++++ src/thingdef/thingdef_expression.cpp | 83 ++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+) diff --git a/src/namedef.h b/src/namedef.h index 146997309..7eef612c1 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -300,6 +300,7 @@ xx(CallACS) xx(Sqrt) xx(CheckClass) xx(IsPointerEqual) +xx(RClamp) // Various actor names which are used internally xx(MapSpot) diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index dd90ce1d1..2e25fb2f7 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -158,6 +158,7 @@ std2: 'random' { RET(TK_Random); } 'random2' { RET(TK_Random2); } 'frandom' { RET(TK_FRandom); } + 'rclamp' { RET(TK_RClamp); } L (L|D)* { RET(TK_Identifier); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 9dde74972..62622cf00 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -122,4 +122,5 @@ xx(TK_Array, "'array'") xx(TK_In, "'in'") xx(TK_SizeOf, "'sizeof'") xx(TK_AlignOf, "'alignof'") +xx(TK_RClamp, "'rclamp'") #undef xx diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 773f7ffac..4cef24187 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -371,6 +371,29 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) return new FxRandom(rng, min, max, sc); } + else if (sc.CheckToken(TK_RClamp)) + { + FRandom *rng; + + if (sc.CheckToken('[')) + { + sc.MustGetToken(TK_Identifier); + rng = FRandom::StaticFindRNG(sc.String); + sc.MustGetToken(']'); + } + else + { + rng = &pr_exrandom; + } + sc.MustGetToken('('); + + FxExpression *min = ParseExpressionM(sc, cls); + sc.MustGetToken(','); + FxExpression *max = ParseExpressionM(sc, cls); + sc.MustGetToken(')'); + + return new FxRClamp(rng, min, max, sc); + } else if (sc.CheckToken(TK_FRandom)) { FRandom *rng; diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 77af37f53..42e35489d 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -559,6 +559,27 @@ public: // //========================================================================== +class FxRClamp : public FxExpression +{ +protected: + FRandom * rng; + FxExpression *min, *max; + +public: + + FxRClamp(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); + ~FxRClamp(); + FxExpression *Resolve(FCompileContext&); + + ExpVal EvalExpression(AActor *self); +}; + +//========================================================================== +// +// +// +//========================================================================== + class FxFRandom : public FxRandom { public: diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 7dbf5ec36..5a5510a0b 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1691,6 +1691,89 @@ ExpVal FxRandom::EvalExpression (AActor *self) return val; } +//========================================================================== +// +// +// +//========================================================================== +FxRClamp::FxRClamp(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) +: FxExpression(pos) +{ + if (mi != NULL && ma != NULL) + { + min = new FxIntCast(mi); + max = new FxIntCast(ma); + } + else min = max = NULL; + rng = r; + ValueType = VAL_Int; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRClamp::~FxRClamp() +{ + SAFE_DELETE(min); + SAFE_DELETE(max); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxRClamp::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + if (min && max) + { + RESOLVE(min, ctx); + RESOLVE(max, ctx); + ABORT(min && max); + } + return this; +}; + + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxRClamp::EvalExpression(AActor *self) +{ + ExpVal val; + val.Type = VAL_Int; + + if (min != NULL && max != NULL) + { + int minval = min->EvalExpression(self).GetInt(); + int maxval = max->EvalExpression(self).GetInt(); + + if (maxval < minval) + { + swapvalues(maxval, minval); + } + + val.Int = (*rng)(2); //rng->operator()(2); //(maxval - minval + 1) + minval; + if (val.Int > 0) + val.Int = maxval; + else + val.Int = minval; + } + else + { + val.Int = (*rng)(); + } + return val; +} + //========================================================================== // // From 785f72d6eb257dd3392a5962c3310503890b53ba Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sat, 13 Dec 2014 15:59:27 -0600 Subject: [PATCH 28/32] - Renamed RClamp to Pick. --- src/namedef.h | 2 +- src/sc_man_scanner.re | 2 +- src/sc_man_tokens.h | 2 +- src/thingdef/thingdef_exp.cpp | 4 ++-- src/thingdef/thingdef_exp.h | 6 +++--- src/thingdef/thingdef_expression.cpp | 8 ++++---- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index 7eef612c1..e0b7e8ba6 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -300,7 +300,7 @@ xx(CallACS) xx(Sqrt) xx(CheckClass) xx(IsPointerEqual) -xx(RClamp) +xx(Pick) // Various actor names which are used internally xx(MapSpot) diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 2e25fb2f7..3a7f717a8 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -158,7 +158,7 @@ std2: 'random' { RET(TK_Random); } 'random2' { RET(TK_Random2); } 'frandom' { RET(TK_FRandom); } - 'rclamp' { RET(TK_RClamp); } + 'pick' { RET(TK_Pick); } L (L|D)* { RET(TK_Identifier); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 62622cf00..1c22046c9 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -122,5 +122,5 @@ xx(TK_Array, "'array'") xx(TK_In, "'in'") xx(TK_SizeOf, "'sizeof'") xx(TK_AlignOf, "'alignof'") -xx(TK_RClamp, "'rclamp'") +xx(TK_Pick, "'pick'") #undef xx diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 4cef24187..fd0936485 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -371,7 +371,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) return new FxRandom(rng, min, max, sc); } - else if (sc.CheckToken(TK_RClamp)) + else if (sc.CheckToken(TK_Pick)) { FRandom *rng; @@ -392,7 +392,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) FxExpression *max = ParseExpressionM(sc, cls); sc.MustGetToken(')'); - return new FxRClamp(rng, min, max, sc); + return new FxPick(rng, min, max, sc); } else if (sc.CheckToken(TK_FRandom)) { diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 42e35489d..03e465c3a 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -559,7 +559,7 @@ public: // //========================================================================== -class FxRClamp : public FxExpression +class FxPick : public FxExpression { protected: FRandom * rng; @@ -567,8 +567,8 @@ protected: public: - FxRClamp(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); - ~FxRClamp(); + FxPick(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); + ~FxPick(); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression(AActor *self); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 5a5510a0b..dc2cb2209 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1696,7 +1696,7 @@ ExpVal FxRandom::EvalExpression (AActor *self) // // //========================================================================== -FxRClamp::FxRClamp(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) +FxPick::FxPick(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) : FxExpression(pos) { if (mi != NULL && ma != NULL) @@ -1715,7 +1715,7 @@ FxRClamp::FxRClamp(FRandom * r, FxExpression *mi, FxExpression *ma, const FScrip // //========================================================================== -FxRClamp::~FxRClamp() +FxPick::~FxPick() { SAFE_DELETE(min); SAFE_DELETE(max); @@ -1727,7 +1727,7 @@ FxRClamp::~FxRClamp() // //========================================================================== -FxExpression *FxRClamp::Resolve(FCompileContext &ctx) +FxExpression *FxPick::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); if (min && max) @@ -1746,7 +1746,7 @@ FxExpression *FxRClamp::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxRClamp::EvalExpression(AActor *self) +ExpVal FxPick::EvalExpression(AActor *self) { ExpVal val; val.Type = VAL_Int; From 3f3aab42f1f1f20a522411c163800a78472b24b4 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sun, 14 Dec 2014 04:45:39 -0600 Subject: [PATCH 29/32] - Pick can now hold unlimited numbers to choose from. - I.e. pick(1,4,12,16) --- src/thingdef/thingdef_exp.cpp | 18 ++++++++--- src/thingdef/thingdef_exp.h | 4 +-- src/thingdef/thingdef_expression.cpp | 47 +++++++++++++--------------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index fd0936485..daa7f1a9c 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -374,6 +374,9 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) else if (sc.CheckToken(TK_Pick)) { FRandom *rng; + TArray list; + list.Clear(); + int index = 0; if (sc.CheckToken('[')) { @@ -387,12 +390,17 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) } sc.MustGetToken('('); - FxExpression *min = ParseExpressionM(sc, cls); - sc.MustGetToken(','); - FxExpression *max = ParseExpressionM(sc, cls); - sc.MustGetToken(')'); + while (!(sc.CheckToken(')'))) + { + FxExpression *min = ParseExpressionM(sc, cls); + list.Push(min); + if (sc.CheckToken(')')) + break; + else + sc.MustGetToken(','); + } - return new FxPick(rng, min, max, sc); + return new FxPick(rng, list, sc); } else if (sc.CheckToken(TK_FRandom)) { diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 03e465c3a..b53b8796b 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -563,11 +563,11 @@ class FxPick : public FxExpression { protected: FRandom * rng; - FxExpression *min, *max; + TArray min; public: - FxPick(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); + FxPick(FRandom *, TArray mi, const FScriptPosition &pos); ~FxPick(); FxExpression *Resolve(FCompileContext&); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index dc2cb2209..dd8e0e4c9 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1696,15 +1696,17 @@ ExpVal FxRandom::EvalExpression (AActor *self) // // //========================================================================== -FxPick::FxPick(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) +FxPick::FxPick(FRandom * r, TArray mi, const FScriptPosition &pos) : FxExpression(pos) { - if (mi != NULL && ma != NULL) + int index = 0; + int max = mi.Size(); + if (max > 0) { - min = new FxIntCast(mi); - max = new FxIntCast(ma); + for (index = 0; index < max; index++) + min.Push(new FxIntCast(mi[index])); } - else min = max = NULL; + else min.Clear(); rng = r; ValueType = VAL_Int; } @@ -1717,8 +1719,7 @@ FxPick::FxPick(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPos FxPick::~FxPick() { - SAFE_DELETE(min); - SAFE_DELETE(max); + min.Clear(); } //========================================================================== @@ -1729,12 +1730,17 @@ FxPick::~FxPick() FxExpression *FxPick::Resolve(FCompileContext &ctx) { + int index = 0; CHECKRESOLVED(); - if (min && max) + int max = min.Size(); + if (max > 0) { - RESOLVE(min, ctx); - RESOLVE(max, ctx); - ABORT(min && max); + for (index = 0; index < max; index++) + { + RESOLVE(min[index], ctx); + ABORT(min[index]); + } + } return this; }; @@ -1750,22 +1756,11 @@ ExpVal FxPick::EvalExpression(AActor *self) { ExpVal val; val.Type = VAL_Int; - - if (min != NULL && max != NULL) + int max = min.Size(); + if (max > 0) { - int minval = min->EvalExpression(self).GetInt(); - int maxval = max->EvalExpression(self).GetInt(); - - if (maxval < minval) - { - swapvalues(maxval, minval); - } - - val.Int = (*rng)(2); //rng->operator()(2); //(maxval - minval + 1) + minval; - if (val.Int > 0) - val.Int = maxval; - else - val.Int = minval; + int select = (*rng)(max); + val.Int = min[select]->EvalExpression(self).GetInt(); } else { From 6410428715cdcffdc4727ef31ca3549d40105f00 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 14 Dec 2014 12:03:55 +0100 Subject: [PATCH 30/32] - fixed: FxPick leaked the array's content. Also did some cleanup on FxPick code. --- src/thingdef/thingdef_exp.h | 2 +- src/thingdef/thingdef_expression.cpp | 21 +++++---------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index b53b8796b..0e03c661f 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -563,7 +563,7 @@ class FxPick : public FxExpression { protected: FRandom * rng; - TArray min; + TDeletingArray min; public: diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index dd8e0e4c9..913079bd2 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1699,14 +1699,10 @@ ExpVal FxRandom::EvalExpression (AActor *self) FxPick::FxPick(FRandom * r, TArray mi, const FScriptPosition &pos) : FxExpression(pos) { - int index = 0; - int max = mi.Size(); - if (max > 0) + for (unsigned int index = 0; index < mi.Size(); index++) { - for (index = 0; index < max; index++) - min.Push(new FxIntCast(mi[index])); + min.Push(new FxIntCast(mi[index])); } - else min.Clear(); rng = r; ValueType = VAL_Int; } @@ -1719,7 +1715,6 @@ FxPick::FxPick(FRandom * r, TArray mi, const FScriptPosition &pos FxPick::~FxPick() { - min.Clear(); } //========================================================================== @@ -1730,17 +1725,11 @@ FxPick::~FxPick() FxExpression *FxPick::Resolve(FCompileContext &ctx) { - int index = 0; CHECKRESOLVED(); - int max = min.Size(); - if (max > 0) + for (unsigned int index = 0; index < min.Size(); index++) { - for (index = 0; index < max; index++) - { - RESOLVE(min[index], ctx); - ABORT(min[index]); - } - + RESOLVE(min[index], ctx); + ABORT(min[index]); } return this; }; From b6c5cfb9efc8f398d09cbbfde3da653bdb968eaf Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 15 Dec 2014 10:26:22 -0600 Subject: [PATCH 31/32] - Fixed: The new HIT* flags were checking the wrong actor. --- src/p_mobj.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 39d1ba12d..49b4b983f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1202,9 +1202,9 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) if (target != NULL && ((target->flags & (MF_SHOOTABLE|MF_CORPSE)) || (target->flags6 & MF6_KILLED)) ) { - if (target->flags7 & MF7_HITTARGET) mo->target = target; - if (target->flags7 & MF7_HITMASTER) mo->master = target; - if (target->flags7 & MF7_HITTRACER) mo->tracer = target; + if (mo->flags7 & MF7_HITTARGET) mo->target = target; + if (mo->flags7 & MF7_HITMASTER) mo->master = target; + if (mo->flags7 & MF7_HITTRACER) mo->tracer = target; if (target->flags & MF_NOBLOOD) nextstate = mo->FindState(NAME_Crash); if (nextstate == NULL) nextstate = mo->FindState(NAME_Death, NAME_Extreme); } From 465d9ab89a288e9194b5143eb6a54d92692ba5ea Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 15 Dec 2014 14:50:35 -0600 Subject: [PATCH 32/32] - Added flags for A_CheckLOF: - CLOFF_SETTARGET | CLOFF_SETMASTER | CLOFF_SETTRACER - An actor that causes A_CheckLOF (and only an actor) to succeed will set the intercepting actor as its target, master, and/or tracer, respectively. --- src/thingdef/thingdef_codeptr.cpp | 57 ++++++++++++++++++------------ wadsrc/static/actors/constants.txt | 4 +++ 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index a620f0080..2a2da343e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3071,37 +3071,41 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget) enum CLOF_flags { - CLOFF_NOAIM_VERT = 0x1, - CLOFF_NOAIM_HORZ = 0x2, + CLOFF_NOAIM_VERT = 0x00000001, + CLOFF_NOAIM_HORZ = 0x00000002, - CLOFF_JUMPENEMY = 0x4, - CLOFF_JUMPFRIEND = 0x8, - CLOFF_JUMPOBJECT = 0x10, - CLOFF_JUMPNONHOSTILE = 0x20, + CLOFF_JUMPENEMY = 0x00000004, + CLOFF_JUMPFRIEND = 0x00000008, + CLOFF_JUMPOBJECT = 0x00000010, + CLOFF_JUMPNONHOSTILE = 0x00000020, - CLOFF_SKIPENEMY = 0x40, - CLOFF_SKIPFRIEND = 0x80, - CLOFF_SKIPOBJECT = 0x100, - CLOFF_SKIPNONHOSTILE = 0x200, + CLOFF_SKIPENEMY = 0x00000040, + CLOFF_SKIPFRIEND = 0x00000080, + CLOFF_SKIPOBJECT = 0x00000100, + CLOFF_SKIPNONHOSTILE = 0x00000200, - CLOFF_MUSTBESHOOTABLE = 0x400, + CLOFF_MUSTBESHOOTABLE = 0x00000400, - CLOFF_SKIPTARGET = 0x800, - CLOFF_ALLOWNULL = 0x1000, - CLOFF_CHECKPARTIAL = 0x2000, + CLOFF_SKIPTARGET = 0x00000800, + CLOFF_ALLOWNULL = 0x00001000, + CLOFF_CHECKPARTIAL = 0x00002000, - CLOFF_MUSTBEGHOST = 0x4000, - CLOFF_IGNOREGHOST = 0x8000, + CLOFF_MUSTBEGHOST = 0x00004000, + CLOFF_IGNOREGHOST = 0x00008000, - CLOFF_MUSTBESOLID = 0x10000, - CLOFF_BEYONDTARGET = 0x20000, + CLOFF_MUSTBESOLID = 0x00010000, + CLOFF_BEYONDTARGET = 0x00020000, - CLOFF_FROMBASE = 0x40000, - CLOFF_MUL_HEIGHT = 0x80000, - CLOFF_MUL_WIDTH = 0x100000, + CLOFF_FROMBASE = 0x00040000, + CLOFF_MUL_HEIGHT = 0x00080000, + CLOFF_MUL_WIDTH = 0x00100000, - CLOFF_JUMP_ON_MISS = 0x200000, - CLOFF_AIM_VERT_NOOFFSET = 0x400000, + CLOFF_JUMP_ON_MISS = 0x00200000, + CLOFF_AIM_VERT_NOOFFSET = 0x00400000, + + CLOFF_SETTARGET = 0x00800000, + CLOFF_SETMASTER = 0x01000000, + CLOFF_SETTRACER = 0x02000000, }; struct LOFData @@ -3341,6 +3345,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) { return; } + if ((trace.HitType == TRACE_HitActor) && (trace.Actor != NULL) && !(lof_data.BadActor)) + { + if (flags & (CLOFF_SETTARGET)) self->target = trace.Actor; + if (flags & (CLOFF_SETMASTER)) self->master = trace.Actor; + if (flags & (CLOFF_SETTRACER)) self->tracer = trace.Actor; + } + ACTION_JUMP(jump); } } diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 22914fbfc..8695c9c19 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -372,6 +372,10 @@ enum CLOFF_JUMP_ON_MISS = 0x200000, CLOFF_AIM_VERT_NOOFFSET = 0x400000, + CLOFF_SETTARGET = 0x800000, + CLOFF_SETMASTER = 0x1000000, + CLOFF_SETTRACER = 0x2000000, + CLOFF_SKIPOBSTACLES = CLOFF_SKIPENEMY|CLOFF_SKIPFRIEND|CLOFF_SKIPOBJECT|CLOFF_SKIPNONHOSTILE, CLOFF_NOAIM = CLOFF_NOAIM_VERT|CLOFF_NOAIM_HORZ };