This commit is contained in:
Rachael Alexanderson 2017-02-07 02:23:48 -05:00
commit d760b5070a
18 changed files with 595 additions and 530 deletions

View file

@ -2012,8 +2012,8 @@ PDynArray::PDynArray()
// //
//========================================================================== //==========================================================================
PDynArray::PDynArray(PType *etype) PDynArray::PDynArray(PType *etype,PStruct *backing)
: ElementType(etype) : ElementType(etype), BackingType(backing)
{ {
mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName());
Size = sizeof(FArray); Size = sizeof(FArray);
@ -2061,7 +2061,33 @@ PDynArray *NewDynArray(PType *type)
PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket); PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket);
if (atype == NULL) if (atype == NULL)
{ {
atype = new PDynArray(type); FString backingname;
switch (type->GetRegType())
{
case REGT_INT:
backingname.Format("DynArray_I%d", type->Size * 8);
break;
case REGT_FLOAT:
backingname.Format("DynArray_F%d", type->Size * 8);
break;
case REGT_STRING:
backingname = "DynArray_String";
break;
case REGT_POINTER:
backingname = "DynArray_Ptr";
break;
default:
I_Error("Unsupported dynamic array requested");
break;
}
auto backing = NewNativeStruct(backingname, nullptr);
atype = new PDynArray(type, backing);
TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket); TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket);
} }
return (PDynArray *)atype; return (PDynArray *)atype;

View file

@ -6,6 +6,7 @@
#endif #endif
typedef std::pair<const class PType *, unsigned> FTypeAndOffset; typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
class PStruct;
#include "vm.h" #include "vm.h"
@ -649,9 +650,10 @@ class PDynArray : public PCompoundType
DECLARE_CLASS(PDynArray, PCompoundType); DECLARE_CLASS(PDynArray, PCompoundType);
HAS_OBJECT_POINTERS; HAS_OBJECT_POINTERS;
public: public:
PDynArray(PType *etype); PDynArray(PType *etype, PStruct *backing);
PType *ElementType; PType *ElementType;
PStruct *BackingType;
virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;

View file

@ -821,6 +821,8 @@ xx(DamageFunction)
xx(Length) xx(Length)
xx(Unit) xx(Unit)
xx(Size) xx(Size)
xx(Copy)
xx(Move)
xx(Voidptr) xx(Voidptr)
xx(StateLabel) xx(StateLabel)
xx(SpriteID) xx(SpriteID)

View file

@ -1,28 +0,0 @@
/*
* Name: General Use Types Definitions -- Header Include file
* Version: 1.24
* Author: Vladimir Arnost (QA-Software)
* Last revision: Sep-4-1995
* Compiler: Borland C++ 3.1, Watcom C/C++ 10.0
*
*/
#ifndef __DEFTYPES_H_
#define __DEFTYPES_H_
/* Global type declarations */
#include "doomtype.h"
/* machine dependent types */
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef signed char schar;
typedef signed short sshort;
typedef signed int sint;
typedef signed long slong;
#endif // __DEFTYPES_H_

View file

@ -105,12 +105,6 @@ Revision History:
/* compiler dependence */ /* compiler dependence */
#ifndef OSD_CPU_H #ifndef OSD_CPU_H
#define OSD_CPU_H #define OSD_CPU_H
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif #endif
#ifndef PI #ifndef PI
@ -119,12 +113,8 @@ typedef signed int INT32; /* signed 32bit */
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning (disable: 4244) #pragma warning (disable: 4244)
#define INLINE __forceinline
#endif #endif
#ifdef __GNUC__
#define INLINE __inline
#endif
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define EG_SH 16 /* 16.16 fixed point (EG timing) */ #define EG_SH 16 /* 16.16 fixed point (EG timing) */
@ -171,97 +161,100 @@ typedef signed int INT32; /* signed 32bit */
/* Saving is necessary for member of the 'R' mark for suspend/resume */ /* Saving is necessary for member of the 'R' mark for suspend/resume */
typedef struct{ struct OPL_SLOT
UINT32 ar; /* attack rate: AR<<2 */ {
UINT32 dr; /* decay rate: DR<<2 */ uint32_t ar; /* attack rate: AR<<2 */
UINT32 rr; /* release rate:RR<<2 */ uint32_t dr; /* decay rate: DR<<2 */
UINT8 KSR; /* key scale rate */ uint32_t rr; /* release rate:RR<<2 */
UINT8 ksl; /* keyscale level */ uint8_t KSR; /* key scale rate */
UINT8 ksr; /* key scale rate: kcode>>KSR */ uint8_t ksl; /* keyscale level */
UINT8 mul; /* multiple: mul_tab[ML] */ uint8_t ksr; /* key scale rate: kcode>>KSR */
uint8_t mul; /* multiple: mul_tab[ML] */
/* Phase Generator */ /* Phase Generator */
UINT32 Cnt; /* frequency counter */ uint32_t Cnt; /* frequency counter */
UINT32 Incr; /* frequency counter step */ uint32_t Incr; /* frequency counter step */
UINT8 FB; /* feedback shift value */ uint8_t FB; /* feedback shift value */
INT32 *connect1; /* slot1 output pointer */ int32_t *connect1; /* slot1 output pointer */
INT32 op1_out[2]; /* slot1 output for feedback */ int32_t op1_out[2]; /* slot1 output for feedback */
UINT8 CON; /* connection (algorithm) type */ uint8_t CON; /* connection (algorithm) type */
/* Envelope Generator */ /* Envelope Generator */
UINT8 eg_type; /* percussive/non-percussive mode */ uint8_t eg_type; /* percussive/non-percussive mode */
UINT8 state; /* phase type */ uint8_t state; /* phase type */
UINT32 TL; /* total level: TL << 2 */ uint32_t TL; /* total level: TL << 2 */
INT32 TLL; /* adjusted now TL */ int32_t TLL; /* adjusted now TL */
INT32 volume; /* envelope counter */ int32_t volume; /* envelope counter */
UINT32 sl; /* sustain level: sl_tab[SL] */ uint32_t sl; /* sustain level: sl_tab[SL] */
uint8_t eg_sh_ar; /* (attack state) */
UINT8 eg_sh_ar; /* (attack state) */ uint8_t eg_sel_ar; /* (attack state) */
UINT8 eg_sel_ar; /* (attack state) */ uint8_t eg_sh_dr; /* (decay state) */
UINT8 eg_sh_dr; /* (decay state) */ uint8_t eg_sel_dr; /* (decay state) */
UINT8 eg_sel_dr; /* (decay state) */ uint8_t eg_sh_rr; /* (release state) */
UINT8 eg_sh_rr; /* (release state) */ uint8_t eg_sel_rr; /* (release state) */
UINT8 eg_sel_rr; /* (release state) */ uint32_t key; /* 0 = KEY OFF, >0 = KEY ON */
UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
/* LFO */ /* LFO */
UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ uint32_t AMmask; /* LFO Amplitude Modulation enable mask */
UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ uint8_t vib; /* LFO Phase Modulation enable flag (active high)*/
/* waveform select */ /* waveform select */
unsigned int wavetable; unsigned int wavetable;
} OPL_SLOT; };
typedef struct{ struct OPL_CH
{
OPL_SLOT SLOT[2]; OPL_SLOT SLOT[2];
/* phase generator state */ /* phase generator state */
UINT32 block_fnum; /* block+fnum */ uint32_t block_fnum; /* block+fnum */
UINT32 fc; /* Freq. Increment base */ uint32_t fc; /* Freq. Increment base */
UINT32 ksl_base; /* KeyScaleLevel Base step */ uint32_t ksl_base; /* KeyScaleLevel Base step */
UINT8 kcode; /* key code (for key scaling) */ uint8_t kcode; /* key code (for key scaling) */
float LeftVol; /* volumes for stereo panning */ float LeftVol; /* volumes for stereo panning */
float RightVol; float RightVol;
} OPL_CH; };
/* OPL state */ /* OPL state */
typedef struct fm_opl_f { struct FM_OPL
{
/* FM channel slots */ /* FM channel slots */
OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/
UINT32 eg_cnt; /* global envelope generator counter */ uint32_t eg_cnt; /* global envelope generator counter */
UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ uint32_t eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */
UINT32 eg_timer_add; /* step of eg_timer */ uint32_t eg_timer_add; /* step of eg_timer */
UINT32 eg_timer_overflow; /* envelope generator timer overflows every 1 sample (on real chip) */ uint32_t eg_timer_overflow; /* envelope generator timer overflows every 1 sample (on real chip) */
UINT8 rhythm; /* Rhythm mode */ uint8_t rhythm; /* Rhythm mode */
UINT32 fn_tab[1024]; /* fnumber->increment counter */ uint32_t fn_tab[1024]; /* fnumber->increment counter */
/* LFO */ /* LFO */
UINT8 lfo_am_depth;
UINT8 lfo_pm_depth_range;
UINT32 lfo_am_cnt;
UINT32 lfo_am_inc;
UINT32 lfo_pm_cnt;
UINT32 lfo_pm_inc;
UINT32 noise_rng; /* 23 bit noise shift register */ uint8_t lfo_am_depth;
UINT32 noise_p; /* current noise 'phase' */ uint8_t lfo_pm_depth_range;
UINT32 noise_f; /* current noise peroid */ uint32_t lfo_am_cnt;
uint32_t lfo_am_inc;
uint32_t lfo_pm_cnt;
uint32_t lfo_pm_inc;
UINT8 wavesel; /* waveform select enable flag */ uint32_t noise_rng; /* 23 bit noise shift register */
uint32_t noise_p; /* current noise 'phase' */
uint32_t noise_f; /* current noise period */
uint8_t wavesel; /* waveform select enable flag */
int T[2]; /* timer counters */ int T[2]; /* timer counters */
UINT8 st[2]; /* timer enable */ uint8_t st[2]; /* timer enable */
UINT8 address; /* address register */
UINT8 status; /* status flag */ uint8_t address; /* address register */
UINT8 statusmask; /* status mask */ uint8_t status; /* status flag */
UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ uint8_t statusmask; /* status mask */
uint8_t mode; /* Reg.08 : CSM,notesel,etc. */
bool IsStereo; /* Write stereo output */ bool IsStereo; /* Write stereo output */
} FM_OPL; };
@ -278,59 +271,59 @@ static const int slot_array[32]=
/* table is 3dB/octave , DV converts this into 6dB/octave */ /* table is 3dB/octave , DV converts this into 6dB/octave */
/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ /* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */
#define DV (0.1875/2.0) #define DV (0.1875/2.0)
static const UINT32 ksl_tab[8*16]= static const uint32_t ksl_tab[8*16]=
{ {
/* OCT 0 */ /* OCT 0 */
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
/* OCT 1 */ /* OCT 1 */
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
UINT32(0.000/DV), UINT32(0.750/DV), UINT32(1.125/DV), UINT32(1.500/DV), uint32_t(0.000/DV), uint32_t(0.750/DV), uint32_t(1.125/DV), uint32_t(1.500/DV),
UINT32(1.875/DV), UINT32(2.250/DV), UINT32(2.625/DV), UINT32(3.000/DV), uint32_t(1.875/DV), uint32_t(2.250/DV), uint32_t(2.625/DV), uint32_t(3.000/DV),
/* OCT 2 */ /* OCT 2 */
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
UINT32(0.000/DV), UINT32(1.125/DV), UINT32(1.875/DV), UINT32(2.625/DV), uint32_t(0.000/DV), uint32_t(1.125/DV), uint32_t(1.875/DV), uint32_t(2.625/DV),
UINT32(3.000/DV), UINT32(3.750/DV), UINT32(4.125/DV), UINT32(4.500/DV), uint32_t(3.000/DV), uint32_t(3.750/DV), uint32_t(4.125/DV), uint32_t(4.500/DV),
UINT32(4.875/DV), UINT32(5.250/DV), UINT32(5.625/DV), UINT32(6.000/DV), uint32_t(4.875/DV), uint32_t(5.250/DV), uint32_t(5.625/DV), uint32_t(6.000/DV),
/* OCT 3 */ /* OCT 3 */
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(1.875/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(1.875/DV),
UINT32(3.000/DV), UINT32(4.125/DV), UINT32(4.875/DV), UINT32(5.625/DV), uint32_t(3.000/DV), uint32_t(4.125/DV), uint32_t(4.875/DV), uint32_t(5.625/DV),
UINT32(6.000/DV), UINT32(6.750/DV), UINT32(7.125/DV), UINT32(7.500/DV), uint32_t(6.000/DV), uint32_t(6.750/DV), uint32_t(7.125/DV), uint32_t(7.500/DV),
UINT32(7.875/DV), UINT32(8.250/DV), UINT32(8.625/DV), UINT32(9.000/DV), uint32_t(7.875/DV), uint32_t(8.250/DV), uint32_t(8.625/DV), uint32_t(9.000/DV),
/* OCT 4 */ /* OCT 4 */
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(3.000/DV), UINT32(4.875/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(4.875/DV),
UINT32(6.000/DV), UINT32(7.125/DV), UINT32(7.875/DV), UINT32(8.625/DV), uint32_t(6.000/DV), uint32_t(7.125/DV), uint32_t(7.875/DV), uint32_t(8.625/DV),
UINT32(9.000/DV), UINT32(9.750/DV),UINT32(10.125/DV),UINT32(10.500/DV), uint32_t(9.000/DV), uint32_t(9.750/DV),uint32_t(10.125/DV),uint32_t(10.500/DV),
UINT32(10.875/DV),UINT32(11.250/DV),UINT32(11.625/DV),UINT32(12.000/DV), uint32_t(10.875/DV),uint32_t(11.250/DV),uint32_t(11.625/DV),uint32_t(12.000/DV),
/* OCT 5 */ /* OCT 5 */
UINT32(0.000/DV), UINT32(3.000/DV), UINT32(6.000/DV), UINT32(7.875/DV), uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(6.000/DV), uint32_t(7.875/DV),
UINT32(9.000/DV),UINT32(10.125/DV),UINT32(10.875/DV),UINT32(11.625/DV), uint32_t(9.000/DV),uint32_t(10.125/DV),uint32_t(10.875/DV),uint32_t(11.625/DV),
UINT32(12.000/DV),UINT32(12.750/DV),UINT32(13.125/DV),UINT32(13.500/DV), uint32_t(12.000/DV),uint32_t(12.750/DV),uint32_t(13.125/DV),uint32_t(13.500/DV),
UINT32(13.875/DV),UINT32(14.250/DV),UINT32(14.625/DV),UINT32(15.000/DV), uint32_t(13.875/DV),uint32_t(14.250/DV),uint32_t(14.625/DV),uint32_t(15.000/DV),
/* OCT 6 */ /* OCT 6 */
UINT32(0.000/DV), UINT32(6.000/DV), UINT32(9.000/DV),UINT32(10.875/DV), uint32_t(0.000/DV), uint32_t(6.000/DV), uint32_t(9.000/DV),uint32_t(10.875/DV),
UINT32(12.000/DV),UINT32(13.125/DV),UINT32(13.875/DV),UINT32(14.625/DV), uint32_t(12.000/DV),uint32_t(13.125/DV),uint32_t(13.875/DV),uint32_t(14.625/DV),
UINT32(15.000/DV),UINT32(15.750/DV),UINT32(16.125/DV),UINT32(16.500/DV), uint32_t(15.000/DV),uint32_t(15.750/DV),uint32_t(16.125/DV),uint32_t(16.500/DV),
UINT32(16.875/DV),UINT32(17.250/DV),UINT32(17.625/DV),UINT32(18.000/DV), uint32_t(16.875/DV),uint32_t(17.250/DV),uint32_t(17.625/DV),uint32_t(18.000/DV),
/* OCT 7 */ /* OCT 7 */
UINT32(0.000/DV), UINT32(9.000/DV),UINT32(12.000/DV),UINT32(13.875/DV), uint32_t(0.000/DV), uint32_t(9.000/DV),uint32_t(12.000/DV),uint32_t(13.875/DV),
UINT32(15.000/DV),UINT32(16.125/DV),UINT32(16.875/DV),UINT32(17.625/DV), uint32_t(15.000/DV),uint32_t(16.125/DV),uint32_t(16.875/DV),uint32_t(17.625/DV),
UINT32(18.000/DV),UINT32(18.750/DV),UINT32(19.125/DV),UINT32(19.500/DV), uint32_t(18.000/DV),uint32_t(18.750/DV),uint32_t(19.125/DV),uint32_t(19.500/DV),
UINT32(19.875/DV),UINT32(20.250/DV),UINT32(20.625/DV),UINT32(21.000/DV) uint32_t(19.875/DV),uint32_t(20.250/DV),uint32_t(20.625/DV),uint32_t(21.000/DV)
}; };
#undef DV #undef DV
/* 0 / 3.0 / 1.5 / 6.0 dB/OCT */ /* 0 / 3.0 / 1.5 / 6.0 dB/OCT */
static const UINT32 ksl_shift[4] = { 31, 1, 2, 0 }; static const uint32_t ksl_shift[4] = { 31, 1, 2, 0 };
/* sustain level table (3dB per step) */ /* sustain level table (3dB per step) */
/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ /* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) #define SC(db) (uint32_t) ( db * (2.0/ENV_STEP) )
static const UINT32 sl_tab[16]={ static const uint32_t sl_tab[16]={
SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
}; };
@ -339,7 +332,6 @@ static const UINT32 sl_tab[16]={
#define RATE_STEPS (8) #define RATE_STEPS (8)
static const unsigned char eg_inc[15*RATE_STEPS]={ static const unsigned char eg_inc[15*RATE_STEPS]={
/*cycle:0 1 2 3 4 5 6 7*/ /*cycle:0 1 2 3 4 5 6 7*/
/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ /* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */
@ -446,10 +438,10 @@ O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
/* multiple table */ /* multiple table */
#define ML 2 #define ML 2
static const UINT8 mul_tab[16]= { static const uint8_t mul_tab[16]= {
/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ /* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */
UINT8(0.50*ML), UINT8(1.00*ML), UINT8(2.00*ML), UINT8(3.00*ML), UINT8(4.00*ML), UINT8(5.00*ML), UINT8(6.00*ML), UINT8(7.00*ML), uint8_t(0.50*ML), uint8_t(1.00*ML), uint8_t(2.00*ML), uint8_t(3.00*ML), uint8_t(4.00*ML), uint8_t(5.00*ML), uint8_t(6.00*ML), uint8_t(7.00*ML),
UINT8(8.00*ML), UINT8(9.00*ML),UINT8(10.00*ML),UINT8(10.00*ML),UINT8(12.00*ML),UINT8(12.00*ML),UINT8(15.00*ML),UINT8(15.00*ML) uint8_t(8.00*ML), uint8_t(9.00*ML),uint8_t(10.00*ML),uint8_t(10.00*ML),uint8_t(12.00*ML),uint8_t(12.00*ML),uint8_t(15.00*ML),uint8_t(15.00*ML)
}; };
#undef ML #undef ML
@ -478,12 +470,12 @@ static unsigned int sin_tab[SIN_LEN * 4];
The whole table takes: 64 * 210 = 13440 samples. The whole table takes: 64 * 210 = 13440 samples.
When AM = 1 data is used directly When AM = 1 data is used directly
When AM = 0 data is divided by 4 before being used (loosing precision is important) When AM = 0 data is divided by 4 before being used (losing precision is important)
*/ */
#define LFO_AM_TAB_ELEMENTS 210 #define LFO_AM_TAB_ELEMENTS 210
static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { static const uint8_t lfo_am_table[LFO_AM_TAB_ELEMENTS] = {
0,0,0,0,0,0,0, 0,0,0,0,0,0,0,
1,1,1,1, 1,1,1,1,
2,2,2,2, 2,2,2,2,
@ -539,8 +531,7 @@ static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = {
}; };
/* LFO Phase Modulation table (verified on real YM3812) */ /* LFO Phase Modulation table (verified on real YM3812) */
static const INT8 lfo_pm_table[8*8*2] = { static const int8_t lfo_pm_table[8*8*2] = {
/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ /* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */
0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ 0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/
0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ 0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/
@ -582,8 +573,8 @@ static int num_lock = 0;
static signed int phase_modulation; /* phase modulation input (SLOT 2) */ static signed int phase_modulation; /* phase modulation input (SLOT 2) */
static signed int output; static signed int output;
static UINT32 LFO_AM; static uint32_t LFO_AM;
static INT32 LFO_PM; static int32_t LFO_PM;
static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length); static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length);
static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length); static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length);
@ -591,7 +582,7 @@ static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length);
/* status set and IRQ handling */ /* status set and IRQ handling */
INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag)
{ {
/* set status flag */ /* set status flag */
OPL->status |= flag; OPL->status |= flag;
@ -605,7 +596,7 @@ INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag)
} }
/* status reset and IRQ handling */ /* status reset and IRQ handling */
INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
{ {
/* reset status flag */ /* reset status flag */
OPL->status &=~flag; OPL->status &=~flag;
@ -619,7 +610,7 @@ INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
} }
/* IRQ mask set */ /* IRQ mask set */
INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) static inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
{ {
OPL->statusmask = flag; OPL->statusmask = flag;
/* IRQ handling check */ /* IRQ handling check */
@ -629,13 +620,13 @@ INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
/* advance LFO to next sample */ /* advance LFO to next sample */
INLINE void advance_lfo(FM_OPL *OPL) static inline void advance_lfo(FM_OPL *OPL)
{ {
UINT8 tmp; uint8_t tmp;
/* LFO */ /* LFO */
OPL->lfo_am_cnt += OPL->lfo_am_inc; OPL->lfo_am_cnt += OPL->lfo_am_inc;
if (OPL->lfo_am_cnt >= (UINT32)(LFO_AM_TAB_ELEMENTS<<LFO_SH) ) /* lfo_am_table is 210 elements long */ if (OPL->lfo_am_cnt >= (uint32_t)(LFO_AM_TAB_ELEMENTS<<LFO_SH) ) /* lfo_am_table is 210 elements long */
OPL->lfo_am_cnt -= (LFO_AM_TAB_ELEMENTS<<LFO_SH); OPL->lfo_am_cnt -= (LFO_AM_TAB_ELEMENTS<<LFO_SH);
tmp = lfo_am_table[ OPL->lfo_am_cnt >> LFO_SH ]; tmp = lfo_am_table[ OPL->lfo_am_cnt >> LFO_SH ];
@ -650,7 +641,7 @@ INLINE void advance_lfo(FM_OPL *OPL)
} }
/* advance to next sample */ /* advance to next sample */
INLINE void advance(FM_OPL *OPL, int loch, int hich) static inline void advance(FM_OPL *OPL, int loch, int hich)
{ {
OPL_CH *CH; OPL_CH *CH;
OPL_SLOT *op; OPL_SLOT *op;
@ -695,7 +686,7 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich)
{ {
op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)];
if ( op->volume >= (INT32)op->sl ) if ( op->volume >= (int32_t)op->sl )
op->state = EG_SUS; op->state = EG_SUS;
} }
@ -746,7 +737,7 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich)
/* Phase Generator */ /* Phase Generator */
if(op->vib) if(op->vib)
{ {
UINT8 block; uint8_t block;
unsigned int block_fnum = CH->block_fnum; unsigned int block_fnum = CH->block_fnum;
unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; unsigned int fnum_lfo = (block_fnum&0x0380) >> 7;
@ -772,7 +763,7 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich)
} }
} }
INLINE void advance_noise(FM_OPL *OPL) static inline void advance_noise(FM_OPL *OPL)
{ {
int i; int i;
@ -793,7 +784,7 @@ INLINE void advance_noise(FM_OPL *OPL)
while (i) while (i)
{ {
/* /*
UINT32 j; uint32_t j;
j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1;
OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1);
*/ */
@ -814,9 +805,9 @@ INLINE void advance_noise(FM_OPL *OPL)
} }
INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) static inline signed int op_calc(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab)
{ {
UINT32 p; uint32_t p;
p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ];
@ -825,9 +816,9 @@ INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigne
return tl_tab[p]; return tl_tab[p];
} }
INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) static inline signed int op_calc1(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab)
{ {
UINT32 p; uint32_t p;
p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ]; p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ];
@ -837,10 +828,10 @@ INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsign
} }
#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) #define volume_calc(OP) ((OP)->TLL + ((uint32_t)(OP)->volume) + (LFO_AM & (OP)->AMmask))
/* calculate output */ /* calculate output */
INLINE float OPL_CALC_CH( OPL_CH *CH ) static inline float OPL_CALC_CH( OPL_CH *CH )
{ {
OPL_SLOT *SLOT; OPL_SLOT *SLOT;
unsigned int env; unsigned int env;
@ -911,7 +902,7 @@ number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal
/* calculate rhythm */ /* calculate rhythm */
INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) static inline void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
{ {
OPL_SLOT *SLOT; OPL_SLOT *SLOT;
signed int out; signed int out;
@ -988,7 +979,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
/* when res1 = 0 phase = 0x000 | 0xd0; */ /* when res1 = 0 phase = 0x000 | 0xd0; */
/* when res1 = 1 phase = 0x200 | (0xd0>>2); */ /* when res1 = 1 phase = 0x200 | (0xd0>>2); */
UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; uint32_t phase = res1 ? (0x200|(0xd0>>2)) : 0xd0;
/* enable gate based on frequency of operator 2 in channel 8 */ /* enable gate based on frequency of operator 2 in channel 8 */
unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1; unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1;
@ -1029,7 +1020,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
/* when bit8 = 0 phase = 0x100; */ /* when bit8 = 0 phase = 0x100; */
/* when bit8 = 1 phase = 0x200; */ /* when bit8 = 1 phase = 0x200; */
UINT32 phase = bit8 ? 0x200 : 0x100; uint32_t phase = bit8 ? 0x200 : 0x100;
/* Noise bit XOR'es phase by 0x100 */ /* Noise bit XOR'es phase by 0x100 */
/* when noisebit = 0 pass the phase from calculation above */ /* when noisebit = 0 pass the phase from calculation above */
@ -1059,7 +1050,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
/* when res1 = 0 phase = 0x000 | 0x100; */ /* when res1 = 0 phase = 0x000 | 0x100; */
/* when res1 = 1 phase = 0x200 | 0x100; */ /* when res1 = 1 phase = 0x200 | 0x100; */
UINT32 phase = res1 ? 0x300 : 0x100; uint32_t phase = res1 ? 0x300 : 0x100;
/* enable gate based on frequency of operator 2 in channel 8 */ /* enable gate based on frequency of operator 2 in channel 8 */
unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1; unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1;
@ -1073,7 +1064,6 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
output += op_calc(phase<<FREQ_SH, env, 0, CH[8].SLOT[SLOT2].wavetable) * 2; output += op_calc(phase<<FREQ_SH, env, 0, CH[8].SLOT[SLOT2].wavetable) * 2;
} }
} }
@ -1176,18 +1166,18 @@ static void OPL_initalize(FM_OPL *OPL)
for( i=0 ; i < 1024 ; i++ ) for( i=0 ; i < 1024 ; i++ )
{ {
/* opn phase increment counter = 20bit */ /* opn phase increment counter = 20bit */
OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL_FREQBASE * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ OPL->fn_tab[i] = (uint32_t)( (double)i * 64 * OPL_FREQBASE * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
} }
/* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */
/* One entry from LFO_AM_TABLE lasts for 64 samples */ /* One entry from LFO_AM_TABLE lasts for 64 samples */
OPL->lfo_am_inc = UINT32((1.0 / 64.0 ) * (1<<LFO_SH) * OPL_FREQBASE); OPL->lfo_am_inc = uint32_t((1.0 / 64.0 ) * (1<<LFO_SH) * OPL_FREQBASE);
/* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */
OPL->lfo_pm_inc = UINT32((1.0 / 1024.0) * (1<<LFO_SH) * OPL_FREQBASE); OPL->lfo_pm_inc = uint32_t((1.0 / 1024.0) * (1<<LFO_SH) * OPL_FREQBASE);
OPL->eg_timer_add = UINT32((1<<EG_SH) * OPL_FREQBASE); OPL->eg_timer_add = uint32_t((1<<EG_SH) * OPL_FREQBASE);
OPL->eg_timer_overflow = UINT32(( 1 ) * (1<<EG_SH)); OPL->eg_timer_overflow = uint32_t(( 1 ) * (1<<EG_SH));
// [RH] Support full MIDI panning. (But default to mono and center panning.) // [RH] Support full MIDI panning. (But default to mono and center panning.)
OPL->IsStereo = false; OPL->IsStereo = false;
@ -1198,7 +1188,7 @@ static void OPL_initalize(FM_OPL *OPL)
} }
} }
INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) static inline void FM_KEYON(OPL_SLOT *SLOT, uint32_t key_set)
{ {
if( !SLOT->key ) if( !SLOT->key )
{ {
@ -1210,7 +1200,7 @@ INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set)
SLOT->key |= key_set; SLOT->key |= key_set;
} }
INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr) static inline void FM_KEYOFF(OPL_SLOT *SLOT, uint32_t key_clr)
{ {
if( SLOT->key ) if( SLOT->key )
{ {
@ -1226,7 +1216,7 @@ INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr)
} }
/* update phase increment counter of operator (also update the EG rates if necessary) */ /* update phase increment counter of operator (also update the EG rates if necessary) */
void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) static inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
{ {
int ksr; int ksr;
@ -1257,7 +1247,7 @@ void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
} }
/* set multi,am,vib,EG-TYP,KSR,mul */ /* set multi,am,vib,EG-TYP,KSR,mul */
void set_mul(FM_OPL *OPL,int slot,int v) static inline void set_mul(FM_OPL *OPL,int slot,int v)
{ {
OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_CH *CH = &OPL->P_CH[slot/2];
OPL_SLOT *SLOT = &CH->SLOT[slot&1]; OPL_SLOT *SLOT = &CH->SLOT[slot&1];
@ -1271,7 +1261,7 @@ void set_mul(FM_OPL *OPL,int slot,int v)
} }
/* set ksl & tl */ /* set ksl & tl */
void set_ksl_tl(FM_OPL *OPL,int slot,int v) static inline void set_ksl_tl(FM_OPL *OPL,int slot,int v)
{ {
OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_CH *CH = &OPL->P_CH[slot/2];
OPL_SLOT *SLOT = &CH->SLOT[slot&1]; OPL_SLOT *SLOT = &CH->SLOT[slot&1];
@ -1283,7 +1273,7 @@ void set_ksl_tl(FM_OPL *OPL,int slot,int v)
} }
/* set attack rate & decay rate */ /* set attack rate & decay rate */
INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) static inline void set_ar_dr(FM_OPL *OPL,int slot,int v)
{ {
OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_CH *CH = &OPL->P_CH[slot/2];
OPL_SLOT *SLOT = &CH->SLOT[slot&1]; OPL_SLOT *SLOT = &CH->SLOT[slot&1];
@ -1307,7 +1297,7 @@ INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
} }
/* set sustain level & release rate */ /* set sustain level & release rate */
void set_sl_rr(FM_OPL *OPL,int slot,int v) static inline void set_sl_rr(FM_OPL *OPL,int slot,int v)
{ {
OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_CH *CH = &OPL->P_CH[slot/2];
OPL_SLOT *SLOT = &CH->SLOT[slot&1]; OPL_SLOT *SLOT = &CH->SLOT[slot&1];
@ -1352,12 +1342,13 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
} }
else else
{ /* set IRQ mask ,timer enable*/ { /* set IRQ mask ,timer enable*/
UINT8 st1 = v&1; uint8_t st1 = v&1;
UINT8 st2 = (v>>1)&1; uint8_t st2 = (v>>1)&1;
/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
OPL_STATUS_RESET(OPL, v & (0x78-0x08) ); OPL_STATUS_RESET(OPL, v & (0x78-0x08) );
OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); OPL_STATUSMASK_SET(OPL, (~v) & 0x78 );
/* timer 2 */ /* timer 2 */
if(OPL->st[1] != st2) if(OPL->st[1] != st2)
{ {
@ -1468,9 +1459,9 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
} }
} }
/* update */ /* update */
if(CH->block_fnum != (UINT32)block_fnum) if(CH->block_fnum != (uint32_t)block_fnum)
{ {
UINT8 block = block_fnum >> 10; uint8_t block = block_fnum >> 10;
CH->block_fnum = block_fnum; CH->block_fnum = block_fnum;
@ -1604,15 +1595,15 @@ public:
{ {
int i; int i;
UINT8 rhythm = Chip.rhythm&0x20; uint8_t rhythm = Chip.rhythm&0x20;
UINT32 lfo_am_cnt_bak = Chip.lfo_am_cnt; uint32_t lfo_am_cnt_bak = Chip.lfo_am_cnt;
UINT32 eg_timer_bak = Chip.eg_timer; uint32_t eg_timer_bak = Chip.eg_timer;
UINT32 eg_cnt_bak = Chip.eg_cnt; uint32_t eg_cnt_bak = Chip.eg_cnt;
UINT32 lfo_am_cnt_out = lfo_am_cnt_bak; uint32_t lfo_am_cnt_out = lfo_am_cnt_bak;
UINT32 eg_timer_out = eg_timer_bak; uint32_t eg_timer_out = eg_timer_bak;
UINT32 eg_cnt_out = eg_cnt_bak; uint32_t eg_cnt_out = eg_cnt_bak;
for (i = 0; i <= (rhythm ? 5 : 8); ++i) for (i = 0; i <= (rhythm ? 5 : 8); ++i)
{ {

View file

@ -69,12 +69,12 @@ musicBlock::~musicBlock ()
if (OPLinstruments != NULL) free(OPLinstruments); if (OPLinstruments != NULL) free(OPLinstruments);
} }
void musicBlock::writeFrequency(uint slot, uint note, int pitch, uint keyOn) void musicBlock::writeFrequency(uint32_t slot, uint32_t note, int pitch, uint32_t keyOn)
{ {
io->OPLwriteFreq (slot, note, pitch, keyOn); io->OPLwriteFreq (slot, note, pitch, keyOn);
} }
void musicBlock::writeModulation(uint slot, struct OPL2instrument *instr, int state) void musicBlock::writeModulation(uint32_t slot, struct OPL2instrument *instr, int state)
{ {
if (state) if (state)
state = 0x40; /* enable Frequency Vibrato */ state = 0x40; /* enable Frequency Vibrato */
@ -83,17 +83,17 @@ void musicBlock::writeModulation(uint slot, struct OPL2instrument *instr, int st
instr->trem_vibr_2 | state); instr->trem_vibr_2 | state);
} }
uint musicBlock::calcVolume(uint channelVolume, uint channelExpression, uint noteVolume) uint32_t musicBlock::calcVolume(uint32_t channelVolume, uint32_t channelExpression, uint32_t noteVolume)
{ {
noteVolume = ((ulong)channelVolume * channelExpression * noteVolume) / (127*127); noteVolume = ((uint64_t)channelVolume * channelExpression * noteVolume) / (127*127);
if (noteVolume > 127) if (noteVolume > 127)
return 127; return 127;
else else
return noteVolume; return noteVolume;
} }
int musicBlock::occupyChannel(uint slot, uint channel, int musicBlock::occupyChannel(uint32_t slot, uint32_t channel,
int note, int volume, struct OP2instrEntry *instrument, uchar secondary) int note, int volume, struct OP2instrEntry *instrument, uint8_t secondary)
{ {
struct OPL2instrument *instr; struct OPL2instrument *instr;
struct channelEntry *ch = &channels[slot]; struct channelEntry *ch = &channels[slot];
@ -142,7 +142,7 @@ int musicBlock::occupyChannel(uint slot, uint channel,
return slot; return slot;
} }
int musicBlock::releaseChannel(uint slot, uint killed) int musicBlock::releaseChannel(uint32_t slot, uint32_t killed)
{ {
struct channelEntry *ch = &channels[slot]; struct channelEntry *ch = &channels[slot];
writeFrequency(slot, ch->realnote, ch->pitch, 0); writeFrequency(slot, ch->realnote, ch->pitch, 0);
@ -157,10 +157,10 @@ int musicBlock::releaseChannel(uint slot, uint killed)
return slot; return slot;
} }
int musicBlock::releaseSustain(uint channel) int musicBlock::releaseSustain(uint32_t channel)
{ {
uint i; uint32_t i;
uint id = channel; uint32_t id = channel;
for(i = 0; i < io->OPLchannels; i++) for(i = 0; i < io->OPLchannels; i++)
{ {
@ -170,16 +170,16 @@ int musicBlock::releaseSustain(uint channel)
return 0; return 0;
} }
int musicBlock::findFreeChannel(uint flag, uint channel, uchar note) int musicBlock::findFreeChannel(uint32_t flag, uint32_t channel, uint8_t note)
{ {
uint i; uint32_t i;
ulong bestfit = 0; uint32_t bestfit = 0;
uint bestvoice = 0; uint32_t bestvoice = 0;
for (i = 0; i < io->OPLchannels; ++i) for (i = 0; i < io->OPLchannels; ++i)
{ {
ulong magic; uint32_t magic;
magic = ((channels[i].flags & CH_FREE) << 24) | magic = ((channels[i].flags & CH_FREE) << 24) |
((channels[i].note == note && ((channels[i].note == note &&
@ -200,9 +200,9 @@ int musicBlock::findFreeChannel(uint flag, uint channel, uchar note)
return bestvoice; return bestvoice;
} }
struct OP2instrEntry *musicBlock::getInstrument(uint channel, uchar note) struct OP2instrEntry *musicBlock::getInstrument(uint32_t channel, uint8_t note)
{ {
uint instrnumber; uint32_t instrnumber;
if (channel == PERCUSSION) if (channel == PERCUSSION)
{ {
@ -225,7 +225,7 @@ struct OP2instrEntry *musicBlock::getInstrument(uint channel, uchar note)
// code 1: play note // code 1: play note
CVAR (Bool, opl_singlevoice, 0, 0) CVAR (Bool, opl_singlevoice, 0, 0)
void musicBlock::OPLplayNote(uint channel, uchar note, int volume) void musicBlock::OPLplayNote(uint32_t channel, uint8_t note, int volume)
{ {
int i; int i;
struct OP2instrEntry *instr; struct OP2instrEntry *instr;
@ -251,11 +251,11 @@ void musicBlock::OPLplayNote(uint channel, uchar note, int volume)
} }
// code 0: release note // code 0: release note
void musicBlock::OPLreleaseNote(uint channel, uchar note) void musicBlock::OPLreleaseNote(uint32_t channel, uint8_t note)
{ {
uint i; uint32_t i;
uint id = channel; uint32_t id = channel;
uint sustain = driverdata.channelSustain[channel]; uint32_t sustain = driverdata.channelSustain[channel];
for(i = 0; i < io->OPLchannels; i++) for(i = 0; i < io->OPLchannels; i++)
{ {
@ -270,10 +270,10 @@ void musicBlock::OPLreleaseNote(uint channel, uchar note)
} }
// code 2: change pitch wheel (bender) // code 2: change pitch wheel (bender)
void musicBlock::OPLpitchWheel(uint channel, int pitch) void musicBlock::OPLpitchWheel(uint32_t channel, int pitch)
{ {
uint i; uint32_t i;
uint id = channel; uint32_t id = channel;
// Convert pitch from 14-bit to 7-bit, then scale it, since the player // Convert pitch from 14-bit to 7-bit, then scale it, since the player
// code only understands sensitivities of 2 semitones. // code only understands sensitivities of 2 semitones.
@ -292,10 +292,10 @@ void musicBlock::OPLpitchWheel(uint channel, int pitch)
} }
// code 4: change control // code 4: change control
void musicBlock::OPLchangeControl(uint channel, uchar controller, int value) void musicBlock::OPLchangeControl(uint32_t channel, uint8_t controller, int value)
{ {
uint i; uint32_t i;
uint id = channel; uint32_t id = channel;
switch (controller) switch (controller)
{ {
@ -310,7 +310,7 @@ void musicBlock::OPLchangeControl(uint channel, uchar controller, int value)
struct channelEntry *ch = &channels[i]; struct channelEntry *ch = &channels[i];
if (ch->channel == id) if (ch->channel == id)
{ {
uchar flags = ch->flags; uint8_t flags = ch->flags;
ch->time = MLtime; ch->time = MLtime;
if (value >= MOD_MIN) if (value >= MOD_MIN)
{ {
@ -418,7 +418,7 @@ void musicBlock::OPLchangeControl(uint channel, uchar controller, int value)
} }
} }
void musicBlock::OPLresetControllers(uint chan, int vol) void musicBlock::OPLresetControllers(uint32_t chan, int vol)
{ {
driverdata.channelVolume[chan] = vol; driverdata.channelVolume[chan] = vol;
driverdata.channelExpression[chan] = 127; driverdata.channelExpression[chan] = 127;
@ -429,14 +429,14 @@ void musicBlock::OPLresetControllers(uint chan, int vol)
driverdata.channelPitchSens[chan] = 200; driverdata.channelPitchSens[chan] = 200;
} }
void musicBlock::OPLprogramChange(uint channel, int value) void musicBlock::OPLprogramChange(uint32_t channel, int value)
{ {
driverdata.channelInstr[channel] = value; driverdata.channelInstr[channel] = value;
} }
void musicBlock::OPLplayMusic(int vol) void musicBlock::OPLplayMusic(int vol)
{ {
uint i; uint32_t i;
for (i = 0; i < CHANNELS; i++) for (i = 0; i < CHANNELS; i++)
{ {
@ -446,7 +446,7 @@ void musicBlock::OPLplayMusic(int vol)
void musicBlock::OPLstopMusic() void musicBlock::OPLstopMusic()
{ {
uint i; uint32_t i;
for(i = 0; i < io->OPLchannels; i++) for(i = 0; i < io->OPLchannels; i++)
if (!(channels[i].flags & CH_FREE)) if (!(channels[i].flags & CH_FREE))
releaseChannel(i, 1); releaseChannel(i, 1);
@ -454,10 +454,10 @@ void musicBlock::OPLstopMusic()
int musicBlock::OPLloadBank (FileReader &data) int musicBlock::OPLloadBank (FileReader &data)
{ {
static const uchar masterhdr[8] = { '#','O','P','L','_','I','I','#' }; static const uint8_t masterhdr[8] = { '#','O','P','L','_','I','I','#' };
struct OP2instrEntry *instruments; struct OP2instrEntry *instruments;
uchar filehdr[8]; uint8_t filehdr[8];
data.Read (filehdr, 8); data.Read (filehdr, 8);
if (memcmp(filehdr, masterhdr, 8)) if (memcmp(filehdr, masterhdr, 8))

View file

@ -22,7 +22,7 @@
* Oct-30-1994 V1.40 V.Arnost * Oct-30-1994 V1.40 V.Arnost
* Added BLASTER variable parsing * Added BLASTER variable parsing
* Apr-14-1995 V1.50 V.Arnost * Apr-14-1995 V1.50 V.Arnost
* Some declarations moved from adlib.h to deftypes.h * Some declarations moved from adlib.h to doomtype.h
* Jul-22-1995 V1.60 V.Arnost * Jul-22-1995 V1.60 V.Arnost
* Ported to Watcom C * Ported to Watcom C
* Simplified WriteChannel() and WriteValue() * Simplified WriteChannel() and WriteValue()
@ -63,7 +63,7 @@ void OPLio::WriteDelay(int ticks)
{ {
} }
void OPLio::OPLwriteReg(int which, uint reg, uchar data) void OPLio::OPLwriteReg(int which, uint32_t reg, uint8_t data)
{ {
if (IsOPL3) if (IsOPL3)
{ {
@ -80,13 +80,13 @@ void OPLio::OPLwriteReg(int which, uint reg, uchar data)
* Write to an operator pair. To be used for register bases of 0x20, 0x40, * Write to an operator pair. To be used for register bases of 0x20, 0x40,
* 0x60, 0x80 and 0xE0. * 0x60, 0x80 and 0xE0.
*/ */
void OPLio::OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2) void OPLio::OPLwriteChannel(uint32_t regbase, uint32_t channel, uint8_t data1, uint8_t data2)
{ {
static const uint op_num[OPL2CHANNELS] = { static const uint32_t op_num[OPL2CHANNELS] = {
0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12}; 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12};
uint which = channel / OPL2CHANNELS; uint32_t which = channel / OPL2CHANNELS;
uint reg = regbase + op_num[channel % OPL2CHANNELS]; uint32_t reg = regbase + op_num[channel % OPL2CHANNELS];
OPLwriteReg (which, reg, data1); OPLwriteReg (which, reg, data1);
OPLwriteReg (which, reg+3, data2); OPLwriteReg (which, reg+3, data2);
} }
@ -95,10 +95,10 @@ void OPLio::OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2
* Write to channel a single value. To be used for register bases of * Write to channel a single value. To be used for register bases of
* 0xA0, 0xB0 and 0xC0. * 0xA0, 0xB0 and 0xC0.
*/ */
void OPLio::OPLwriteValue(uint regbase, uint channel, uchar value) void OPLio::OPLwriteValue(uint32_t regbase, uint32_t channel, uint8_t value)
{ {
uint which = channel / OPL2CHANNELS; uint32_t which = channel / OPL2CHANNELS;
uint reg = regbase + (channel % OPL2CHANNELS); uint32_t reg = regbase + (channel % OPL2CHANNELS);
OPLwriteReg (which, reg, value); OPLwriteReg (which, reg, value);
} }
@ -174,7 +174,7 @@ static WORD frequencies[] =
* That last byte in the table doesn't look right, either, but that's what * That last byte in the table doesn't look right, either, but that's what
* it really is. * it really is.
*/ */
void OPLio::OPLwriteFreq(uint channel, uint note, uint pitch, uint keyon) void OPLio::OPLwriteFreq(uint32_t channel, uint32_t note, uint32_t pitch, uint32_t keyon)
{ {
int octave = 0; int octave = 0;
int j = (note << 5) + pitch; int j = (note << 5) + pitch;
@ -202,9 +202,9 @@ void OPLio::OPLwriteFreq(uint channel, uint note, uint pitch, uint keyon)
/* /*
* Adjust volume value (register 0x40) * Adjust volume value (register 0x40)
*/ */
inline uint OPLio::OPLconvertVolume(uint data, uint volume) inline uint32_t OPLio::OPLconvertVolume(uint32_t data, uint32_t volume)
{ {
static uchar volumetable[128] = { static uint8_t volumetable[128] = {
0, 1, 3, 5, 6, 8, 10, 11, 0, 1, 3, 5, 6, 8, 10, 11,
13, 14, 16, 17, 19, 20, 22, 23, 13, 14, 16, 17, 19, 20, 22, 23,
25, 26, 27, 29, 30, 32, 33, 34, 25, 26, 27, 29, 30, 32, 33, 34,
@ -223,11 +223,11 @@ inline uint OPLio::OPLconvertVolume(uint data, uint volume)
124, 124, 125, 125, 126, 126, 127, 127}; 124, 124, 125, 125, 126, 126, 127, 127};
return 0x3F - (((0x3F - data) * return 0x3F - (((0x3F - data) *
(uint)volumetable[volume <= 127 ? volume : 127]) >> 7); (uint32_t)volumetable[volume <= 127 ? volume : 127]) >> 7);
} }
uint OPLio::OPLpanVolume(uint volume, int pan) uint32_t OPLio::OPLpanVolume(uint32_t volume, int pan)
{ {
if (pan >= 0) if (pan >= 0)
return volume; return volume;
@ -238,7 +238,7 @@ uint OPLio::OPLpanVolume(uint volume, int pan)
/* /*
* Write volume data to a channel * Write volume data to a channel
*/ */
void OPLio::OPLwriteVolume(uint channel, struct OPL2instrument *instr, uint volume) void OPLio::OPLwriteVolume(uint32_t channel, struct OPL2instrument *instr, uint32_t volume)
{ {
if (instr != 0) if (instr != 0)
{ {
@ -251,11 +251,11 @@ void OPLio::OPLwriteVolume(uint channel, struct OPL2instrument *instr, uint volu
/* /*
* Write pan (balance) data to a channel * Write pan (balance) data to a channel
*/ */
void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan) void OPLio::OPLwritePan(uint32_t channel, struct OPL2instrument *instr, int pan)
{ {
if (instr != 0) if (instr != 0)
{ {
uchar bits; uint8_t bits;
if (pan < -36) bits = 0x10; // left if (pan < -36) bits = 0x10; // left
else if (pan > 36) bits = 0x20; // right else if (pan > 36) bits = 0x20; // right
else bits = 0x30; // both else bits = 0x30; // both
@ -292,7 +292,7 @@ void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan)
* data[5] data[12] reg. 0x40 - output level (bottom 6 bits only) * data[5] data[12] reg. 0x40 - output level (bottom 6 bits only)
* data[6] reg. 0xC0 - feedback/AM-FM (both operators) * data[6] reg. 0xC0 - feedback/AM-FM (both operators)
*/ */
void OPLio::OPLwriteInstrument(uint channel, struct OPL2instrument *instr) void OPLio::OPLwriteInstrument(uint32_t channel, struct OPL2instrument *instr)
{ {
OPLwriteChannel(0x40, channel, 0x3F, 0x3F); // no volume OPLwriteChannel(0x40, channel, 0x3F, 0x3F); // no volume
OPLwriteChannel(0x20, channel, instr->trem_vibr_1, instr->trem_vibr_2); OPLwriteChannel(0x20, channel, instr->trem_vibr_1, instr->trem_vibr_2);
@ -307,7 +307,7 @@ void OPLio::OPLwriteInstrument(uint channel, struct OPL2instrument *instr)
*/ */
void OPLio::OPLshutup(void) void OPLio::OPLshutup(void)
{ {
uint i; uint32_t i;
for(i = 0; i < OPLchannels; i++) for(i = 0; i < OPLchannels; i++)
{ {
@ -321,10 +321,10 @@ void OPLio::OPLshutup(void)
/* /*
* Initialize hardware upon startup * Initialize hardware upon startup
*/ */
int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) int OPLio::OPLinit(uint32_t numchips, bool stereo, bool initopl3)
{ {
assert(numchips >= 1 && numchips <= countof(chips)); assert(numchips >= 1 && numchips <= countof(chips));
uint i; uint32_t i;
IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3); IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3);
memset(chips, 0, sizeof(chips)); memset(chips, 0, sizeof(chips));
@ -349,7 +349,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
void OPLio::OPLwriteInitState(bool initopl3) void OPLio::OPLwriteInitState(bool initopl3)
{ {
for (uint i = 0; i < NumChips; ++i) for (uint32_t i = 0; i < NumChips; ++i)
{ {
int chip = i << (int)IsOPL3; int chip = i << (int)IsOPL3;
if (IsOPL3 && initopl3) if (IsOPL3 && initopl3)

View file

@ -289,7 +289,7 @@ FString OPLMIDIDevice::GetStats()
{ {
FString out; FString out;
char star[3] = { TEXTCOLOR_ESCAPE, 'A', '*' }; char star[3] = { TEXTCOLOR_ESCAPE, 'A', '*' };
for (uint i = 0; i < io->OPLchannels; ++i) for (uint32_t i = 0; i < io->OPLchannels; ++i)
{ {
if (channels[i].flags & CH_FREE) if (channels[i].flags & CH_FREE)
{ {

View file

@ -336,7 +336,7 @@ DiskWriterIO::~DiskWriterIO()
// //
//========================================================================== //==========================================================================
int DiskWriterIO::OPLinit(uint numchips, bool, bool initopl3) int DiskWriterIO::OPLinit(uint32_t numchips, bool, bool initopl3)
{ {
FILE *file = fopen(Filename, "wb"); FILE *file = fopen(Filename, "wb");
if (file == NULL) if (file == NULL)

View file

@ -76,7 +76,7 @@ Voice-mail (Czech language only, not recommended; weekends only):
#define __MUSLIB_H_ #define __MUSLIB_H_
#ifndef __DEFTYPES_H_ #ifndef __DEFTYPES_H_
#include "deftypes.h" #include "doomtype.h"
#endif #endif
class FileReader; class FileReader;
@ -119,7 +119,7 @@ struct OPL2instrument {
/*0B*/ BYTE scale_2; /* OP 2: key scale level */ /*0B*/ BYTE scale_2; /* OP 2: key scale level */
/*0C*/ BYTE level_2; /* OP 2: output level */ /*0C*/ BYTE level_2; /* OP 2: output level */
/*0D*/ BYTE unused; /*0D*/ BYTE unused;
/*0E*/ sshort basenote; /* base note offset */ /*0E*/ int16_t basenote; /* base note offset */
}; };
/* OP2 instrument file entry */ /* OP2 instrument file entry */
@ -152,41 +152,41 @@ struct OP2instrEntry {
#define CH_FREE 0x80 #define CH_FREE 0x80
struct OPLdata { struct OPLdata {
uint channelInstr[CHANNELS]; // instrument # uint32_t channelInstr[CHANNELS]; // instrument #
uchar channelVolume[CHANNELS]; // volume uint8_t channelVolume[CHANNELS]; // volume
uchar channelLastVolume[CHANNELS]; // last volume uint8_t channelLastVolume[CHANNELS]; // last volume
schar channelPan[CHANNELS]; // pan, 0=normal int8_t channelPan[CHANNELS]; // pan, 0=normal
schar channelPitch[CHANNELS]; // pitch wheel, 64=normal int8_t channelPitch[CHANNELS]; // pitch wheel, 64=normal
uchar channelSustain[CHANNELS]; // sustain pedal value uint8_t channelSustain[CHANNELS]; // sustain pedal value
uchar channelModulation[CHANNELS]; // modulation pot value uint8_t channelModulation[CHANNELS]; // modulation pot value
ushort channelPitchSens[CHANNELS]; // pitch sensitivity, 2=default uint16_t channelPitchSens[CHANNELS]; // pitch sensitivity, 2=default
ushort channelRPN[CHANNELS]; // RPN number for data entry uint16_t channelRPN[CHANNELS]; // RPN number for data entry
uchar channelExpression[CHANNELS]; // expression uint8_t channelExpression[CHANNELS]; // expression
}; };
struct OPLio { struct OPLio {
virtual ~OPLio(); virtual ~OPLio();
void OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2); void OPLwriteChannel(uint32_t regbase, uint32_t channel, uint8_t data1, uint8_t data2);
void OPLwriteValue(uint regbase, uint channel, uchar value); void OPLwriteValue(uint32_t regbase, uint32_t channel, uint8_t value);
void OPLwriteFreq(uint channel, uint freq, uint octave, uint keyon); void OPLwriteFreq(uint32_t channel, uint32_t freq, uint32_t octave, uint32_t keyon);
uint OPLconvertVolume(uint data, uint volume); uint32_t OPLconvertVolume(uint32_t data, uint32_t volume);
uint OPLpanVolume(uint volume, int pan); uint32_t OPLpanVolume(uint32_t volume, int pan);
void OPLwriteVolume(uint channel, struct OPL2instrument *instr, uint volume); void OPLwriteVolume(uint32_t channel, struct OPL2instrument *instr, uint32_t volume);
void OPLwritePan(uint channel, struct OPL2instrument *instr, int pan); void OPLwritePan(uint32_t channel, struct OPL2instrument *instr, int pan);
void OPLwriteInstrument(uint channel, struct OPL2instrument *instr); void OPLwriteInstrument(uint32_t channel, struct OPL2instrument *instr);
void OPLshutup(void); void OPLshutup(void);
void OPLwriteInitState(bool initopl3); void OPLwriteInitState(bool initopl3);
virtual int OPLinit(uint numchips, bool stereo=false, bool initopl3=false); virtual int OPLinit(uint32_t numchips, bool stereo=false, bool initopl3=false);
virtual void OPLdeinit(void); virtual void OPLdeinit(void);
virtual void OPLwriteReg(int which, uint reg, uchar data); virtual void OPLwriteReg(int which, uint32_t reg, uint8_t data);
virtual void SetClockRate(double samples_per_tick); virtual void SetClockRate(double samples_per_tick);
virtual void WriteDelay(int ticks); virtual void WriteDelay(int ticks);
class OPLEmul *chips[MAXOPL2CHIPS]; class OPLEmul *chips[MAXOPL2CHIPS];
uint OPLchannels; uint32_t OPLchannels;
uint NumChips; uint32_t NumChips;
bool IsOPL3; bool IsOPL3;
}; };
@ -195,7 +195,7 @@ struct DiskWriterIO : public OPLio
DiskWriterIO(const char *filename); DiskWriterIO(const char *filename);
~DiskWriterIO(); ~DiskWriterIO();
int OPLinit(uint numchips, bool notused, bool initopl3); int OPLinit(uint32_t numchips, bool notused, bool initopl3);
void SetClockRate(double samples_per_tick); void SetClockRate(double samples_per_tick);
void WriteDelay(int ticks); void WriteDelay(int ticks);
@ -214,14 +214,14 @@ struct musicBlock {
struct OP2instrEntry *OPLinstruments; struct OP2instrEntry *OPLinstruments;
ulong MLtime; uint32_t MLtime;
void OPLplayNote(uint channel, uchar note, int volume); void OPLplayNote(uint32_t channel, uint8_t note, int volume);
void OPLreleaseNote(uint channel, uchar note); void OPLreleaseNote(uint32_t channel, uint8_t note);
void OPLpitchWheel(uint channel, int pitch); void OPLpitchWheel(uint32_t channel, int pitch);
void OPLchangeControl(uint channel, uchar controller, int value); void OPLchangeControl(uint32_t channel, uint8_t controller, int value);
void OPLprogramChange(uint channel, int value); void OPLprogramChange(uint32_t channel, int value);
void OPLresetControllers(uint channel, int vol); void OPLresetControllers(uint32_t channel, int vol);
void OPLplayMusic(int vol); void OPLplayMusic(int vol);
void OPLstopMusic(); void OPLstopMusic();
@ -230,27 +230,27 @@ struct musicBlock {
protected: protected:
/* OPL channel (voice) data */ /* OPL channel (voice) data */
struct channelEntry { struct channelEntry {
uchar channel; /* MUS channel number */ uint8_t channel; /* MUS channel number */
uchar note; /* note number */ uint8_t note; /* note number */
uchar flags; /* see CH_xxx below */ uint8_t flags; /* see CH_xxx below */
uchar realnote; /* adjusted note number */ uint8_t realnote; /* adjusted note number */
schar finetune; /* frequency fine-tune */ int8_t finetune; /* frequency fine-tune */
sint pitch; /* pitch-wheel value */ int pitch; /* pitch-wheel value */
uint volume; /* note volume */ uint32_t volume; /* note volume */
uint realvolume; /* adjusted note volume */ uint32_t realvolume; /* adjusted note volume */
struct OPL2instrument *instr; /* current instrument */ struct OPL2instrument *instr; /* current instrument */
ulong time; /* note start time */ uint32_t time; /* note start time */
} channels[MAXCHANNELS]; } channels[MAXCHANNELS];
void writeFrequency(uint slot, uint note, int pitch, uint keyOn); void writeFrequency(uint32_t slot, uint32_t note, int pitch, uint32_t keyOn);
void writeModulation(uint slot, struct OPL2instrument *instr, int state); void writeModulation(uint32_t slot, struct OPL2instrument *instr, int state);
uint calcVolume(uint channelVolume, uint channelExpression, uint noteVolume); uint32_t calcVolume(uint32_t channelVolume, uint32_t channelExpression, uint32_t noteVolume);
int occupyChannel(uint slot, uint channel, int occupyChannel(uint32_t slot, uint32_t channel,
int note, int volume, struct OP2instrEntry *instrument, uchar secondary); int note, int volume, struct OP2instrEntry *instrument, uint8_t secondary);
int releaseChannel(uint slot, uint killed); int releaseChannel(uint32_t slot, uint32_t killed);
int releaseSustain(uint channel); int releaseSustain(uint32_t channel);
int findFreeChannel(uint flag, uint channel, uchar note); int findFreeChannel(uint32_t flag, uint32_t channel, uint8_t note);
struct OP2instrEntry *getInstrument(uint channel, uchar note); struct OP2instrEntry *getInstrument(uint32_t channel, uint8_t note);
friend class Stat_opl; friend class Stat_opl;

View file

@ -856,6 +856,7 @@ void P_Spawn3DFloors (void)
{ {
case ExtraFloor_LightOnly: case ExtraFloor_LightOnly:
if (line.args[1] < 0 || line.args[1] > 2) line.args[1] = 0; if (line.args[1] < 0 || line.args[1] > 2) line.args[1] = 0;
if (line.args[0] != 0)
P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0); P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0);
break; break;
@ -875,6 +876,7 @@ void P_Spawn3DFloors (void)
line.args[4]=0; line.args[4]=0;
} }
} }
if (line.args[0] != 0)
P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]); P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]);
break; break;

View file

@ -1097,7 +1097,7 @@ public:
{ {
ld->alpha = 0.75; ld->alpha = 0.75;
} }
if (strifetrans2 && ld->alpha == OPAQUE) if (strifetrans2 && ld->alpha == 1.)
{ {
ld->alpha = 0.25; ld->alpha = 0.25;
} }

View file

@ -6368,11 +6368,8 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
//========================================================================== //==========================================================================
FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos) FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos)
: FxExpression(EFX_GlobalVariable, pos) : FxMemberBase(EFX_GlobalVariable, mem, pos)
{ {
membervar = mem;
AddressRequested = false;
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
} }
//========================================================================== //==========================================================================
@ -6548,11 +6545,8 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build)
//========================================================================== //==========================================================================
FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition &pos) FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition &pos)
: FxExpression(EFX_StackVariable, pos) : FxMemberBase(EFX_StackVariable, new PField(NAME_None, type, 0, offset), pos)
{ {
membervar = new PField(NAME_None, type, 0, offset);
AddressRequested = false;
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
} }
//========================================================================== //==========================================================================
@ -6651,14 +6645,16 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build)
// //
// //
//========================================================================== //==========================================================================
FxMemberBase::FxMemberBase(EFxType type, PField *f, const FScriptPosition &p)
:FxExpression(type, p), membervar(f)
{
}
FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos) FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
: FxExpression(EFX_StructMember, pos) : FxMemberBase(EFX_StructMember, mem, pos)
{ {
classx = x; classx = x;
membervar = mem;
AddressRequested = false;
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
} }
//========================================================================== //==========================================================================
@ -6730,35 +6726,13 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct)))
{ {
// if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. // if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember) if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember || classx->ExprType == EFX_GlobalVariable || classx->ExprType == EFX_StackVariable)
{ {
auto parentfield = static_cast<FxStructMember *>(classx)->membervar; auto parentfield = static_cast<FxMemberBase *>(classx)->membervar;
// PFields are garbage collected so this will be automatically taken care of later. // PFields are garbage collected so this will be automatically taken care of later.
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
newfield->BitValue = membervar->BitValue; newfield->BitValue = membervar->BitValue;
static_cast<FxStructMember *>(classx)->membervar = newfield; static_cast<FxMemberBase *>(classx)->membervar = newfield;
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = classx->Resolve(ctx);
classx = nullptr;
return x;
}
else if (classx->ExprType == EFX_GlobalVariable)
{
auto parentfield = static_cast<FxGlobalVariable *>(classx)->membervar;
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
newfield->BitValue = membervar->BitValue;
static_cast<FxGlobalVariable *>(classx)->membervar = newfield;
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = classx->Resolve(ctx);
classx = nullptr;
return x;
}
else if (classx->ExprType == EFX_StackVariable)
{
auto parentfield = static_cast<FxStackVariable *>(classx)->membervar;
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
newfield->BitValue = membervar->BitValue;
static_cast<FxStackVariable *>(classx)->ReplaceField(newfield);
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = classx->Resolve(ctx); auto x = classx->Resolve(ctx);
classx = nullptr; classx = nullptr;
@ -6946,7 +6920,18 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
return nullptr; return nullptr;
} }
PArray *arraytype = dyn_cast<PArray>(Array->ValueType); PArray *arraytype = nullptr;
PType *elementtype = nullptr;
if (Array->IsDynamicArray())
{
PDynArray *darraytype = static_cast<PDynArray*>(Array->ValueType);
elementtype = darraytype->ElementType;
Array->ValueType = NewPointer(NewResizableArray(elementtype)); // change type so that this can use the code for resizable arrays unchanged.
arrayispointer = true;
}
else
{
arraytype = dyn_cast<PArray>(Array->ValueType);
if (arraytype == nullptr) if (arraytype == nullptr)
{ {
// Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this. // Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this.
@ -6960,19 +6945,16 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
arraytype = static_cast<PArray*>(ptype->PointedType); arraytype = static_cast<PArray*>(ptype->PointedType);
arrayispointer = true; arrayispointer = true;
} }
elementtype = arraytype->ElementType;
}
if (Array->IsResizableArray()) if (Array->IsResizableArray())
{ {
// if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable)
{ {
auto parentfield = static_cast<FxStructMember *>(Array)->membervar; auto parentfield = static_cast<FxMemberBase *>(Array)->membervar;
SizeAddr = parentfield->Offset + parentfield->Type->Align; SizeAddr = parentfield->Offset + sizeof(void*);
}
else if (Array->ExprType == EFX_GlobalVariable)
{
auto parentfield = static_cast<FxGlobalVariable *>(Array)->membervar;
SizeAddr = parentfield->Offset + parentfield->Type->Align;
} }
else else
{ {
@ -6981,54 +6963,32 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
return nullptr; return nullptr;
} }
} }
else if (index->isConstant()) // constant indices can only be resolved at compile time for statically sized arrays.
else if (index->isConstant() && arraytype != nullptr && !arrayispointer)
{ {
unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt(); unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
if (indexval >= arraytype->ElementCount && !Array->IsResizableArray()) if (indexval >= arraytype->ElementCount)
{ {
ScriptPosition.Message(MSG_ERROR, "Array index out of bounds"); ScriptPosition.Message(MSG_ERROR, "Array index out of bounds");
delete this; delete this;
return nullptr; return nullptr;
} }
if (!arrayispointer)
{
// if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable)
{ {
auto parentfield = static_cast<FxStructMember *>(Array)->membervar; auto parentfield = static_cast<FxMemberBase *>(Array)->membervar;
// PFields are garbage collected so this will be automatically taken care of later. // PFields are garbage collected so this will be automatically taken care of later.
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
static_cast<FxStructMember *>(Array)->membervar = newfield; static_cast<FxMemberBase *>(Array)->membervar = newfield;
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = Array->Resolve(ctx); auto x = Array->Resolve(ctx);
Array = nullptr; Array = nullptr;
return x; return x;
} }
else if (Array->ExprType == EFX_GlobalVariable)
{
auto parentfield = static_cast<FxGlobalVariable *>(Array)->membervar;
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
static_cast<FxGlobalVariable *>(Array)->membervar = newfield;
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = Array->Resolve(ctx);
Array = nullptr;
return x;
}
else if (Array->ExprType == EFX_StackVariable)
{
auto parentfield = static_cast<FxStackVariable *>(Array)->membervar;
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
static_cast<FxStackVariable *>(Array)->ReplaceField(newfield);
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
auto x = Array->Resolve(ctx);
Array = nullptr;
return x;
}
}
} }
ValueType = arraytype->ElementType; ValueType = elementtype;
if (!Array->RequestAddress(ctx, &AddressWritable)) if (!Array->RequestAddress(ctx, &AddressWritable))
{ {
ScriptPosition.Message(MSG_ERROR, "Unable to dereference array."); ScriptPosition.Message(MSG_ERROR, "Unable to dereference array.");
@ -7067,17 +7027,8 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0)); build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0));
auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr); auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr);
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) static_cast<FxMemberBase *>(Array)->membervar = f;
{ static_cast<FxMemberBase *>(Array)->AddressRequested = false;
static_cast<FxStructMember *>(Array)->membervar = f;
static_cast<FxStructMember *>(Array)->AddressRequested = false;
}
else if (Array->ExprType == EFX_GlobalVariable)
{
static_cast<FxGlobalVariable *>(Array)->membervar = f;
static_cast<FxGlobalVariable *>(Array)->AddressRequested = false;
}
Array->ValueType = TypeUInt32; Array->ValueType = TypeUInt32;
bound = Array->Emit(build); bound = Array->Emit(build);
} }
@ -7804,6 +7755,70 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
// same for String methods. It also uses a hidden struct type to define them. // same for String methods. It also uses a hidden struct type to define them.
Self->ValueType = TypeStringStruct; Self->ValueType = TypeStringStruct;
} }
else if (Self->IsDynamicArray())
{
if (MethodName == NAME_Size)
{
FxExpression *x = new FxMemberIdentifier(Self, NAME_Size, ScriptPosition); // todo: obfuscate the name to prevent direct access.
Self = nullptr;
delete this;
return x->Resolve(ctx);
}
else
{
auto elementType = static_cast<PDynArray*>(Self->ValueType)->ElementType;
Self->ValueType = static_cast<PDynArray*>(Self->ValueType)->BackingType;
// this requires some added type checks for the passed types.
for (auto &a : ArgList)
{
a = a->Resolve(ctx);
if (a == nullptr)
{
delete this;
return nullptr;
}
if (a->IsDynamicArray())
{
// Copy and Move must turn their parameter into a pointer to the backing struct type.
auto backingtype = static_cast<PDynArray*>(a->ValueType)->BackingType;
if (elementType != static_cast<PDynArray*>(a->ValueType)->ElementType)
{
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument");
delete this;
return nullptr;
}
bool writable;
if (!a->RequestAddress(ctx, &writable))
{
ScriptPosition.Message(MSG_ERROR, "Unable to dereference array variable");
delete this;
return nullptr;
}
a->ValueType = NewPointer(backingtype);
// Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.)
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable)
{
auto member = static_cast<FxMemberBase*>(Self);
auto newfield = new PField(NAME_None, backingtype, 0, member->membervar->Offset);
member->membervar = newfield;
}
}
else if (a->IsPointer() && Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
{
// the only case which must be checked up front is for pointer arrays receiving a new element.
// Since there is only one native backing class it uses a neutral void pointer as its argument,
// meaning that FxMemberFunctionCall is unable to do a proper check. So we have to do it here.
if (a->ValueType != elementType)
{
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument. Got %s, expected %s", a->ValueType->DescriptiveName(), elementType->DescriptiveName());
delete this;
return nullptr;
}
}
}
}
}
else if (Self->IsArray()) else if (Self->IsArray())
{ {
if (MethodName == NAME_Size) if (MethodName == NAME_Size)
@ -7826,19 +7841,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
else else
{ {
// Resizable arrays can only be defined in C code and they can only exist in pointer form to reduce their impact on the code generator. // Resizable arrays can only be defined in C code and they can only exist in pointer form to reduce their impact on the code generator.
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember) if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_GlobalVariable)
{ {
auto member = static_cast<FxStructMember*>(Self); auto member = static_cast<FxMemberBase*>(Self);
auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer.
member->membervar = newfield;
Self = nullptr;
delete this;
member->ValueType = TypeUInt32;
return member;
}
else if (Self->ExprType == EFX_GlobalVariable)
{
auto member = static_cast<FxGlobalVariable*>(Self);
auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer. auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer.
member->membervar = newfield; member->membervar = newfield;
Self = nullptr; Self = nullptr;

View file

@ -333,6 +333,7 @@ public:
bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); }
bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); } bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); }
bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form. bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form.
bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); }
virtual ExpEmit Emit(VMFunctionBuilder *build); virtual ExpEmit Emit(VMFunctionBuilder *build);
void EmitStatement(VMFunctionBuilder *build); void EmitStatement(VMFunctionBuilder *build);
@ -1313,19 +1314,30 @@ public:
}; };
//==========================================================================
//
// FxMemberBase
//
//==========================================================================
class FxMemberBase : public FxExpression
{
public:
PField *membervar;
bool AddressRequested = false;
bool AddressWritable = true;
FxMemberBase(EFxType type, PField *f, const FScriptPosition &p);
};
//========================================================================== //==========================================================================
// //
// FxGlobalVariaböe // FxGlobalVariaböe
// //
//========================================================================== //==========================================================================
class FxGlobalVariable : public FxExpression class FxGlobalVariable : public FxMemberBase
{ {
public: public:
PField *membervar;
bool AddressRequested;
bool AddressWritable;
FxGlobalVariable(PField*, const FScriptPosition&); FxGlobalVariable(PField*, const FScriptPosition&);
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
bool RequestAddress(FCompileContext &ctx, bool *writable); bool RequestAddress(FCompileContext &ctx, bool *writable);
@ -1342,19 +1354,17 @@ public:
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
//========================================================================== //==========================================================================
// //
// FxClassMember // FxClassMember
// //
//========================================================================== //==========================================================================
class FxStructMember : public FxExpression class FxStructMember : public FxMemberBase
{ {
public: public:
FxExpression *classx; FxExpression *classx;
PField *membervar;
bool AddressRequested;
bool AddressWritable;
FxStructMember(FxExpression*, PField*, const FScriptPosition&); FxStructMember(FxExpression*, PField*, const FScriptPosition&);
~FxStructMember(); ~FxStructMember();
@ -1402,13 +1412,9 @@ public:
// //
//========================================================================== //==========================================================================
class FxStackVariable : public FxExpression class FxStackVariable : public FxMemberBase
{ {
public: public:
PField *membervar;
bool AddressRequested;
bool AddressWritable;
FxStackVariable(PType *type, int offset, const FScriptPosition&); FxStackVariable(PType *type, int offset, const FScriptPosition&);
~FxStackVariable(); ~FxStackVariable();
void ReplaceField(PField *newfield); void ReplaceField(PField *newfield);

View file

@ -1137,3 +1137,50 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat)
(*self) += s; (*self) += s;
return 0; return 0;
} }
DEFINE_ACTION_FUNCTION(FStringStruct, Mid)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_INT(ipos);
PARAM_INT(ilen);
// validate. we don't want to crash if someone passes negative values.
// with size_t it's handled naturally I think, as it's unsigned, but not in ZScript.
if (ipos < 0) ipos = 0;
if (ilen < 0) ilen = 0;
// convert to size_t to prevent overflows here
size_t slen = self->Len();
size_t pos = (size_t)ipos;
size_t len = (size_t)ilen;
if (pos > slen) pos = slen - 1;
if (pos + len > slen)
len = slen - pos;
FString s = self->Mid(pos, len);
ACTION_RETURN_STRING(s);
}
DEFINE_ACTION_FUNCTION(FStringStruct, Len)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
ACTION_RETURN_INT(self->Len());
}
// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int.
DEFINE_ACTION_FUNCTION(FStringStruct, CharAt)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_INT(pos);
int slen = self->Len();
if (pos < 0 || pos >= slen)
ACTION_RETURN_STRING("");
ACTION_RETURN_STRING(FString((*self)[pos]));
}
DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_INT(pos);
int slen = self->Len();
if (pos < 0 || pos >= slen)
ACTION_RETURN_INT(0);
ACTION_RETURN_INT((*self)[pos]);
}

View file

@ -1358,9 +1358,16 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
case AST_DynArrayType: case AST_DynArrayType:
if (allowarraytypes) if (allowarraytypes)
{ {
Error(field, "%s: Dynamic array types not implemented yet", name.GetChars());
auto atype = static_cast<ZCC_DynArrayType *>(ztype); auto atype = static_cast<ZCC_DynArrayType *>(ztype);
retval = NewDynArray(DetermineType(outertype, field, name, atype->ElementType, false, false)); auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true);
if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1)
{
Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName());
}
else
{
retval = NewDynArray(ftype);
}
break; break;
} }
break; break;

View file

@ -417,9 +417,14 @@ enum EPickStart
// Although String is a builtin type, this is a convenient way to attach methods to it. // Although String is a builtin type, this is a convenient way to attach methods to it.
struct StringStruct native struct StringStruct native
{ {
native void Replace(String pattern, String replacement);
native static vararg String Format(String fmt, ...); native static vararg String Format(String fmt, ...);
native vararg void AppendFormat(String fmt, ...); native vararg void AppendFormat(String fmt, ...);
native void Replace(String pattern, String replacement);
native String Mid(int pos = 0, int len = 2147483647);
native int Len();
native String CharAt(int pos);
native int CharCodeAt(int pos);
} }
class Floor : Thinker native class Floor : Thinker native

View file

@ -156,7 +156,7 @@ class FastProjectile : Actor
ExplodeMissile (NULL, NULL); ExplodeMissile (NULL, NULL);
return; return;
} }
if (frac != (0, 0, 0) && ripcount <= 0) if (!(frac.xy ~== (0, 0)) && ripcount <= 0)
{ {
ripcount = count >> 3; ripcount = count >> 3;