Subversion Repositories eduke32

Rev

Rev 8734 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 8734 Rev 8736
1
//-------------------------------------------------------------------------
1
//-------------------------------------------------------------------------
2
/*
2
/*
3
Copyright (C) 2016 EDuke32 developers and contributors
3
Copyright (C) 2016 EDuke32 developers and contributors
4

4

5
This file is part of EDuke32.
5
This file is part of EDuke32.
6

6

7
EDuke32 is free software; you can redistribute it and/or
7
EDuke32 is free software; you can redistribute it and/or
8
modify it under the terms of the GNU General Public License version 2
8
modify it under the terms of the GNU General Public License version 2
9
as published by the Free Software Foundation.
9
as published by the Free Software Foundation.
10

10

11
This program is distributed in the hope that it will be useful,
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14

14

15
See the GNU General Public License for more details.
15
See the GNU General Public License for more details.
16

16

17
You should have received a copy of the GNU General Public License
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
*/
20
*/
21
//-------------------------------------------------------------------------
21
//-------------------------------------------------------------------------
22
22
23
#include "anim.h"
23
#include "anim.h"
24
#include "cmdline.h"
24
#include "cmdline.h"
25
#include "colmatch.h"
25
#include "colmatch.h"
26
#include "communityapi.h"
26
#include "communityapi.h"
27
#include "compat.h"
27
#include "compat.h"
28
#include "duke3d.h"
28
#include "duke3d.h"
29
#include "gamestructures.h"
29
#include "gamestructures.h"
30
#include "input.h"
30
#include "input.h"
31
#include "menus.h"
31
#include "menus.h"
32
#include "osdcmds.h"
32
#include "osdcmds.h"
33
#include "savegame.h"
33
#include "savegame.h"
34
#include "scriplib.h"
34
#include "scriplib.h"
35
35
36
#ifdef LUNATIC
36
#ifdef LUNATIC
37
# include "lunatic_game.h"
37
# include "lunatic_game.h"
38
#endif
38
#endif
39
39
40
#include "vfs.h"
40
#include "vfs.h"
41
41
42
#if KRANDDEBUG
42
#if KRANDDEBUG
43
# define GAMEEXEC_INLINE
43
# define GAMEEXEC_INLINE
44
# define GAMEEXEC_STATIC
44
# define GAMEEXEC_STATIC
45
#else
45
#else
46
# define GAMEEXEC_INLINE inline
46
# define GAMEEXEC_INLINE inline
47
# define GAMEEXEC_STATIC static
47
# define GAMEEXEC_STATIC static
48
#endif
48
#endif
49
49
50
vmstate_t vm;
50
vmstate_t vm;
51
51
52
#if !defined LUNATIC
52
#if !defined LUNATIC
53
int32_t g_tw;
53
int32_t g_tw;
54
int32_t g_currentEvent = -1;
54
int32_t g_currentEvent = -1;
55
55
56
intptr_t const *insptr;
56
intptr_t const *insptr;
57
57
58
int32_t g_returnVarID    = -1;  // var ID of "RETURN"
58
int32_t g_returnVarID    = -1;  // var ID of "RETURN"
59
int32_t g_weaponVarID    = -1;  // var ID of "WEAPON"
59
int32_t g_weaponVarID    = -1;  // var ID of "WEAPON"
60
int32_t g_worksLikeVarID = -1;  // var ID of "WORKSLIKE"
60
int32_t g_worksLikeVarID = -1;  // var ID of "WORKSLIKE"
61
int32_t g_zRangeVarID    = -1;  // var ID of "ZRANGE"
61
int32_t g_zRangeVarID    = -1;  // var ID of "ZRANGE"
62
int32_t g_angRangeVarID  = -1;  // var ID of "ANGRANGE"
62
int32_t g_angRangeVarID  = -1;  // var ID of "ANGRANGE"
63
int32_t g_aimAngleVarID  = -1;  // var ID of "AUTOAIMANGLE"
63
int32_t g_aimAngleVarID  = -1;  // var ID of "AUTOAIMANGLE"
64
int32_t g_lotagVarID     = -1;  // var ID of "LOTAG"
64
int32_t g_lotagVarID     = -1;  // var ID of "LOTAG"
65
int32_t g_hitagVarID     = -1;  // var ID of "HITAG"
65
int32_t g_hitagVarID     = -1;  // var ID of "HITAG"
66
int32_t g_textureVarID   = -1;  // var ID of "TEXTURE"
66
int32_t g_textureVarID   = -1;  // var ID of "TEXTURE"
67
int32_t g_thisActorVarID = -1;  // var ID of "THISACTOR"
67
int32_t g_thisActorVarID = -1;  // var ID of "THISACTOR"
68
int32_t g_structVarIDs   = -1;
68
int32_t g_structVarIDs   = -1;
69
69
70
// for timing events and actors
70
// for timing events and actors
71
uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
71
uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
72
double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES], g_actorMinMs[MAXTILES], g_actorMaxMs[MAXTILES];
72
double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES], g_actorMinMs[MAXTILES], g_actorMaxMs[MAXTILES];
73
73
74
GAMEEXEC_STATIC void VM_Execute(int const loop = false);
74
GAMEEXEC_STATIC void VM_Execute(int const loop = false);
75
75
76
#endif
76
#endif
77
77
78
#if !defined LUNATIC
78
#if !defined LUNATIC
79
void VM_ScriptInfo(intptr_t const * const ptr, int const range)
79
void VM_ScriptInfo(intptr_t const * const ptr, int const range)
80
{
80
{
81
    if (!apScript || !ptr || g_currentEvent == -1)
81
    if (!apScript || !ptr || g_currentEvent == -1)
82
        return;
82
        return;
83
83
84
    initprintf("\n");
84
    initprintf("\n");
85
85
86
    for (auto pScript = max<intptr_t const *>(ptr - (range >> 1), apScript),
86
    for (auto pScript = max<intptr_t const *>(ptr - (range >> 1), apScript),
87
                p_end   = min<intptr_t const *>(ptr + (range >> 1), apScript + g_scriptSize);
87
                p_end   = min<intptr_t const *>(ptr + (range >> 1), apScript + g_scriptSize);
88
            pScript < p_end;
88
            pScript < p_end;
89
            ++pScript)
89
            ++pScript)
90
    {
90
    {
91
        initprintf("%5d: %3d: ", (int32_t)(pScript - apScript), (int32_t)(pScript - ptr));
91
        initprintf("%5d: %3d: ", (int32_t)(pScript - apScript), (int32_t)(pScript - ptr));
92
92
93
        auto &v = *pScript;
93
        auto &v = *pScript;
94
        int const lineNum = VM_DECODE_LINE_NUMBER(v);
94
        int const lineNum = VM_DECODE_LINE_NUMBER(v);
95
        int const vmInst  = VM_DECODE_INST(v);
95
        int const vmInst  = VM_DECODE_INST(v);
96
96
97
        if (lineNum && lineNum != VM_IFELSE_MAGIC && vmInst < CON_OPCODE_END)
97
        if (lineNum && lineNum != VM_IFELSE_MAGIC && vmInst < CON_OPCODE_END)
98
            initprintf("%5d %s (%d)\n", lineNum, VM_GetKeywordForID(vmInst), vmInst);
98
            initprintf("%5d %s (%d)\n", lineNum, VM_GetKeywordForID(vmInst), vmInst);
99
        else
99
        else
100
            initprintf("%d\n", (int32_t)*pScript);
100
            initprintf("%d\n", (int32_t)*pScript);
101
    }
101
    }
102
102
103
    initprintf("\n");
103
    initprintf("\n");
104
104
105
    if (ptr == insptr)
105
    if (ptr == insptr)
106
    {
106
    {
107
        if (vm.pUSprite)
107
        if (vm.pUSprite)
108
            initprintf("current actor: %d (%d)\n", vm.spriteNum, vm.pUSprite->picnum);
108
            initprintf("current actor: %d (%d)\n", vm.spriteNum, vm.pUSprite->picnum);
109
109
110
        initprintf("g_errorLineNum: %d, g_tw: %d\n", VM_DECODE_LINE_NUMBER(g_tw), VM_DECODE_INST(g_tw));
110
        initprintf("g_errorLineNum: %d, g_tw: %d\n", VM_DECODE_LINE_NUMBER(g_tw), VM_DECODE_INST(g_tw));
111
    }
111
    }
112
}
112
}
113
#endif
113
#endif
114
114
115
static void VM_DeleteSprite(int const spriteNum, int const playerNum)
115
static void VM_DeleteSprite(int const spriteNum, int const playerNum)
116
{
116
{
117
    if (EDUKE32_PREDICT_FALSE((unsigned) spriteNum >= MAXSPRITES))
117
    if (EDUKE32_PREDICT_FALSE((unsigned) spriteNum >= MAXSPRITES))
118
        return;
118
        return;
119
119
120
    // if player was set to squish, first stop that...
120
    // if player was set to squish, first stop that...
121
    if (EDUKE32_PREDICT_FALSE(playerNum >= 0 && g_player[playerNum].ps->actorsqu == spriteNum))
121
    if (EDUKE32_PREDICT_FALSE(playerNum >= 0 && g_player[playerNum].ps->actorsqu == spriteNum))
122
        g_player[playerNum].ps->actorsqu = -1;
122
        g_player[playerNum].ps->actorsqu = -1;
123
123
124
    A_DeleteSprite(spriteNum);
124
    A_DeleteSprite(spriteNum);
125
}
125
}
126
126
127
intptr_t apScriptEvents[MAXEVENTS];
127
intptr_t apScriptEvents[MAXEVENTS];
128
128
129
// May recurse, e.g. through EVENT_XXX -> ... -> EVENT_KILLIT
129
// May recurse, e.g. through EVENT_XXX -> ... -> EVENT_KILLIT
130
#ifdef LUNATIC
130
#ifdef LUNATIC
131
static FORCE_INLINE int32_t VM_EventInlineInternal__(int const &eventNum, int const &spriteNum, int const &playerNum, int const &playerDist, int32_t returnValue)
131
static FORCE_INLINE int32_t VM_EventInlineInternal__(int const &eventNum, int const &spriteNum, int const &playerNum, int const &playerDist, int32_t returnValue)
132
{
132
{
133
    const double t = timerGetHiTicks();
133
    const double t = timerGetHiTicks();
134
    int32_t ret = El_CallEvent(&g_ElState, eventNum, spriteNum, playerNum, playerDist, &returnValue);
134
    int32_t ret = El_CallEvent(&g_ElState, eventNum, spriteNum, playerNum, playerDist, &returnValue);
135
135
136
    // NOTE: the run times are those of the called event plus any events
136
    // NOTE: the run times are those of the called event plus any events
137
    // called by it, *not* "self" time.
137
    // called by it, *not* "self" time.
138
    g_eventTotalMs[eventNum] += timerGetHiTicks()-t;
138
    g_eventTotalMs[eventNum] += timerGetHiTicks()-t;
139
    g_eventCalls[eventNum]++;
139
    g_eventCalls[eventNum]++;
140
140
141
    if (ret == 1)
141
    if (ret == 1)
142
        VM_DeleteSprite(spriteNum, playerNum);
142
        VM_DeleteSprite(spriteNum, playerNum);
143
143
144
    return returnValue;
144
    return returnValue;
145
}
145
}
146
#else
146
#else
147
static uspritetype dummy_sprite;
147
static uspritetype dummy_sprite;
148
static actor_t     dummy_actor;
148
static actor_t     dummy_actor;
149
149
150
static inline void VM_DummySprite(void)
150
static inline void VM_DummySprite(void)
151
{
151
{
152
    vm.pUSprite = &dummy_sprite;
152
    vm.pUSprite = &dummy_sprite;
153
    vm.pActor   = &dummy_actor;
153
    vm.pActor   = &dummy_actor;
154
    vm.pData    = &dummy_actor.t_data[0];
154
    vm.pData    = &dummy_actor.t_data[0];
155
}
155
}
156
156
157
// verification that the event actually exists happens elsewhere
157
// verification that the event actually exists happens elsewhere
158
static FORCE_INLINE int32_t VM_EventInlineInternal__(int const eventNum, int const spriteNum, int const playerNum,
158
static FORCE_INLINE int32_t VM_EventInlineInternal__(int const eventNum, int const spriteNum, int const playerNum,
159
                                                       int const playerDist = -1, int32_t returnValue = 0)
159
                                                       int const playerDist = -1, int32_t returnValue = 0)
160
{
160
{
161
    vmstate_t const newVMstate = { spriteNum, playerNum, playerDist, 0,
161
    vmstate_t const newVMstate = { spriteNum, playerNum, playerDist, 0,
162
                                   &sprite[spriteNum&(MAXSPRITES-1)],
162
                                   &sprite[spriteNum&(MAXSPRITES-1)],
163
                                   &actor[spriteNum&(MAXSPRITES-1)].t_data[0],
163
                                   &actor[spriteNum&(MAXSPRITES-1)].t_data[0],
164
                                   g_player[playerNum&(MAXPLAYERS-1)].ps,
164
                                   g_player[playerNum&(MAXPLAYERS-1)].ps,
165
                                   &actor[spriteNum&(MAXSPRITES-1)] };
165
                                   &actor[spriteNum&(MAXSPRITES-1)] };
166
166
167
    auto &globalReturn = aGameVars[g_returnVarID].global;
167
    auto &globalReturn = aGameVars[g_returnVarID].global;
168
168
169
    struct
169
    struct
170
    {
170
    {
171
        vmstate_t vm;
171
        vmstate_t vm;
172
        intptr_t globalReturn;
172
        intptr_t globalReturn;
173
        int eventNum;
173
        int eventNum;
174
        intptr_t const *insptr;
174
        intptr_t const *insptr;
175
    } const saved = { vm, globalReturn, g_currentEvent, insptr };
175
    } const saved = { vm, globalReturn, g_currentEvent, insptr };
176
176
177
    vm = newVMstate;
177
    vm = newVMstate;
178
    g_currentEvent = eventNum;
178
    g_currentEvent = eventNum;
179
    insptr = apScript + apScriptEvents[eventNum];
179
    insptr = apScript + apScriptEvents[eventNum];
180
    globalReturn = returnValue;
180
    globalReturn = returnValue;
181
181
182
    double const t = timerGetHiTicks();
182
    double const t = timerGetHiTicks();
183
183
184
    if ((unsigned)spriteNum >= MAXSPRITES)
184
    if ((unsigned)spriteNum >= MAXSPRITES)
185
        VM_DummySprite();
185
        VM_DummySprite();
186
186
187
    if ((unsigned)playerNum >= (unsigned)g_mostConcurrentPlayers)
187
    if ((unsigned)playerNum >= (unsigned)g_mostConcurrentPlayers)
188
        vm.pPlayer = g_player[0].ps;
188
        vm.pPlayer = g_player[0].ps;
189
189
190
    VM_Execute(true);
190
    VM_Execute(true);
191
191
192
    if (vm.flags & VM_KILL)
192
    if (vm.flags & VM_KILL)
193
        VM_DeleteSprite(vm.spriteNum, vm.playerNum);
193
        VM_DeleteSprite(vm.spriteNum, vm.playerNum);
194
194
195
    g_eventTotalMs[eventNum] += timerGetHiTicks()-t;
195
    g_eventTotalMs[eventNum] += timerGetHiTicks()-t;
196
    g_eventCalls[eventNum]++;
196
    g_eventCalls[eventNum]++;
197
197
198
    // restoring these needs to happen after VM_DeleteSprite() due to event recursion
198
    // restoring these needs to happen after VM_DeleteSprite() due to event recursion
199
    returnValue = globalReturn;
199
    returnValue = globalReturn;
200
200
201
    vm             = saved.vm;
201
    vm             = saved.vm;
202
    globalReturn   = saved.globalReturn;
202
    globalReturn   = saved.globalReturn;
203
    g_currentEvent = saved.eventNum;
203
    g_currentEvent = saved.eventNum;
204
    insptr         = saved.insptr;
204
    insptr         = saved.insptr;
205
205
206
    return returnValue;
206
    return returnValue;
207
}
207
}
208
#endif
208
#endif
209
209
210
// the idea here is that the compiler inlines the call to VM_EventInlineInternal__() and gives us a set of
210
// the idea here is that the compiler inlines the call to VM_EventInlineInternal__() and gives us a set of
211
// functions which are optimized further based on distance/return having values known at compile time
211
// functions which are optimized further based on distance/return having values known at compile time
212
212
213
int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist, int32_t const nReturn)
213
int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist, int32_t const nReturn)
214
{
214
{
215
    return VM_EventInlineInternal__(nEventID, spriteNum, playerNum, nDist, nReturn);
215
    return VM_EventInlineInternal__(nEventID, spriteNum, playerNum, nDist, nReturn);
216
}
216
}
217
217
218
int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist)
218
int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist)
219
{
219
{
220
    return VM_EventInlineInternal__(nEventID, spriteNum, playerNum, nDist);
220
    return VM_EventInlineInternal__(nEventID, spriteNum, playerNum, nDist);
221
}
221
}
222
222
223
int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum)
223
int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum)
224
{
224
{
225
    return VM_EventInlineInternal__(nEventID, spriteNum, playerNum);
225
    return VM_EventInlineInternal__(nEventID, spriteNum, playerNum);
226
}
226
}
227
227
228
int32_t VM_ExecuteEventWithValue(int const nEventID, int const spriteNum, int const playerNum, int32_t const nReturn)
228
int32_t VM_ExecuteEventWithValue(int const nEventID, int const spriteNum, int const playerNum, int32_t const nReturn)
229
{
229
{
230
    return VM_EventInlineInternal__(nEventID, spriteNum, playerNum, -1, nReturn);
230
    return VM_EventInlineInternal__(nEventID, spriteNum, playerNum, -1, nReturn);
231
}
231
}
232
232
233
233
234
static int VM_CheckSquished(void)
234
static int VM_CheckSquished(void)
235
{
235
{
236
    auto const pSector = (usectorptr_t)&sector[vm.pSprite->sectnum];
236
    auto const pSector = (usectorptr_t)&sector[vm.pSprite->sectnum];
237
237
238
    if (pSector->lotag == ST_23_SWINGING_DOOR || (vm.pSprite->picnum == APLAYER && ud.noclip) ||
238
    if (pSector->lotag == ST_23_SWINGING_DOOR || (vm.pSprite->picnum == APLAYER && ud.noclip) ||
239
        (pSector->lotag == ST_1_ABOVE_WATER && !A_CheckNoSE7Water(vm.pUSprite, vm.pSprite->sectnum, pSector->lotag, NULL)))
239
        (pSector->lotag == ST_1_ABOVE_WATER && !A_CheckNoSE7Water(vm.pUSprite, vm.pSprite->sectnum, pSector->lotag, NULL)))
240
        return 0;
240
        return 0;
241
241
242
    int32_t floorZ = pSector->floorz;
242
    int32_t floorZ = pSector->floorz;
243
    int32_t ceilZ  = pSector->ceilingz;
243
    int32_t ceilZ  = pSector->ceilingz;
244
#ifdef YAX_ENABLE
244
#ifdef YAX_ENABLE
245
    int16_t cb, fb;
245
    int16_t cb, fb;
246
246
247
    yax_getbunches(vm.pSprite->sectnum, &cb, &fb);
247
    yax_getbunches(vm.pSprite->sectnum, &cb, &fb);
248
248
249
    if (cb >= 0 && (pSector->ceilingstat&512)==0)  // if ceiling non-blocking...
249
    if (cb >= 0 && (pSector->ceilingstat&512)==0)  // if ceiling non-blocking...
250
        ceilZ -= ZOFFSET5;  // unconditionally don't squish... yax_getneighborsect is slowish :/
250
        ceilZ -= ZOFFSET5;  // unconditionally don't squish... yax_getneighborsect is slowish :/
251
    if (fb >= 0 && (pSector->floorstat&512)==0)
251
    if (fb >= 0 && (pSector->floorstat&512)==0)
252
        floorZ += ZOFFSET5;
252
        floorZ += ZOFFSET5;
253
#endif
253
#endif
254
254
255
    if (vm.pSprite->pal == 1 ? (floorZ - ceilZ >= ZOFFSET5 || (pSector->lotag & 32768u)) : (floorZ - ceilZ >= ZOFFSET4))
255
    if (vm.pSprite->pal == 1 ? (floorZ - ceilZ >= ZOFFSET5 || (pSector->lotag & 32768u)) : (floorZ - ceilZ >= ZOFFSET4))
256
        return 0;
256
        return 0;
257
257
258
    P_DoQuote(QUOTE_SQUISHED, vm.pPlayer);
258
    P_DoQuote(QUOTE_SQUISHED, vm.pPlayer);
259
259
260
    if (A_CheckEnemySprite(vm.pSprite))
260
    if (A_CheckEnemySprite(vm.pSprite))
261
        vm.pSprite->xvel = 0;
261
        vm.pSprite->xvel = 0;
262
262
263
#ifndef EDUKE32_STANDALONE
263
#ifndef EDUKE32_STANDALONE
264
    if (EDUKE32_PREDICT_FALSE(vm.pSprite->pal == 1)) // frozen
264
    if (EDUKE32_PREDICT_FALSE(vm.pSprite->pal == 1)) // frozen
265
    {
265
    {
266
        vm.pActor->picnum = SHOTSPARK1;
266
        vm.pActor->picnum = SHOTSPARK1;
267
        vm.pActor->extra  = 1;
267
        vm.pActor->extra  = 1;
268
        return 0;
268
        return 0;
269
    }
269
    }
270
#endif
270
#endif
271
271
272
    return 1;
272
    return 1;
273
}
273
}
274
274
275
#if !defined LUNATIC
275
#if !defined LUNATIC
276
GAMEEXEC_STATIC GAMEEXEC_INLINE void P_ForceAngle(DukePlayer_t *pPlayer)
276
GAMEEXEC_STATIC GAMEEXEC_INLINE void P_ForceAngle(DukePlayer_t *pPlayer)
277
{
277
{
278
    int const nAngle = 128-(krand()&255);
278
    int const nAngle = 128-(krand()&255);
279
279
280
    pPlayer->q16horiz           += F16(64);
280
    pPlayer->q16horiz           += F16(64);
281
    pPlayer->return_to_center = 9;
281
    pPlayer->return_to_center = 9;
282
    pPlayer->rotscrnang       = nAngle >> 1;
282
    pPlayer->rotscrnang       = nAngle >> 1;
283
    pPlayer->look_ang         = pPlayer->rotscrnang;
283
    pPlayer->look_ang         = pPlayer->rotscrnang;
284
}
284
}
285
#endif
285
#endif
286
286
287
// wow, this function sucks
287
// wow, this function sucks
288
#ifdef __cplusplus
288
#ifdef __cplusplus
289
extern "C"
289
extern "C"
290
#endif
290
#endif
291
int A_Dodge(spritetype * const);
291
int A_Dodge(spritetype * const);
292
int A_Dodge(spritetype * const pSprite)
292
int A_Dodge(spritetype * const pSprite)
293
{
293
{
294
    if (A_CheckEnemySprite(pSprite) && pSprite->extra <= 0)  // hack
294
    if (A_CheckEnemySprite(pSprite) && pSprite->extra <= 0)  // hack
295
        return 0;
295
        return 0;
296
296
297
    vec2_t const msin = { sintable[(pSprite->ang + 512) & 2047], sintable[pSprite->ang & 2047] };
297
    vec2_t const msin = { sintable[(pSprite->ang + 512) & 2047], sintable[pSprite->ang & 2047] };
298
298
299
    for (native_t nexti, SPRITES_OF_STAT_SAFE(STAT_PROJECTILE, i, nexti)) //weapons list
299
    for (native_t nexti, SPRITES_OF_STAT_SAFE(STAT_PROJECTILE, i, nexti)) //weapons list
300
    {
300
    {
301
        if (OW(i) == i)
301
        if (OW(i) == i)
302
            continue;
302
            continue;
303
303
304
        vec2_t const b = { SX(i) - pSprite->x, SY(i) - pSprite->y };
304
        vec2_t const b = { SX(i) - pSprite->x, SY(i) - pSprite->y };
305
        vec2_t const v = { sintable[(SA(i) + 512) & 2047], sintable[SA(i) & 2047] };
305
        vec2_t const v = { sintable[(SA(i) + 512) & 2047], sintable[SA(i) & 2047] };
306
306
307
        if (((msin.x * b.x) + (msin.y * b.y) >= 0) && ((v.x * b.x) + (v.y * b.y) < 0))
307
        if (((msin.x * b.x) + (msin.y * b.y) >= 0) && ((v.x * b.x) + (v.y * b.y) < 0))
308
        {
308
        {
309
            if (klabs((v.x * b.y) - (v.y * b.x)) < 65536 << 6)
309
            if (klabs((v.x * b.y) - (v.y * b.x)) < 65536 << 6)
310
            {
310
            {
311
                pSprite->ang -= 512+(krand()&1024);
311
                pSprite->ang -= 512+(krand()&1024);
312
                return 1;
312
                return 1;
313
            }
313
            }
314
        }
314
        }
315
    }
315
    }
316
316
317
    return 0;
317
    return 0;
318
}
318
}
319
319
320
int A_GetFurthestAngle(int const spriteNum, int const angDiv)
320
int A_GetFurthestAngle(int const spriteNum, int const angDiv)
321
{
321
{
322
    auto const pSprite = (uspriteptr_t)&sprite[spriteNum];
322
    auto const pSprite = (uspriteptr_t)&sprite[spriteNum];
323
323
324
    if (pSprite->picnum != APLAYER && (AC_COUNT(actor[spriteNum].t_data)&63) > 2)
324
    if (pSprite->picnum != APLAYER && (AC_COUNT(actor[spriteNum].t_data)&63) > 2)
325
        return (pSprite->ang + 1024) & 2047;
325
        return (pSprite->ang + 1024) & 2047;
326
326
327
    int       furthestAngle = 0;
327
    int       furthestAngle = 0;
328
    int const angIncs       = tabledivide32_noinline(2048, angDiv);
328
    int const angIncs       = tabledivide32_noinline(2048, angDiv);
329
    int32_t   greatestDist  = INT32_MIN;
329
    int32_t   greatestDist  = INT32_MIN;
330
    hitdata_t hit;
330
    hitdata_t hit;
331
331
332
    for (native_t j = pSprite->ang; j < (2048 + pSprite->ang); j += angIncs)
332
    for (native_t j = pSprite->ang; j < (2048 + pSprite->ang); j += angIncs)
333
    {
333
    {
334
        vec3_t origin = *(const vec3_t *)pSprite;
334
        vec3_t origin = *(const vec3_t *)pSprite;
335
        origin.z -= ZOFFSET3;
335
        origin.z -= ZOFFSET3;
336
        hitscan(&origin, pSprite->sectnum, sintable[(j + 512) & 2047], sintable[j & 2047], 0, &hit, CLIPMASK1);
336
        hitscan(&origin, pSprite->sectnum, sintable[(j + 512) & 2047], sintable[j & 2047], 0, &hit, CLIPMASK1);
337
337
338
        int const hitDist = klabs(hit.pos.x-pSprite->x) + klabs(hit.pos.y-pSprite->y);
338
        int const hitDist = klabs(hit.pos.x-pSprite->x) + klabs(hit.pos.y-pSprite->y);
339
339
340
        if (hitDist > greatestDist)
340
        if (hitDist > greatestDist)
341
        {
341
        {
342
            greatestDist = hitDist;
342
            greatestDist = hitDist;
343
            furthestAngle = j;
343
            furthestAngle = j;
344
        }
344
        }
345
    }
345
    }
346
346
347
    return furthestAngle & 2047;
347
    return furthestAngle & 2047;
348
}
348
}
349
349
350
int A_FurthestVisiblePoint(int const spriteNum, uspriteptr_t const ts, vec2_t * const vect)
350
int A_FurthestVisiblePoint(int const spriteNum, uspriteptr_t const ts, vec2_t * const vect)
351
{
351
{
352
    if (AC_COUNT(actor[spriteNum].t_data)&63)
352
    if (AC_COUNT(actor[spriteNum].t_data)&63)
353
        return -1;
353
        return -1;
354
354
355
    auto const pnSprite = (uspriteptr_t)&sprite[spriteNum];
355
    auto const pnSprite = (uspriteptr_t)&sprite[spriteNum];
356
356
357
    hitdata_t hit;
357
    hitdata_t hit;
358
    int const angincs = 128;
358
    int const angincs = 128;
359
//    ((!g_netServer && ud.multimode < 2) && ud.player_skill < 3) ? 2048 / 2 : tabledivide32_noinline(2048, 1 + (krand() & 1));
359
//    ((!g_netServer && ud.multimode < 2) && ud.player_skill < 3) ? 2048 / 2 : tabledivide32_noinline(2048, 1 + (krand() & 1));
360
360
361
    for (native_t j = ts->ang; j < (2048 + ts->ang); j += (angincs /*-(krand()&511)*/))
361
    for (native_t j = ts->ang; j < (2048 + ts->ang); j += (angincs /*-(krand()&511)*/))
362
    {
362
    {
363
        vec3_t origin = *(const vec3_t *)ts;
363
        vec3_t origin = *(const vec3_t *)ts;
364
        origin.z -= ZOFFSET2;
364
        origin.z -= ZOFFSET2;
365
        hitscan(&origin, ts->sectnum, sintable[(j + 512) & 2047], sintable[j & 2047], 16384 - (krand() & 32767), &hit, CLIPMASK1);
365
        hitscan(&origin, ts->sectnum, sintable[(j + 512) & 2047], sintable[j & 2047], 16384 - (krand() & 32767), &hit, CLIPMASK1);
366
366
367
        if (hit.sect < 0)
367
        if (hit.sect < 0)
368
            continue;
368
            continue;
369
369
370
        int const d  = FindDistance2D(hit.pos.x - ts->x, hit.pos.y - ts->y);
370
        int const d  = FindDistance2D(hit.pos.x - ts->x, hit.pos.y - ts->y);
371
        int const da = FindDistance2D(hit.pos.x - pnSprite->x, hit.pos.y - pnSprite->y);
371
        int const da = FindDistance2D(hit.pos.x - pnSprite->x, hit.pos.y - pnSprite->y);
372
372
373
        if (d < da)
373
        if (d < da)
374
        {
374
        {
375
            if (cansee(hit.pos.x, hit.pos.y, hit.pos.z, hit.sect, pnSprite->x, pnSprite->y, pnSprite->z - ZOFFSET2, pnSprite->sectnum))
375
            if (cansee(hit.pos.x, hit.pos.y, hit.pos.z, hit.sect, pnSprite->x, pnSprite->y, pnSprite->z - ZOFFSET2, pnSprite->sectnum))
376
            {
376
            {
377
                vect->x = hit.pos.x;
377
                vect->x = hit.pos.x;
378
                vect->y = hit.pos.y;
378
                vect->y = hit.pos.y;
379
                return hit.sect;
379
                return hit.sect;
380
            }
380
            }
381
        }
381
        }
382
    }
382
    }
383
383
384
    return -1;
384
    return -1;
385
}
385
}
386
386
387
void VM_GetZRange(int const spriteNum, int32_t * const ceilhit, int32_t * const florhit, int const wallDist)
387
void VM_GetZRange(int const spriteNum, int32_t * const ceilhit, int32_t * const florhit, int const wallDist)
388
{
388
{
389
    auto const pSprite = &sprite[spriteNum];
389
    auto const pSprite = &sprite[spriteNum];
390
    int const  ocstat  = pSprite->cstat;
390
    int const  ocstat  = pSprite->cstat;
391
391
392
    pSprite->cstat = 0;
392
    pSprite->cstat = 0;
393
    pSprite->z -= ACTOR_FLOOR_OFFSET;
393
    pSprite->z -= ACTOR_FLOOR_OFFSET;
394
394
395
    getzrange(&pSprite->pos, pSprite->sectnum, &actor[spriteNum].ceilingz, ceilhit, &actor[spriteNum].floorz, florhit, wallDist, CLIPMASK0);
395
    getzrange(&pSprite->pos, pSprite->sectnum, &actor[spriteNum].ceilingz, ceilhit, &actor[spriteNum].floorz, florhit, wallDist, CLIPMASK0);
396
396
397
    pSprite->z += ACTOR_FLOOR_OFFSET;
397
    pSprite->z += ACTOR_FLOOR_OFFSET;
398
    pSprite->cstat = ocstat;
398
    pSprite->cstat = ocstat;
399
}
399
}
400
400
401
void A_GetZLimits(int const spriteNum)
401
void A_GetZLimits(int const spriteNum)
402
{
402
{
403
    auto const pSprite = &sprite[spriteNum];
403
    auto const pSprite = &sprite[spriteNum];
404
    int32_t    ceilhit, florhit;
404
    int32_t    ceilhit, florhit;
405
    int const  clipDist = A_GetClipdist(spriteNum, -1);
405
    int const  clipDist = A_GetClipdist(spriteNum, -1);
406
    auto const oceilz   = actor[spriteNum].ceilingz;
406
    auto const oceilz   = actor[spriteNum].ceilingz;
407
407
408
    VM_GetZRange(spriteNum, &ceilhit, &florhit, pSprite->statnum == STAT_PROJECTILE ? clipDist << 3 : clipDist);
408
    VM_GetZRange(spriteNum, &ceilhit, &florhit, pSprite->statnum == STAT_PROJECTILE ? clipDist << 3 : clipDist);
409
    actor[spriteNum].flags &= ~SFLAG_NOFLOORSHADOW;
409
    actor[spriteNum].flags &= ~SFLAG_NOFLOORSHADOW;
410
410
411
    if ((florhit&49152) == 49152 && (sprite[florhit&(MAXSPRITES-1)].cstat&48) == 0)
411
    if ((florhit&49152) == 49152 && (sprite[florhit&(MAXSPRITES-1)].cstat&48) == 0)
412
    {
412
    {
413
        auto const hitspr = (uspriteptr_t)&sprite[florhit&(MAXSPRITES-1)];
413
        auto const hitspr = (uspriteptr_t)&sprite[florhit&(MAXSPRITES-1)];
414
414
415
        florhit &= (MAXSPRITES-1);
415
        florhit &= (MAXSPRITES-1);
416
416
417
        // If a non-projectile would fall onto non-frozen enemy OR an enemy onto a player...
417
        // If a non-projectile would fall onto non-frozen enemy OR an enemy onto a player...
418
        if ((A_CheckEnemySprite(hitspr) && hitspr->pal != 1 && pSprite->statnum != STAT_PROJECTILE)
418
        if ((A_CheckEnemySprite(hitspr) && hitspr->pal != 1 && pSprite->statnum != STAT_PROJECTILE)
419
                || (hitspr->picnum == APLAYER && A_CheckEnemySprite(pSprite)))
419
                || (hitspr->picnum == APLAYER && A_CheckEnemySprite(pSprite)))
420
        {
420
        {
421
            actor[spriteNum].flags |= SFLAG_NOFLOORSHADOW;  // No shadows on actors
421
            actor[spriteNum].flags |= SFLAG_NOFLOORSHADOW;  // No shadows on actors
422
            pSprite->xvel = -256;  // SLIDE_ABOVE_ENEMY
422
            pSprite->xvel = -256;  // SLIDE_ABOVE_ENEMY
423
            A_SetSprite(spriteNum, CLIPMASK0);
423
            A_SetSprite(spriteNum, CLIPMASK0);
424
        }
424
        }
425
        else if (pSprite->statnum == STAT_PROJECTILE && hitspr->picnum == APLAYER && pSprite->owner==florhit)
425
        else if (pSprite->statnum == STAT_PROJECTILE && hitspr->picnum == APLAYER && pSprite->owner==florhit)
426
        {
426
        {
427
            actor[spriteNum].ceilingz = sector[pSprite->sectnum].ceilingz;
427
            actor[spriteNum].ceilingz = sector[pSprite->sectnum].ceilingz;
428
            actor[spriteNum].floorz   = sector[pSprite->sectnum].floorz;
428
            actor[spriteNum].floorz   = sector[pSprite->sectnum].floorz;
429
        }
429
        }
430
    }
430
    }
431
431
432
    // in E1L1, the dumpster fire sprites break after calling this function because the cardboard boxes
432
    // in E1L1, the dumpster fire sprites break after calling this function because the cardboard boxes
433
    // are a few units higher than the fire and are detected as the "ceiling"
433
    // are a few units higher than the fire and are detected as the "ceiling"
434
    // unfortunately, this trips the "ifgapzl 16 break" in "state firestate"
434
    // unfortunately, this trips the "ifgapzl 16 break" in "state firestate"
435
    if ((ceilhit&49152) == 49152 && (sprite[ceilhit&(MAXSPRITES-1)].cstat&48) == 0)
435
    if ((ceilhit&49152) == 49152 && (sprite[ceilhit&(MAXSPRITES-1)].cstat&48) == 0)
436
    {
436
    {
437
        if (pSprite->z >= actor[spriteNum].floorz)
437
        if (pSprite->z >= actor[spriteNum].floorz)
438
            actor[spriteNum].ceilingz = oceilz;
438
            actor[spriteNum].ceilingz = oceilz;
439
    }
439
    }
440
}
440
}
441
441
442
void A_Fall(int const spriteNum)
442
void A_Fall(int const spriteNum)
443
{
443
{
444
    auto const pSprite = &sprite[spriteNum];
444
    auto const pSprite = &sprite[spriteNum];
445
    int spriteGravity = g_spriteGravity;
445
    int spriteGravity = g_spriteGravity;
446
446
447
    if (EDUKE32_PREDICT_FALSE(G_CheckForSpaceFloor(pSprite->sectnum)))
447
    if (EDUKE32_PREDICT_FALSE(G_CheckForSpaceFloor(pSprite->sectnum)))
448
        spriteGravity = 0;
448
        spriteGravity = 0;
449
    else if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER || EDUKE32_PREDICT_FALSE(G_CheckForSpaceCeiling(pSprite->sectnum)))
449
    else if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER || EDUKE32_PREDICT_FALSE(G_CheckForSpaceCeiling(pSprite->sectnum)))
450
        spriteGravity = g_spriteGravity/6;
450
        spriteGravity = g_spriteGravity/6;
451
451
452
    int32_t ceilhit, florhit;
452
    int32_t ceilhit, florhit;
453
    VM_GetZRange(spriteNum, &ceilhit, &florhit, A_GetClipdist(spriteNum, -1));
453
    VM_GetZRange(spriteNum, &ceilhit, &florhit, A_GetClipdist(spriteNum, -1));
454
454
455
#ifdef YAX_ENABLE
455
#ifdef YAX_ENABLE
456
    int fbunch = (sector[pSprite->sectnum].floorstat&512) ? -1 : yax_getbunch(pSprite->sectnum, YAX_FLOOR);
456
    int fbunch = (sector[pSprite->sectnum].floorstat&512) ? -1 : yax_getbunch(pSprite->sectnum, YAX_FLOOR);
457
#endif
457
#endif
458
458
459
    if (pSprite->z < actor[spriteNum].floorz-ACTOR_FLOOR_OFFSET
459
    if (pSprite->z < actor[spriteNum].floorz-ACTOR_FLOOR_OFFSET
460
#ifdef YAX_ENABLE
460
#ifdef YAX_ENABLE
461
            || fbunch >= 0
461
            || fbunch >= 0
462
#endif
462
#endif
463
       )
463
       )
464
    {
464
    {
465
        if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER && pSprite->zvel > 3122)
465
        if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER && pSprite->zvel > 3122)
466
            pSprite->zvel = 3144;
466
            pSprite->zvel = 3144;
467
        pSprite->z += pSprite->zvel = min(ACTOR_MAXFALLINGZVEL, pSprite->zvel+spriteGravity);
467
        pSprite->z += pSprite->zvel = min(ACTOR_MAXFALLINGZVEL, pSprite->zvel+spriteGravity);
468
    }
468
    }
469
469
470
#ifdef YAX_ENABLE
470
#ifdef YAX_ENABLE
471
    if (fbunch >= 0)
471
    if (fbunch >= 0)
472
        setspritez(spriteNum, &pSprite->pos);
472
        setspritez(spriteNum, &pSprite->pos);
473
    else
473
    else
474
#endif
474
#endif
475
        if (pSprite->z >= actor[spriteNum].floorz-ACTOR_FLOOR_OFFSET)
475
        if (pSprite->z >= actor[spriteNum].floorz-ACTOR_FLOOR_OFFSET)
476
        {
476
        {
477
            pSprite->z = actor[spriteNum].floorz-ACTOR_FLOOR_OFFSET;
477
            pSprite->z = actor[spriteNum].floorz-ACTOR_FLOOR_OFFSET;
478
            pSprite->zvel = 0;
478
            pSprite->zvel = 0;
479
        }
479
        }
480
}
480
}
481
481
482
int __fastcall G_GetAngleDelta(int currAngle, int newAngle)
482
int __fastcall G_GetAngleDelta(int currAngle, int newAngle)
483
{
483
{
484
    currAngle &= 2047;
484
    currAngle &= 2047;
485
    newAngle &= 2047;
485
    newAngle &= 2047;
486
486
487
    if (klabs(currAngle-newAngle) < 1024)
487
    if (klabs(currAngle-newAngle) < 1024)
488
    {
488
    {
489
//        OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
489
//        OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
490
        return newAngle-currAngle;
490
        return newAngle-currAngle;
491
    }
491
    }
492
492
493
    if (newAngle > 1024)
493
    if (newAngle > 1024)
494
        newAngle -= 2048;
494
        newAngle -= 2048;
495
    if (currAngle > 1024)
495
    if (currAngle > 1024)
496
        currAngle -= 2048;
496
        currAngle -= 2048;
497
497
498
//    OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
498
//    OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
499
    return newAngle-currAngle;
499
    return newAngle-currAngle;
500
}
500
}
501
501
502
GAMEEXEC_STATIC void VM_AlterAng(int32_t const moveFlags)
502
GAMEEXEC_STATIC void VM_AlterAng(int32_t const moveFlags)
503
{
503
{
504
    int const elapsedTics = (AC_COUNT(vm.pData))&31;
504
    int const elapsedTics = (AC_COUNT(vm.pData))&31;
505
505
506
#if !defined LUNATIC
506
#if !defined LUNATIC
507
    if (EDUKE32_PREDICT_FALSE((unsigned)AC_MOVE_ID(vm.pData) >= (unsigned)g_scriptSize-1))
507
    if (EDUKE32_PREDICT_FALSE((unsigned)AC_MOVE_ID(vm.pData) >= (unsigned)g_scriptSize-1))
508
508
509
    {
509
    {
510
        AC_MOVE_ID(vm.pData) = 0;
510
        AC_MOVE_ID(vm.pData) = 0;
511
        OSD_Printf(OSD_ERROR "bad moveptr for actor %d (%d)!\n", vm.spriteNum, vm.pUSprite->picnum);
511
        OSD_Printf(OSD_ERROR "bad moveptr for actor %d (%d)!\n", vm.spriteNum, vm.pUSprite->picnum);
512
        return;
512
        return;
513
    }
513
    }
514
514
515
    auto const moveptr = apScript + AC_MOVE_ID(vm.pData);
515
    auto const moveptr = apScript + AC_MOVE_ID(vm.pData);
516
    auto &hvel    = moveptr[0];
516
    auto &hvel    = moveptr[0];
517
    auto &vvel    = moveptr[1];
517
    auto &vvel    = moveptr[1];
518
#else
518
#else
519
    auto &hvel = vm.pActor->mv.hvel;
519
    auto &hvel = vm.pActor->mv.hvel;
520
    auto &vvel = vm.pActor->mv.vvel;
520
    auto &vvel = vm.pActor->mv.vvel;
521
#endif
521
#endif
522
522
523
    vm.pSprite->xvel += (hvel - vm.pSprite->xvel)/5;
523
    vm.pSprite->xvel += (hvel - vm.pSprite->xvel)/5;
524
    if (vm.pSprite->zvel < 648)
524
    if (vm.pSprite->zvel < 648)
525
        vm.pSprite->zvel += ((vvel<<4) - vm.pSprite->zvel)/5;
525
        vm.pSprite->zvel += ((vvel<<4) - vm.pSprite->zvel)/5;
526
526
527
    if (A_CheckEnemySprite(vm.pSprite) && vm.pSprite->extra <= 0) // hack
527
    if (A_CheckEnemySprite(vm.pSprite) && vm.pSprite->extra <= 0) // hack
528
        return;
528
        return;
529
529
530
    if (moveFlags&seekplayer)
530
    if (moveFlags&seekplayer)
531
    {
531
    {
532
        int const spriteAngle    = vm.pSprite->ang;
532
        int const spriteAngle    = vm.pSprite->ang;
533
        int const holoDukeSprite = vm.pPlayer->holoduke_on;
533
        int const holoDukeSprite = vm.pPlayer->holoduke_on;
534
534
535
        // NOTE: looks like 'owner' is set to target sprite ID...
535
        // NOTE: looks like 'owner' is set to target sprite ID...
536
536
537
        vm.pSprite->owner = (holoDukeSprite >= 0
537
        vm.pSprite->owner = (holoDukeSprite >= 0
538
                             && cansee(sprite[holoDukeSprite].x, sprite[holoDukeSprite].y, sprite[holoDukeSprite].z, sprite[holoDukeSprite].sectnum,
538
                             && cansee(sprite[holoDukeSprite].x, sprite[holoDukeSprite].y, sprite[holoDukeSprite].z, sprite[holoDukeSprite].sectnum,
539
                                       vm.pSprite->x, vm.pSprite->y, vm.pSprite->z, vm.pSprite->sectnum))
539
                                       vm.pSprite->x, vm.pSprite->y, vm.pSprite->z, vm.pSprite->sectnum))
540
          ? holoDukeSprite
540
          ? holoDukeSprite
541
          : vm.pPlayer->i;
541
          : vm.pPlayer->i;
542
542
543
        int const goalAng = (sprite[vm.pSprite->owner].picnum == APLAYER)
543
        int const goalAng = (sprite[vm.pSprite->owner].picnum == APLAYER)
544
                  ? getangle(vm.pActor->lastv.x - vm.pSprite->x, vm.pActor->lastv.y - vm.pSprite->y)
544
                  ? getangle(vm.pActor->lastv.x - vm.pSprite->x, vm.pActor->lastv.y - vm.pSprite->y)
545
                  : getangle(sprite[vm.pSprite->owner].x - vm.pSprite->x, sprite[vm.pSprite->owner].y - vm.pSprite->y);
545
                  : getangle(sprite[vm.pSprite->owner].x - vm.pSprite->x, sprite[vm.pSprite->owner].y - vm.pSprite->y);
546
546
547
        if (vm.pSprite->xvel && vm.pSprite->picnum != DRONE)
547
        if (vm.pSprite->xvel && vm.pSprite->picnum != DRONE)
548
        {
548
        {
549
            int const angDiff = G_GetAngleDelta(spriteAngle, goalAng);
549
            int const angDiff = G_GetAngleDelta(spriteAngle, goalAng);
550
550
551
            if (elapsedTics < 2)
551
            if (elapsedTics < 2)
552
            {
552
            {
553
                if (klabs(angDiff) < 256)
553
                if (klabs(angDiff) < 256)
554
                {
554
                {
555
                    int const angInc = 128-(krand()&256);
555
                    int const angInc = 128-(krand()&256);
556
                    vm.pSprite->ang += angInc;
556
                    vm.pSprite->ang += angInc;
557
                    if (A_GetHitscanRange(vm.spriteNum) < 844)
557
                    if (A_GetHitscanRange(vm.spriteNum) < 844)
558
                        vm.pSprite->ang -= angInc;
558
                        vm.pSprite->ang -= angInc;
559
                }
559
                }
560
            }
560
            }
561
            else if (elapsedTics > 18 && elapsedTics < GAMETICSPERSEC) // choose
561
            else if (elapsedTics > 18 && elapsedTics < GAMETICSPERSEC) // choose
562
            {
562
            {
563
                if (klabs(angDiff >> 2) < 128)
563
                if (klabs(angDiff >> 2) < 128)
564
                    vm.pSprite->ang = goalAng;
564
                    vm.pSprite->ang = goalAng;
565
                else
565
                else
566
                    vm.pSprite->ang += angDiff >> 2;
566
                    vm.pSprite->ang += angDiff >> 2;
567
            }
567
            }
568
        }
568
        }
569
        else
569
        else
570
            vm.pSprite->ang = goalAng;
570
            vm.pSprite->ang = goalAng;
571
    }
571
    }
572
572
573
    if (elapsedTics < 1)
573
    if (elapsedTics < 1)
574
    {
574
    {
575
        if (moveFlags&furthestdir)
575
        if (moveFlags&furthestdir)
576
        {
576
        {
577
            vm.pSprite->ang = A_GetFurthestAngle(vm.spriteNum, 2);
577
            vm.pSprite->ang = A_GetFurthestAngle(vm.spriteNum, 2);
578
            vm.pSprite->owner = vm.pPlayer->i;
578
            vm.pSprite->owner = vm.pPlayer->i;
579
        }
579
        }
580
580
581
        if (moveFlags&fleeenemy)
581
        if (moveFlags&fleeenemy)
582
            vm.pSprite->ang = A_GetFurthestAngle(vm.spriteNum, 2);
582
            vm.pSprite->ang = A_GetFurthestAngle(vm.spriteNum, 2);
583
    }
583
    }
584
}
584
}
585
585
586
static inline void VM_AddAngle(int const shift, int const goalAng)
586
static inline void VM_AddAngle(int const shift, int const goalAng)
587
{
587
{
588
    int angDiff = G_GetAngleDelta(vm.pSprite->ang, goalAng) >> shift;
588
    int angDiff = G_GetAngleDelta(vm.pSprite->ang, goalAng) >> shift;
589
589
590
    if ((angDiff > -8 && angDiff < 0) || (angDiff < 8 && angDiff > 0))
590
    if ((angDiff > -8 && angDiff < 0) || (angDiff < 8 && angDiff > 0))
591
        angDiff <<= 1;
591
        angDiff <<= 1;
592
592
593
    vm.pSprite->ang += angDiff;
593
    vm.pSprite->ang += angDiff;
594
}
594
}
595
595
596
static inline void VM_FacePlayer(int const shift)
596
static inline void VM_FacePlayer(int const shift)
597
{
597
{
598
    VM_AddAngle(shift, (vm.pPlayer->newowner >= 0) ? getangle(vm.pPlayer->opos.x - vm.pSprite->x, vm.pPlayer->opos.y - vm.pSprite->y)
598
    VM_AddAngle(shift, (vm.pPlayer->newowner >= 0) ? getangle(vm.pPlayer->opos.x - vm.pSprite->x, vm.pPlayer->opos.y - vm.pSprite->y)
599
                                                 : getangle(vm.pPlayer->pos.x - vm.pSprite->x, vm.pPlayer->pos.y - vm.pSprite->y));
599
                                                 : getangle(vm.pPlayer->pos.x - vm.pSprite->x, vm.pPlayer->pos.y - vm.pSprite->y));
600
}
600
}
601
601
602
////////// TROR get*zofslope //////////
602
////////// TROR get*zofslope //////////
603
// These rather belong into the engine.
603
// These rather belong into the engine.
604
604
605
static int32_t VM_GetCeilZOfSlope(void)
605
static int32_t VM_GetCeilZOfSlope(void)
606
{
606
{
607
    vec2_t const vect     = vm.pSprite->pos.vec2;
607
    vec2_t const vect     = vm.pSprite->pos.vec2;
608
    int const    sectnum  = vm.pSprite->sectnum;
608
    int const    sectnum  = vm.pSprite->sectnum;
609
609
610
#ifdef YAX_ENABLE
610
#ifdef YAX_ENABLE
611
    if ((sector[sectnum].ceilingstat&512)==0)
611
    if ((sector[sectnum].ceilingstat&512)==0)
612
    {
612
    {
613
        int const nsect = yax_getneighborsect(vect.x, vect.y, sectnum, YAX_CEILING);
613
        int const nsect = yax_getneighborsect(vect.x, vect.y, sectnum, YAX_CEILING);
614
        if (nsect >= 0)
614
        if (nsect >= 0)
615
            return getceilzofslope(nsect, vect.x, vect.y);
615
            return getceilzofslope(nsect, vect.x, vect.y);
616
    }
616
    }
617
#endif
617
#endif
618
    return getceilzofslope(sectnum, vect.x, vect.y);
618
    return getceilzofslope(sectnum, vect.x, vect.y);
619
}
619
}
620
620
621
#ifndef EDUKE32_STANDALONE
621
#ifndef EDUKE32_STANDALONE
622
static int32_t VM_GetFlorZOfSlope(void)
622
static int32_t VM_GetFlorZOfSlope(void)
623
{
623
{
624
    vec2_t const vect    = vm.pSprite->pos.vec2;
624
    vec2_t const vect    = vm.pSprite->pos.vec2;
625
    int const    sectnum = vm.pSprite->sectnum;
625
    int const    sectnum = vm.pSprite->sectnum;
626
626
627
#ifdef YAX_ENABLE
627
#ifdef YAX_ENABLE
628
    if ((sector[sectnum].floorstat&512)==0)
628
    if ((sector[sectnum].floorstat&512)==0)
629
    {
629
    {
630
        int const nsect = yax_getneighborsect(vect.x, vect.y, sectnum, YAX_FLOOR);
630
        int const nsect = yax_getneighborsect(vect.x, vect.y, sectnum, YAX_FLOOR);
631
        if (nsect >= 0)
631
        if (nsect >= 0)
632
            return getflorzofslope(nsect, vect.x, vect.y);
632
            return getflorzofslope(nsect, vect.x, vect.y);
633
    }
633
    }
634
#endif
634
#endif
635
    return getflorzofslope(sectnum, vect.x, vect.y);
635
    return getflorzofslope(sectnum, vect.x, vect.y);
636
}
636
}
637
#endif
637
#endif
638
638
639
////////////////////
639
////////////////////
640
640
641
static int32_t A_GetWaterZOffset(int spritenum);
641
static int32_t A_GetWaterZOffset(int spritenum);
642
642
643
GAMEEXEC_STATIC void VM_Move(void)
643
GAMEEXEC_STATIC void VM_Move(void)
644
{
644
{
645
    auto const movflagsptr = &AC_MOVFLAGS(vm.pSprite, &actor[vm.spriteNum]);
645
    auto const movflagsptr = &AC_MOVFLAGS(vm.pSprite, &actor[vm.spriteNum]);
646
    // NOTE: test against -1 commented out and later revived in source history
646
    // NOTE: test against -1 commented out and later revived in source history
647
    // XXX: Does its presence/absence break anything? Where are movflags with all bits set created?
647
    // XXX: Does its presence/absence break anything? Where are movflags with all bits set created?
648
    int const movflags = (*movflagsptr == (remove_pointer_t<decltype(movflagsptr)>)-1) ? 0 : *movflagsptr;
648
    int const movflags = (*movflagsptr == (remove_pointer_t<decltype(movflagsptr)>)-1) ? 0 : *movflagsptr;
649
    int const deadflag = (A_CheckEnemySprite(vm.pSprite) && vm.pSprite->extra <= 0);
649
    int const deadflag = (A_CheckEnemySprite(vm.pSprite) && vm.pSprite->extra <= 0);
650
650
651
    AC_COUNT(vm.pData)++;
651
    AC_COUNT(vm.pData)++;
652
652
653
    if (AC_MOVE_ID(vm.pData) == 0 || movflags == 0)
653
    if (AC_MOVE_ID(vm.pData) == 0 || movflags == 0)
654
    {
654
    {
655
        if (deadflag)
655
        if (deadflag)
656
            setsprite(vm.spriteNum, &vm.pSprite->pos);
656
            setsprite(vm.spriteNum, &vm.pSprite->pos);
657
657
658
        return;
658
        return;
659
    }
659
    }
660
660
661
    if (!deadflag)
661
    if (!deadflag)
662
    {
662
    {
663
        if (movflags & face_player)
663
        if (movflags & face_player)
664
            VM_FacePlayer(2);
664
            VM_FacePlayer(2);
665
665
666
        if (movflags & spin)
666
        if (movflags & spin)
667
            vm.pSprite->ang += sintable[((AC_COUNT(vm.pData) << 3) & 2047)] >> 6;
667
            vm.pSprite->ang += sintable[((AC_COUNT(vm.pData) << 3) & 2047)] >> 6;
668
668
669
        if (movflags & face_player_slow)
669
        if (movflags & face_player_slow)
670
            VM_FacePlayer(4);
670
            VM_FacePlayer(4);
671
671
672
        if ((movflags & jumptoplayer_bits) == jumptoplayer_bits)
672
        if ((movflags & jumptoplayer_bits) == jumptoplayer_bits)
673
        {
673
        {
674
            if (AC_COUNT(vm.pData) < 16)
674
            if (AC_COUNT(vm.pData) < 16)
675
                vm.pSprite->zvel -= (sintable[(512 + (AC_COUNT(vm.pData) << 4)) & 2047] >> 5);
675
                vm.pSprite->zvel -= (sintable[(512 + (AC_COUNT(vm.pData) << 4)) & 2047] >> 5);
676
        }
676
        }
677
677
678
        if (movflags & face_player_smart)
678
        if (movflags & face_player_smart)
679
        {
679
        {
680
            vec2_t const vect = { vm.pPlayer->pos.x + (vm.pPlayer->vel.x / 768), vm.pPlayer->pos.y + (vm.pPlayer->vel.y / 768) };
680
            vec2_t const vect = { vm.pPlayer->pos.x + (vm.pPlayer->vel.x / 768), vm.pPlayer->pos.y + (vm.pPlayer->vel.y / 768) };
681
            VM_AddAngle(2, getangle(vect.x - vm.pSprite->x, vect.y - vm.pSprite->y));
681
            VM_AddAngle(2, getangle(vect.x - vm.pSprite->x, vect.y - vm.pSprite->y));
682
        }
682
        }
683
    }
683
    }
684
684
685
#if !defined LUNATIC
685
#if !defined LUNATIC
686
    if (EDUKE32_PREDICT_FALSE((unsigned)AC_MOVE_ID(vm.pData) >= (unsigned)g_scriptSize-1))
686
    if (EDUKE32_PREDICT_FALSE((unsigned)AC_MOVE_ID(vm.pData) >= (unsigned)g_scriptSize-1))
687
    {
687
    {
688
        AC_MOVE_ID(vm.pData) = 0;
688
        AC_MOVE_ID(vm.pData) = 0;
689
        OSD_Printf(OSD_ERROR "clearing bad moveptr for actor %d (%d)\n", vm.spriteNum, vm.pUSprite->picnum);
689
        OSD_Printf(OSD_ERROR "clearing bad moveptr for actor %d (%d)\n", vm.spriteNum, vm.pUSprite->picnum);
690
        return;
690
        return;
691
    }
691
    }
692
692
693
    auto const moveptr = apScript + AC_MOVE_ID(vm.pData);
693
    auto const moveptr = apScript + AC_MOVE_ID(vm.pData);
694
    auto &hvel = moveptr[0];
694
    auto &hvel = moveptr[0];
695
    auto &vvel = moveptr[1];
695
    auto &vvel = moveptr[1];
696
#else
696
#else
697
    auto &hvel = vm.pActor->mv.hvel;
697
    auto &hvel = vm.pActor->mv.hvel;
698
    auto &vvel = vm.pActor->mv.vvel;
698
    auto &vvel = vm.pActor->mv.vvel;
699
#endif
699
#endif
700
700
701
    if (movflags & geth)
701
    if (movflags & geth)
702
        vm.pSprite->xvel += (hvel - vm.pSprite->xvel) >> 1;
702
        vm.pSprite->xvel += (hvel - vm.pSprite->xvel) >> 1;
703
703
704
    if (movflags & getv)
704
    if (movflags & getv)
705
        vm.pSprite->zvel += (16 * vvel - vm.pSprite->zvel) >> 1;
705
        vm.pSprite->zvel += (16 * vvel - vm.pSprite->zvel) >> 1;
706
706
707
    if (movflags&dodgebullet && !deadflag)
707
    if (movflags&dodgebullet && !deadflag)
708
        A_Dodge(vm.pSprite);
708
        A_Dodge(vm.pSprite);
709
709
710
    if (vm.pSprite->picnum != APLAYER)
710
    if (vm.pSprite->picnum != APLAYER)
711
        VM_AlterAng(movflags);
711
        VM_AlterAng(movflags);
712
712
713
    if (vm.pSprite->xvel > -6 && vm.pSprite->xvel < 6)
713
    if (vm.pSprite->xvel > -6 && vm.pSprite->xvel < 6)
714
        vm.pSprite->xvel = 0;
714
        vm.pSprite->xvel = 0;
715
715
716
    int badguyp = A_CheckEnemySprite(vm.pSprite);
716
    int badguyp = A_CheckEnemySprite(vm.pSprite);
717
717
718
    if (vm.pSprite->xvel || vm.pSprite->zvel)
718
    if (vm.pSprite->xvel || vm.pSprite->zvel)
719
    {
719
    {
720
        int spriteXvel = vm.pSprite->xvel;
720
        int spriteXvel = vm.pSprite->xvel;
721
        int angDiff    = vm.pSprite->ang;
721
        int angDiff    = vm.pSprite->ang;
722
722
723
#ifndef EDUKE32_STANDALONE
723
#ifndef EDUKE32_STANDALONE
724
        if (badguyp && (FURY || vm.pSprite->picnum != ROTATEGUN))
724
        if (badguyp && (FURY || vm.pSprite->picnum != ROTATEGUN))
725
        {
725
        {
726
            if (!FURY && (vm.pSprite->picnum == DRONE || vm.pSprite->picnum == COMMANDER) && vm.pSprite->extra > 0)
726
            if (!FURY && (vm.pSprite->picnum == DRONE || vm.pSprite->picnum == COMMANDER) && vm.pSprite->extra > 0)
727
            {
727
            {
728
                if (vm.pSprite->picnum == COMMANDER)
728
                if (vm.pSprite->picnum == COMMANDER)
729
                {
729
                {
730
                    int32_t nSectorZ;
730
                    int32_t nSectorZ;
731
                    // NOTE: COMMANDER updates both actor[].floorz and
731
                    // NOTE: COMMANDER updates both actor[].floorz and
732
                    // .ceilingz regardless of its zvel.
732
                    // .ceilingz regardless of its zvel.
733
                    vm.pActor->floorz = nSectorZ = VM_GetFlorZOfSlope();
733
                    vm.pActor->floorz = nSectorZ = VM_GetFlorZOfSlope();
734
                    if (vm.pSprite->z > nSectorZ-ZOFFSET3)
734
                    if (vm.pSprite->z > nSectorZ-ZOFFSET3)
735
                    {
735
                    {
736
                        vm.pSprite->z = nSectorZ-ZOFFSET3;
736
                        vm.pSprite->z = nSectorZ-ZOFFSET3;
737
                        vm.pSprite->zvel = 0;
737
                        vm.pSprite->zvel = 0;
738
                    }
738
                    }
739
739
740
                    vm.pActor->ceilingz = nSectorZ = VM_GetCeilZOfSlope();
740
                    vm.pActor->ceilingz = nSectorZ = VM_GetCeilZOfSlope();
741
                    if (vm.pSprite->z < nSectorZ+(80<<8))
741
                    if (vm.pSprite->z < nSectorZ+(80<<8))
742
                    {
742
                    {
743
                        vm.pSprite->z = nSectorZ+(80<<8);
743
                        vm.pSprite->z = nSectorZ+(80<<8);
744
                        vm.pSprite->zvel = 0;
744
                        vm.pSprite->zvel = 0;
745
                    }
745
                    }
746
                }
746
                }
747
                else
747
                else
748
                {
748
                {
749
                    int32_t nSectorZ;
749
                    int32_t nSectorZ;
750
                    // The DRONE updates either .floorz or .ceilingz, not both.
750
                    // The DRONE updates either .floorz or .ceilingz, not both.
751
                    if (vm.pSprite->zvel > 0)
751
                    if (vm.pSprite->zvel > 0)
752
                    {
752
                    {
753
                        vm.pActor->floorz = nSectorZ = VM_GetFlorZOfSlope();
753
                        vm.pActor->floorz = nSectorZ = VM_GetFlorZOfSlope();
754
                        if (vm.pSprite->z > nSectorZ-(30<<8))
754
                        if (vm.pSprite->z > nSectorZ-(30<<8))
755
                            vm.pSprite->z = nSectorZ-(30<<8);
755
                            vm.pSprite->z = nSectorZ-(30<<8);
756
                    }
756
                    }
757
                    else
757
                    else
758
                    {
758
                    {
759
                        vm.pActor->ceilingz = nSectorZ = VM_GetCeilZOfSlope();
759
                        vm.pActor->ceilingz = nSectorZ = VM_GetCeilZOfSlope();
760
                        if (vm.pSprite->z < nSectorZ+(50<<8))
760
                        if (vm.pSprite->z < nSectorZ+(50<<8))
761
                        {
761
                        {
762
                            vm.pSprite->z = nSectorZ+(50<<8);
762
                            vm.pSprite->z = nSectorZ+(50<<8);
763
                            vm.pSprite->zvel = 0;
763
                            vm.pSprite->zvel = 0;
764
                        }
764
                        }
765
                    }
765
                    }
766
                }
766
                }
767
            }
767
            }
768
            else if ((FURY && badguyp) || vm.pSprite->picnum != ORGANTIC)
768
            else if ((FURY && badguyp) || vm.pSprite->picnum != ORGANTIC)
769
#else
769
#else
770
        if (badguyp)
770
        if (badguyp)
771
        {
771
        {
772
#endif
772
#endif
773
            {
773
            {
774
                // All other actors besides ORGANTIC don't update .floorz or
774
                // All other actors besides ORGANTIC don't update .floorz or
775
                // .ceilingz here.
775
                // .ceilingz here.
776
                if (vm.pSprite->zvel > 0)
776
                if (vm.pSprite->zvel > 0)
777
                {
777
                {
778
                    if (vm.pSprite->z > vm.pActor->floorz)
778
                    if (vm.pSprite->z > vm.pActor->floorz)
779
                        vm.pSprite->z = vm.pActor->floorz;
779
                        vm.pSprite->z = vm.pActor->floorz;
780
                    vm.pSprite->z += A_GetWaterZOffset(vm.spriteNum);
780
                    vm.pSprite->z += A_GetWaterZOffset(vm.spriteNum);
781
                }
781
                }
782
                else if (vm.pSprite->zvel < 0)
782
                else if (vm.pSprite->zvel < 0)
783
                {
783
                {
784
                    int const l = VM_GetCeilZOfSlope();
784
                    int const l = VM_GetCeilZOfSlope();
785
785
786
                    if (vm.pSprite->z < l+(66<<8))
786
                    if (vm.pSprite->z < l+(66<<8))
787
                    {
787
                    {
788
                        vm.pSprite->z = l+(66<<8);
788
                        vm.pSprite->z = l+(66<<8);
789
                        vm.pSprite->zvel >>= 1;
789
                        vm.pSprite->zvel >>= 1;
790
                    }
790
                    }
791
                }
791
                }
792
            }
792
            }
793
793
794
            if (vm.playerDist < 960 && vm.pSprite->xrepeat > 16)
794
            if (vm.playerDist < 960 && vm.pSprite->xrepeat > 16)
795
            {
795
            {
796
                spriteXvel = -(1024 - vm.playerDist);
796
                spriteXvel = -(1024 - vm.playerDist);
797
                angDiff = getangle(vm.pPlayer->pos.x - vm.pSprite->x, vm.pPlayer->pos.y - vm.pSprite->y);
797
                angDiff = getangle(vm.pPlayer->pos.x - vm.pSprite->x, vm.pPlayer->pos.y - vm.pSprite->y);
798
798
799
                if (vm.playerDist < 512)
799
                if (vm.playerDist < 512)
800
                {
800
                {
801
                    vm.pPlayer->vel.x = 0;
801
                    vm.pPlayer->vel.x = 0;
802
                    vm.pPlayer->vel.y = 0;
802
                    vm.pPlayer->vel.y = 0;
803
                }
803
                }
804
                else
804
                else
805
                {
805
                {
806
                    vm.pPlayer->vel.x = mulscale16(vm.pPlayer->vel.x, vm.pPlayer->runspeed - 0x2000);
806
                    vm.pPlayer->vel.x = mulscale16(vm.pPlayer->vel.x, vm.pPlayer->runspeed - 0x2000);
807
                    vm.pPlayer->vel.y = mulscale16(vm.pPlayer->vel.y, vm.pPlayer->runspeed - 0x2000);
807
                    vm.pPlayer->vel.y = mulscale16(vm.pPlayer->vel.y, vm.pPlayer->runspeed - 0x2000);
808
                }
808
                }
809
            }
809
            }
810
            else
810
            else
811
#ifndef EDUKE32_STANDALONE
811
#ifndef EDUKE32_STANDALONE
812
                if (FURY || (vm.pSprite->picnum != DRONE && vm.pSprite->picnum != SHARK && vm.pSprite->picnum != COMMANDER))
812
                if (FURY || (vm.pSprite->picnum != DRONE && vm.pSprite->picnum != SHARK && vm.pSprite->picnum != COMMANDER))
813
#endif
813
#endif
814
            {
814
            {
815
                if (vm.pPlayer->actorsqu == vm.spriteNum)
815
                if (vm.pPlayer->actorsqu == vm.spriteNum)
816
                    return;
816
                    return;
817
817
818
                if (!A_CheckSpriteFlags(vm.spriteNum, SFLAG_SMOOTHMOVE))
818
                if (!A_CheckSpriteFlags(vm.spriteNum, SFLAG_SMOOTHMOVE))
819
                {
819
                {
820
                    if (AC_COUNT(vm.pData) & 1)
820
                    if (AC_COUNT(vm.pData) & 1)
821
                        return;
821
                        return;
822
                    spriteXvel <<= 1;
822
                    spriteXvel <<= 1;
823
                }
823
                }
824
            }
824
            }
825
        }
825
        }
826
        else if (vm.pSprite->picnum == APLAYER)
826
        else if (vm.pSprite->picnum == APLAYER)
827
            if (vm.pSprite->z < vm.pActor->ceilingz+ZOFFSET5)
827
            if (vm.pSprite->z < vm.pActor->ceilingz+ZOFFSET5)
828
                vm.pSprite->z = vm.pActor->ceilingz+ZOFFSET5;
828
                vm.pSprite->z = vm.pActor->ceilingz+ZOFFSET5;
829
829
830
        vec3_t const vect
830
        vec3_t const vect
831
        = { (spriteXvel * (sintable[(angDiff + 512) & 2047])) >> 14, (spriteXvel * (sintable[angDiff & 2047])) >> 14, vm.pSprite->zvel };
831
        = { (spriteXvel * (sintable[(angDiff + 512) & 2047])) >> 14, (spriteXvel * (sintable[angDiff & 2047])) >> 14, vm.pSprite->zvel };
832
832
833
        vm.pActor->movflag = A_MoveSprite(vm.spriteNum, &vect, (A_CheckSpriteFlags(vm.spriteNum, SFLAG_NOCLIP) ? 0 : CLIPMASK0));
833
        vm.pActor->movflag = A_MoveSprite(vm.spriteNum, &vect, (A_CheckSpriteFlags(vm.spriteNum, SFLAG_NOCLIP) ? 0 : CLIPMASK0));
834
    }
834
    }
835
835
836
    if (!badguyp)
836
    if (!badguyp)
837
        return;
837
        return;
838
838
839
    vm.pSprite->shade += (sector[vm.pSprite->sectnum].ceilingstat & 1) ? (sector[vm.pSprite->sectnum].ceilingshade - vm.pSprite->shade) >> 1
839
    vm.pSprite->shade += (sector[vm.pSprite->sectnum].ceilingstat & 1) ? (sector[vm.pSprite->sectnum].ceilingshade - vm.pSprite->shade) >> 1
840
                                                                 : (sector[vm.pSprite->sectnum].floorshade - vm.pSprite->shade) >> 1;
840
                                                                 : (sector[vm.pSprite->sectnum].floorshade - vm.pSprite->shade) >> 1;
841
}
841
}
842
842
843
static void P_AddWeaponMaybeSwitch(DukePlayer_t * const ps, int const weaponNum)
843
static void P_AddWeaponMaybeSwitch(DukePlayer_t * const ps, int const weaponNum)
844
{
844
{
845
    if ((ps->weaponswitch & (1|4)) == (1|4))
845
    if ((ps->weaponswitch & (1|4)) == (1|4))
846
    {
846
    {
847
        int const playerNum    = P_Get(ps->i);
847
        int const playerNum    = P_Get(ps->i);
848
        int       new_wchoice  = -1;
848
        int       new_wchoice  = -1;
849
        int       curr_wchoice = -1;
849
        int       curr_wchoice = -1;
850
850
851
        for (native_t i=0; i<=FREEZE_WEAPON && (new_wchoice < 0 || curr_wchoice < 0); i++)
851
        for (native_t i=0; i<=FREEZE_WEAPON && (new_wchoice < 0 || curr_wchoice < 0); i++)
852
        {
852
        {
853
            int w = g_player[playerNum].wchoice[i];
853
            int w = g_player[playerNum].wchoice[i];
854
854
855
            if (w == KNEE_WEAPON)
855
            if (w == KNEE_WEAPON)
856
                w = FREEZE_WEAPON;
856
                w = FREEZE_WEAPON;
857
            else
857
            else
858
                w--;
858
                w--;
859
859
860
            if (w == ps->curr_weapon)
860
            if (w == ps->curr_weapon)
861
                curr_wchoice = i;
861
                curr_wchoice = i;
862
            if (w == weaponNum)
862
            if (w == weaponNum)
863
                new_wchoice = i;
863
                new_wchoice = i;
864
        }
864
        }
865
865
866
        P_AddWeapon(ps, weaponNum, (new_wchoice < curr_wchoice));
866
        P_AddWeapon(ps, weaponNum, (new_wchoice < curr_wchoice));
867
    }
867
    }
868
    else
868
    else
869
    {
869
    {
870
        P_AddWeapon(ps, weaponNum, (ps->weaponswitch & 1));
870
        P_AddWeapon(ps, weaponNum, (ps->weaponswitch & 1));
871
    }
871
    }
872
}
872
}
873
873
874
#if defined LUNATIC
874
#if defined LUNATIC
875
void        P_AddWeaponMaybeSwitchI(int32_t snum, int32_t weap) { P_AddWeaponMaybeSwitch(g_player[snum].ps, weap); }
875
void        P_AddWeaponMaybeSwitchI(int32_t snum, int32_t weap) { P_AddWeaponMaybeSwitch(g_player[snum].ps, weap); }
876
#else
876
#else
877
static void P_AddWeaponAmmoCommon(DukePlayer_t * const pPlayer, int const weaponNum, int const nAmount)
877
static void P_AddWeaponAmmoCommon(DukePlayer_t * const pPlayer, int const weaponNum, int const nAmount)
878
{
878
{
879
    P_AddAmmo(pPlayer, weaponNum, nAmount);
879
    P_AddAmmo(pPlayer, weaponNum, nAmount);
880
880
881
    if (PWEAPON(vm.playerNum, pPlayer->curr_weapon, WorksLike) == KNEE_WEAPON && (pPlayer->gotweapon & (1 << weaponNum)))
881
    if (PWEAPON(vm.playerNum, pPlayer->curr_weapon, WorksLike) == KNEE_WEAPON && (pPlayer->gotweapon & (1 << weaponNum)))
882
        P_AddWeaponMaybeSwitch(pPlayer, weaponNum);
882
        P_AddWeaponMaybeSwitch(pPlayer, weaponNum);
883
}
883
}
884
884
885
static void VM_AddWeapon(DukePlayer_t * const pPlayer, int const weaponNum, int const nAmount)
885
static void VM_AddWeapon(DukePlayer_t * const pPlayer, int const weaponNum, int const nAmount)
886
{
886
{
887
    if (EDUKE32_PREDICT_FALSE((unsigned)weaponNum >= MAX_WEAPONS))
887
    if (EDUKE32_PREDICT_FALSE((unsigned)weaponNum >= MAX_WEAPONS))
888
    {
888
    {
889
        CON_ERRPRINTF("invalid weapon %d\n", weaponNum);
889
        CON_ERRPRINTF("invalid weapon %d\n", weaponNum);
890
        return;
890
        return;
891
    }
891
    }
892
892
893
    if ((pPlayer->gotweapon & (1 << weaponNum)) == 0)
893
    if ((pPlayer->gotweapon & (1 << weaponNum)) == 0)
894
    {
894
    {
895
        P_AddWeaponMaybeSwitch(pPlayer, weaponNum);
895
        P_AddWeaponMaybeSwitch(pPlayer, weaponNum);
896
    }
896
    }
897
    else if (pPlayer->ammo_amount[weaponNum] >= pPlayer->max_ammo_amount[weaponNum])
897
    else if (pPlayer->ammo_amount[weaponNum] >= pPlayer->max_ammo_amount[weaponNum])
898
    {
898
    {
899
        vm.flags |= VM_NOEXECUTE;
899
        vm.flags |= VM_NOEXECUTE;
900
        return;
900
        return;
901
    }
901
    }
902
902
903
    P_AddWeaponAmmoCommon(pPlayer, weaponNum, nAmount);
903
    P_AddWeaponAmmoCommon(pPlayer, weaponNum, nAmount);
904
}
904
}
905
905
906
static void VM_AddAmmo(DukePlayer_t * const pPlayer, int const weaponNum, int const nAmount)
906
static void VM_AddAmmo(DukePlayer_t * const pPlayer, int const weaponNum, int const nAmount)
907
{
907
{
908
    if (EDUKE32_PREDICT_FALSE((unsigned)weaponNum >= MAX_WEAPONS))
908
    if (EDUKE32_PREDICT_FALSE((unsigned)weaponNum >= MAX_WEAPONS))
909
    {
909
    {
910
        CON_ERRPRINTF("invalid weapon %d\n", weaponNum);
910
        CON_ERRPRINTF("invalid weapon %d\n", weaponNum);
911
        return;
911
        return;
912
    }
912
    }
913
913
914
    if (pPlayer->ammo_amount[weaponNum] >= pPlayer->max_ammo_amount[weaponNum])
914
    if (pPlayer->ammo_amount[weaponNum] >= pPlayer->max_ammo_amount[weaponNum])
915
    {
915
    {
916
        vm.flags |= VM_NOEXECUTE;
916
        vm.flags |= VM_NOEXECUTE;
917
        return;
917
        return;
918
    }
918
    }
919
919
920
    P_AddWeaponAmmoCommon(pPlayer, weaponNum, nAmount);
920
    P_AddWeaponAmmoCommon(pPlayer, weaponNum, nAmount);
921
}
921
}
922
922
923
static void VM_AddInventory(DukePlayer_t * const pPlayer, int const itemNum, int const nAmount)
923
static void VM_AddInventory(DukePlayer_t * const pPlayer, int const itemNum, int const nAmount)
924
{
924
{
925
    switch (itemNum)
925
    switch (itemNum)
926
    {
926
    {
927
    case GET_STEROIDS:
927
    case GET_STEROIDS:
928
    case GET_SCUBA:
928
    case GET_SCUBA:
929
    case GET_HOLODUKE:
929
    case GET_HOLODUKE:
930
    case GET_JETPACK:
930
    case GET_JETPACK:
931
    case GET_HEATS:
931
    case GET_HEATS:
932
    case GET_FIRSTAID:
932
    case GET_FIRSTAID:
933
    case GET_BOOTS:
933
    case GET_BOOTS:
934
        pPlayer->inven_icon = inv_to_icon[itemNum];
934
        pPlayer->inven_icon = inv_to_icon[itemNum];
935
        pPlayer->inv_amount[itemNum] = nAmount;
935
        pPlayer->inv_amount[itemNum] = nAmount;
936
        break;
936
        break;
937
937
938
    case GET_SHIELD:
938
    case GET_SHIELD:
939
    {
939
    {
940
        int16_t & shield_amount = pPlayer->inv_amount[GET_SHIELD];
940
        int16_t & shield_amount = pPlayer->inv_amount[GET_SHIELD];
941
        shield_amount = min(shield_amount + nAmount, pPlayer->max_shield_amount);
941
        shield_amount = min(shield_amount + nAmount, pPlayer->max_shield_amount);
942
        break;
942
        break;
943
    }
943
    }
944
944
945
    case GET_ACCESS:
945
    case GET_ACCESS:
946
        switch (vm.pSprite->pal)
946
        switch (vm.pSprite->pal)
947
        {
947
        {
948
                case 0: pPlayer->got_access |= 1; break;
948
                case 0: pPlayer->got_access |= 1; break;
949
                case 21: pPlayer->got_access |= 2; break;
949
                case 21: pPlayer->got_access |= 2; break;
950
                case 23: pPlayer->got_access |= 4; break;
950
                case 23: pPlayer->got_access |= 4; break;
951
        }
951
        }
952
        break;
952
        break;
953
953
954
        default: CON_ERRPRINTF("invalid inventory item %d\n", itemNum); break;
954
        default: CON_ERRPRINTF("invalid inventory item %d\n", itemNum); break;
955
    }
955
    }
956
}
956
}
957
#endif
957
#endif
958
958
959
static int A_GetVerticalVel(actor_t const * const pActor)
959
static int A_GetVerticalVel(actor_t const * const pActor)
960
{
960
{
961
#ifdef LUNATIC
961
#ifdef LUNATIC
962
    return pActor->mv.vvel;
962
    return pActor->mv.vvel;
963
#else
963
#else
964
    int32_t moveScriptOfs = AC_MOVE_ID(pActor->t_data);
964
    int32_t moveScriptOfs = AC_MOVE_ID(pActor->t_data);
965
965
966
    return ((unsigned) moveScriptOfs < (unsigned) g_scriptSize - 1) ? apScript[moveScriptOfs + 1] : 0;
966
    return ((unsigned) moveScriptOfs < (unsigned) g_scriptSize - 1) ? apScript[moveScriptOfs + 1] : 0;
967
#endif
967
#endif
968
}
968
}
969
969
970
static int32_t A_GetWaterZOffset(int const spriteNum)
970
static int32_t A_GetWaterZOffset(int const spriteNum)
971
{
971
{
972
    auto const pSprite = (uspriteptr_t)&sprite[spriteNum];
972
    auto const pSprite = (uspriteptr_t)&sprite[spriteNum];
973
    auto const pActor  = &actor[spriteNum];
973
    auto const pActor  = &actor[spriteNum];
974
974
975
    if (sector[pSprite->sectnum].lotag == ST_1_ABOVE_WATER)
975
    if (sector[pSprite->sectnum].lotag == ST_1_ABOVE_WATER)
976
    {
976
    {
977
        if (A_CheckSpriteFlags(spriteNum, SFLAG_NOWATERDIP))
977
        if (A_CheckSpriteFlags(spriteNum, SFLAG_NOWATERDIP))
978
            return 0;
978
            return 0;
979
979
980
        // fix for flying/jumping monsters getting stuck in water
980
        // fix for flying/jumping monsters getting stuck in water
981
        if ((AC_MOVFLAGS(pSprite, pActor) & jumptoplayer_only) || (G_HaveActor(pSprite->picnum) && A_GetVerticalVel(pActor) != 0))
981
        if ((AC_MOVFLAGS(pSprite, pActor) & jumptoplayer_only) || (G_HaveActor(pSprite->picnum) && A_GetVerticalVel(pActor) != 0))
982
            return 0;
982
            return 0;
983
983
984
        return ACTOR_ONWATER_ADDZ;
984
        return ACTOR_ONWATER_ADDZ;
985
    }
985
    }
986
986
987
    return 0;
987
    return 0;
988
}
988
}
989
989
990
static void VM_Fall(int const spriteNum, spritetype * const pSprite)
990
static void VM_Fall(int const spriteNum, spritetype * const pSprite)
991
{
991
{
992
    int spriteGravity = g_spriteGravity;
992
    int spriteGravity = g_spriteGravity;
993
993
994
    pSprite->xoffset = pSprite->yoffset = 0;
994
    pSprite->xoffset = pSprite->yoffset = 0;
995
995
996
    if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER || EDUKE32_PREDICT_FALSE(G_CheckForSpaceCeiling(pSprite->sectnum)))
996
    if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER || EDUKE32_PREDICT_FALSE(G_CheckForSpaceCeiling(pSprite->sectnum)))
997
        spriteGravity = g_spriteGravity/6;
997
        spriteGravity = g_spriteGravity/6;
998
    else if (EDUKE32_PREDICT_FALSE(G_CheckForSpaceFloor(pSprite->sectnum)))
998
    else if (EDUKE32_PREDICT_FALSE(G_CheckForSpaceFloor(pSprite->sectnum)))
999
        spriteGravity = 0;
999
        spriteGravity = 0;
1000
1000
1001
    if (!actor[spriteNum].cgg-- || (sector[pSprite->sectnum].floorstat&2))
1001
    if (!actor[spriteNum].cgg-- || (sector[pSprite->sectnum].floorstat&2))
1002
        actor[spriteNum].cgg = 3;
1002
        actor[spriteNum].cgg = 3;
1003
1003
1004
    A_GetZLimits(spriteNum);
1004
    A_GetZLimits(spriteNum);
1005
1005
1006
    if (pSprite->z < actor[spriteNum].floorz-ACTOR_FLOOR_OFFSET)
1006
    if (pSprite->z < actor[spriteNum].floorz-ACTOR_FLOOR_OFFSET)
1007
    {
1007
    {
1008
        // Free fall.
1008
        // Free fall.
1009
        pSprite->zvel = min(pSprite->zvel+spriteGravity, ACTOR_MAXFALLINGZVEL);
1009
        pSprite->zvel = min(pSprite->zvel+spriteGravity, ACTOR_MAXFALLINGZVEL);
1010
        int newZ = pSprite->z + pSprite->zvel;
1010
        int newZ = pSprite->z + pSprite->zvel;
1011
1011
1012
#ifdef YAX_ENABLE
1012
#ifdef YAX_ENABLE
1013
        if (yax_getbunch(pSprite->sectnum, YAX_FLOOR) >= 0 && (sector[pSprite->sectnum].floorstat & 512) == 0)
1013
        if (yax_getbunch(pSprite->sectnum, YAX_FLOOR) >= 0 && (sector[pSprite->sectnum].floorstat & 512) == 0)
1014
            setspritez(spriteNum, &pSprite->pos);
1014
            setspritez(spriteNum, &pSprite->pos);
1015
        else
1015
        else
1016
#endif
1016
#endif
1017
            if (newZ > actor[spriteNum].floorz - ACTOR_FLOOR_OFFSET)
1017
            if (newZ > actor[spriteNum].floorz - ACTOR_FLOOR_OFFSET)
1018
                newZ = actor[spriteNum].floorz - ACTOR_FLOOR_OFFSET;
1018
                newZ = actor[spriteNum].floorz - ACTOR_FLOOR_OFFSET;
1019
1019
1020
        pSprite->z = newZ;
1020
        pSprite->z = newZ;
1021
        return;
1021
        return;
1022
    }
1022
    }
1023
1023
1024
    // Preliminary new z position of the actor.
1024
    // Preliminary new z position of the actor.
1025
    int newZ = actor[spriteNum].floorz - ACTOR_FLOOR_OFFSET;
1025
    int newZ = actor[spriteNum].floorz - ACTOR_FLOOR_OFFSET;
1026
1026
1027
    if (A_CheckEnemySprite(pSprite) || (pSprite->picnum == APLAYER && pSprite->owner >= 0))
1027
    if (A_CheckEnemySprite(pSprite) || (pSprite->picnum == APLAYER && pSprite->owner >= 0))
1028
    {
1028
    {
1029
        if (pSprite->zvel > 3084 && pSprite->extra <= 1)
1029
        if (pSprite->zvel > 3084 && pSprite->extra <= 1)
1030
        {
1030
        {
1031
            // I'm guessing this DRONE check is from a beta version of the game
1031
            // I'm guessing this DRONE check is from a beta version of the game
1032
            // where they crashed into the ground when killed
1032
            // where they crashed into the ground when killed
1033
#ifndef EDUKE32_STANDALONE
1033
#ifndef EDUKE32_STANDALONE
1034
            if (!FURY && !(pSprite->picnum == APLAYER && pSprite->extra > 0) && pSprite->pal != 1 && pSprite->picnum != DRONE)
1034
            if (!FURY && !(pSprite->picnum == APLAYER && pSprite->extra > 0) && pSprite->pal != 1 && pSprite->picnum != DRONE)
1035
            {
1035
            {
1036
                A_DoGuts(spriteNum,JIBS6,15);
1036
                A_DoGuts(spriteNum,JIBS6,15);
1037
                A_PlaySound(SQUISHED,spriteNum);
1037
                A_PlaySound(SQUISHED,spriteNum);
1038
                A_Spawn(spriteNum,BLOODPOOL);
1038
                A_Spawn(spriteNum,BLOODPOOL);
1039
            }
1039
            }
1040
#endif
1040
#endif
1041
            actor[spriteNum].picnum = SHOTSPARK1;
1041
            actor[spriteNum].picnum = SHOTSPARK1;
1042
            actor[spriteNum].extra = 1;
1042
            actor[spriteNum].extra = 1;
1043
            pSprite->zvel = 0;
1043
            pSprite->zvel = 0;
1044
        }
1044
        }
1045
        else if (pSprite->zvel > 2048 && sector[pSprite->sectnum].lotag != ST_1_ABOVE_WATER)
1045
        else if (pSprite->zvel > 2048 && sector[pSprite->sectnum].lotag != ST_1_ABOVE_WATER)
1046
        {
1046
        {
1047
            int16_t newsect = pSprite->sectnum;
1047
            int16_t newsect = pSprite->sectnum;
1048
1048
1049
            pushmove(&pSprite->pos, &newsect, 128, 4<<8, 4<<8, CLIPMASK0);
1049
            pushmove(&pSprite->pos, &newsect, 128, 4<<8, 4<<8, CLIPMASK0);
1050
            if ((unsigned)newsect < MAXSECTORS)
1050
            if ((unsigned)newsect < MAXSECTORS)
1051
                changespritesect(spriteNum, newsect);
1051
                changespritesect(spriteNum, newsect);
1052
1052
-
 
1053
#ifndef EDUKE32_STANDALONE
-
 
1054
            if (!FURY)
1053
            A_PlaySound(THUD, spriteNum);
1055
                A_PlaySound(THUD, spriteNum);
-
 
1056
#endif
1054
        }
1057
        }
1055
    }
1058
    }
1056
1059
1057
    if (sector[pSprite->sectnum].lotag == ST_1_ABOVE_WATER && actor[spriteNum].floorz == getcorrectflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y))
1060
    if (sector[pSprite->sectnum].lotag == ST_1_ABOVE_WATER && actor[spriteNum].floorz == getcorrectflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y))
1058
    {
1061
    {
1059
        pSprite->z = newZ + A_GetWaterZOffset(spriteNum);
1062
        pSprite->z = newZ + A_GetWaterZOffset(spriteNum);
1060
        return;
1063
        return;
1061
    }
1064
    }
1062
1065
1063
    pSprite->z = newZ;
1066
    pSprite->z = newZ;
1064
    pSprite->zvel = 0;
1067
    pSprite->zvel = 0;
1065
}
1068
}
1066
1069
1067
static int32_t VM_ResetPlayer(int const playerNum, int32_t vmFlags, int32_t const resetFlags)
1070
static int32_t VM_ResetPlayer(int const playerNum, int32_t vmFlags, int32_t const resetFlags)
1068
{
1071
{
1069
    //AddLog("resetplayer");
1072
    //AddLog("resetplayer");
1070
    if (!g_netServer && ud.multimode < 2 && !(resetFlags & 2))
1073
    if (!g_netServer && ud.multimode < 2 && !(resetFlags & 2))
1071
    {
1074
    {
1072
        if (g_quickload && g_quickload->isValid() && ud.recstat != 2 && !(resetFlags & 8))
1075
        if (g_quickload && g_quickload->isValid() && ud.recstat != 2 && !(resetFlags & 8))
1073
        {
1076
        {
1074
            if (resetFlags & 4)
1077
            if (resetFlags & 4)
1075
            {
1078
            {
1076
                KB_FlushKeyboardQueue();
1079
                KB_FlushKeyboardQueue();
1077
                KB_ClearKeysDown();
1080
                KB_ClearKeysDown();
1078
                FX_StopAllSounds();
1081
                FX_StopAllSounds();
1079
                S_ClearSoundLocks();
1082
                S_ClearSoundLocks();
1080
                if (G_LoadPlayerMaybeMulti(*g_quickload) != 0)
1083
                if (G_LoadPlayerMaybeMulti(*g_quickload) != 0)
1081
                {
1084
                {
1082
                    g_quickload->reset();
1085
                    g_quickload->reset();
1083
                    goto QuickLoadFailure;
1086
                    goto QuickLoadFailure;
1084
                }
1087
                }
1085
            }
1088
            }
1086
            else if (!(resetFlags & 1))
1089
            else if (!(resetFlags & 1))
1087
            {
1090
            {
1088
                Menu_Open(playerNum);
1091
                Menu_Open(playerNum);
1089
                KB_ClearKeyDown(sc_Space);
1092
                KB_ClearKeyDown(sc_Space);
1090
                I_AdvanceTriggerClear();
1093
                I_AdvanceTriggerClear();
1091
                Menu_Change(MENU_RESETPLAYER);
1094
                Menu_Change(MENU_RESETPLAYER);
1092
            }
1095
            }
1093
        }
1096
        }
1094
        else
1097
        else
1095
        {
1098
        {
1096
            QuickLoadFailure:
1099
            QuickLoadFailure:
1097
            g_player[playerNum].ps->gm = MODE_RESTART;
1100
            g_player[playerNum].ps->gm = MODE_RESTART;
1098
        }
1101
        }
1099
#if !defined LUNATIC
1102
#if !defined LUNATIC
1100
        vmFlags |= VM_NOEXECUTE;
1103
        vmFlags |= VM_NOEXECUTE;
1101
#endif
1104
#endif
1102
    }
1105
    }
1103
    else
1106
    else
1104
    {
1107
    {
1105
        if (playerNum == myconnectindex)
1108
        if (playerNum == myconnectindex)
1106
        {
1109
        {
1107
            CAMERADIST = 0;
1110
            CAMERADIST = 0;
1108
            CAMERACLOCK = (int32_t) totalclock;
1111
            CAMERACLOCK = (int32_t) totalclock;
1109
        }
1112
        }
1110
1113
1111
        if (g_fakeMultiMode)
1114
        if (g_fakeMultiMode)
1112
            P_ResetMultiPlayer(playerNum);
1115
            P_ResetMultiPlayer(playerNum);
1113
#ifndef NETCODE_DISABLE
1116
#ifndef NETCODE_DISABLE
1114
        if (g_netServer)
1117
        if (g_netServer)
1115
        {
1118
        {
1116
            P_ResetMultiPlayer(playerNum);
1119
            P_ResetMultiPlayer(playerNum);
1117
            Net_SpawnPlayer(playerNum);
1120
            Net_SpawnPlayer(playerNum);
1118
        }
1121
        }
1119
#endif
1122
#endif
1120
    }
1123
    }
1121
1124
1122
    P_UpdateScreenPal(g_player[playerNum].ps);
1125
    P_UpdateScreenPal(g_player[playerNum].ps);
1123
    //AddLog("EOF: resetplayer");
1126
    //AddLog("EOF: resetplayer");
1124
1127
1125
    return vmFlags;
1128
    return vmFlags;
1126
}
1129
}
1127
1130
1128
void G_GetTimeDate(int32_t * const pValues)
1131
void G_GetTimeDate(int32_t * const pValues)
1129
{
1132
{
1130
    time_t timeStruct;
1133
    time_t timeStruct;
1131
    time(&timeStruct);
1134
    time(&timeStruct);
1132
    struct tm *pTime = localtime(&timeStruct);
1135
    struct tm *pTime = localtime(&timeStruct);
1133
1136
1134
    // initprintf("Time&date: %s\n",asctime (ti));
1137
    // initprintf("Time&date: %s\n",asctime (ti));
1135
1138
1136
    pValues[0] = pTime->tm_sec;
1139
    pValues[0] = pTime->tm_sec;
1137
    pValues[1] = pTime->tm_min;
1140
    pValues[1] = pTime->tm_min;
1138
    pValues[2] = pTime->tm_hour;
1141
    pValues[2] = pTime->tm_hour;
1139
    pValues[3] = pTime->tm_mday;
1142
    pValues[3] = pTime->tm_mday;
1140
    pValues[4] = pTime->tm_mon;
1143
    pValues[4] = pTime->tm_mon;
1141
    pValues[5] = pTime->tm_year+1900;
1144
    pValues[5] = pTime->tm_year+1900;
1142
    pValues[6] = pTime->tm_wday;
1145
    pValues[6] = pTime->tm_wday;
1143
    pValues[7] = pTime->tm_yday;
1146
    pValues[7] = pTime->tm_yday;
1144
}
1147
}
1145
1148
1146
static int G_StartTrackSlot(int const volumeNum, int const levelNum)
1149
static int G_StartTrackSlot(int const volumeNum, int const levelNum)
1147
{
1150
{
1148
    if ((unsigned)volumeNum <= MAXVOLUMES && (unsigned)levelNum < MAXLEVELS)
1151
    if ((unsigned)volumeNum <= MAXVOLUMES && (unsigned)levelNum < MAXLEVELS)
1149
    {
1152
    {
1150
        int trackNum = MAXLEVELS*volumeNum + levelNum;
1153
        int trackNum = MAXLEVELS*volumeNum + levelNum;
1151
1154
1152
        return S_TryPlaySpecialMusic(trackNum);
1155
        return S_TryPlaySpecialMusic(trackNum);
1153
    }
1156
    }
1154
1157
1155
    return 1;
1158
    return 1;
1156
}
1159
}
1157
1160
1158
#ifndef LUNATIC
1161
#ifndef LUNATIC
1159
static int G_StartTrackSlotWrap(int const volumeNum, int const levelNum)
1162
static int G_StartTrackSlotWrap(int const volumeNum, int const levelNum)
1160
{
1163
{
1161
    if (EDUKE32_PREDICT_FALSE(G_StartTrackSlot(volumeNum, levelNum)))
1164
    if (EDUKE32_PREDICT_FALSE(G_StartTrackSlot(volumeNum, levelNum)))
1162
    {
1165
    {
1163
        CON_ERRPRINTF("invalid level %d or null music for volume %d level %d\n", levelNum, volumeNum, levelNum);
1166
        CON_ERRPRINTF("invalid level %d or null music for volume %d level %d\n", levelNum, volumeNum, levelNum);
1164
        return 1;
1167
        return 1;
1165
    }
1168
    }
1166
1169
1167
    return 0;
1170
    return 0;
1168
}
1171
}
1169
#else
1172
#else
1170
int G_StartTrack(int const levelNum) { return G_StartTrackSlot(ud.volume_number, levelNum); }
1173
int G_StartTrack(int const levelNum) { return G_StartTrackSlot(ud.volume_number, levelNum); }
1171
#endif
1174
#endif
1172
1175
1173
LUNATIC_EXTERN void G_ShowView(vec3_t vec, fix16_t a, fix16_t horiz, int sect, int ix1, int iy1, int ix2, int iy2, int unbiasedp)
1176
LUNATIC_EXTERN void G_ShowView(vec3_t vec, fix16_t a, fix16_t horiz, int sect, int ix1, int iy1, int ix2, int iy2, int unbiasedp)
1174
{
1177
{
1175
    int x1 = min(ix1, ix2);
1178
    int x1 = min(ix1, ix2);
1176
    int x2 = max(ix1, ix2);
1179
    int x2 = max(ix1, ix2);
1177
    int y1 = min(iy1, iy2);
1180
    int y1 = min(iy1, iy2);
1178
    int y2 = max(iy1, iy2);
1181
    int y2 = max(iy1, iy2);
1179
1182
1180
    if (!unbiasedp)
1183
    if (!unbiasedp)
1181
    {
1184
    {
1182
        // The showview command has a rounding bias towards zero,
1185
        // The showview command has a rounding bias towards zero,
1183
        // e.g. floor((319*1680)/320) == 1674
1186
        // e.g. floor((319*1680)/320) == 1674
1184
        x1 = scale(x1,xdim,320);
1187
        x1 = scale(x1,xdim,320);
1185
        y1 = scale(y1,ydim,200);
1188
        y1 = scale(y1,ydim,200);
1186
        x2 = scale(x2,xdim,320);
1189
        x2 = scale(x2,xdim,320);
1187
        y2 = scale(y2,ydim,200);
1190
        y2 = scale(y2,ydim,200);
1188
    }
1191
    }
1189
    else
1192
    else
1190
    {
1193
    {
1191
        // This will map the maximum 320-based coordinate to the
1194
        // This will map the maximum 320-based coordinate to the
1192
        // maximum real screen coordinate:
1195
        // maximum real screen coordinate:
1193
        // floor((319*1679)/319) == 1679
1196
        // floor((319*1679)/319) == 1679
1194
        x1 = scale(x1,xdim-1,319);
1197
        x1 = scale(x1,xdim-1,319);
1195
        y1 = scale(y1,ydim-1,199);
1198
        y1 = scale(y1,ydim-1,199);
1196
        x2 = scale(x2,xdim-1,319);
1199
        x2 = scale(x2,xdim-1,319);
1197
        y2 = scale(y2,ydim-1,199);
1200
        y2 = scale(y2,ydim-1,199);
1198
    }
1201
    }
1199
1202
1200
    horiz = fix16_clamp(horiz, F16(HORIZ_MIN), F16(HORIZ_MAX));
1203
    horiz = fix16_clamp(horiz, F16(HORIZ_MIN), F16(HORIZ_MAX));
1201
1204
1202
    int const viewingRange = viewingrange;
1205
    int const viewingRange = viewingrange;
1203
    int const yxAspect = yxaspect;
1206
    int const yxAspect = yxaspect;
1204
1207
1205
    videoSetViewableArea(x1,y1,x2,y2);
1208
    videoSetViewableArea(x1,y1,x2,y2);
1206
    renderSetAspect(viewingRange, yxAspect);
1209
    renderSetAspect(viewingRange, yxAspect);
1207
    int const smoothratio = calc_smoothratio(totalclock, ototalclock);
1210
    int const smoothratio = calc_smoothratio(totalclock, ototalclock);
1208
    G_DoInterpolations(smoothratio);
1211
    G_DoInterpolations(smoothratio);
1209
    if (!display_mirror)
1212
    if (!display_mirror)
1210
        G_HandleMirror(vec.x, vec.y, vec.z, a, horiz, smoothratio);
1213
        G_HandleMirror(vec.x, vec.y, vec.z, a, horiz, smoothratio);
1211
#ifdef POLYMER
1214
#ifdef POLYMER
1212
    if (videoGetRenderMode() == REND_POLYMER)
1215
    if (videoGetRenderMode() == REND_POLYMER)
1213
        polymer_setanimatesprites(G_DoSpriteAnimations, vec.x, vec.y, vec.z, fix16_to_int(a), smoothratio);
1216
        polymer_setanimatesprites(G_DoSpriteAnimations, vec.x, vec.y, vec.z, fix16_to_int(a), smoothratio);
1214
#endif
1217
#endif
1215
    yax_preparedrawrooms();
1218
    yax_preparedrawrooms();
1216
    renderDrawRoomsQ16(vec.x, vec.y, vec.z, a, horiz, sect);
1219
    renderDrawRoomsQ16(vec.x, vec.y, vec.z, a, horiz, sect);
1217
    yax_drawrooms(G_DoSpriteAnimations, sect, 0, smoothratio);
1220
    yax_drawrooms(G_DoSpriteAnimations, sect, 0, smoothratio);
1218
1221
1219
    display_mirror = 2;
1222
    display_mirror = 2;
1220
    G_DoSpriteAnimations(vec.x, vec.y, vec.z, fix16_to_int(a), smoothratio);
1223
    G_DoSpriteAnimations(vec.x, vec.y, vec.z, fix16_to_int(a), smoothratio);
1221
    display_mirror = 0;
1224
    display_mirror = 0;
1222
    renderDrawMasks();
1225
    renderDrawMasks();
1223
    G_RestoreInterpolations();
1226
    G_RestoreInterpolations();
1224
    G_UpdateScreenArea();
1227
    G_UpdateScreenArea();
1225
    renderSetAspect(viewingRange, yxAspect);
1228
    renderSetAspect(viewingRange, yxAspect);
1226
}
1229
}
1227
1230
1228
void Screen_Play(void)
1231
void Screen_Play(void)
1229
{
1232
{
1230
    bool running = true;
1233
    bool running = true;
1231
1234
1232
    I_ClearAllInput();
1235
    I_ClearAllInput();
1233
1236
1234
    do
1237
    do
1235
    {
1238
    {
1236
        gameHandleEvents();
1239
        gameHandleEvents();
1237
1240
1238
        ototalclock = totalclock + 1; // pause game like ANMs
1241
        ototalclock = totalclock + 1; // pause game like ANMs
1239
1242
1240
        if (!engineFPSLimit())
1243
        if (!engineFPSLimit())
1241
            continue;
1244
            continue;
1242
1245
1243
        videoClearScreen(0);
1246
        videoClearScreen(0);
1244
1247
1245
        if (VM_OnEventWithReturn(EVENT_SCREEN, -1, myconnectindex, I_CheckAllInput()))
1248
        if (VM_OnEventWithReturn(EVENT_SCREEN, -1, myconnectindex, I_CheckAllInput()))
1246
            running = false;
1249
            running = false;
1247
1250
1248
        videoNextPage();
1251
        videoNextPage();
1249
        I_ClearAllInput();
1252
        I_ClearAllInput();
1250
    } while (running);
1253
    } while (running);
1251
}
1254
}
1252
1255
1253
static void SetArray(int const arrayNum, int const arrayIndex, int const newValue)
1256
static void SetArray(int const arrayNum, int const arrayIndex, int const newValue)
1254
{
1257
{
1255
    if (EDUKE32_PREDICT_FALSE((unsigned)arrayNum >= (unsigned)g_gameArrayCount || (unsigned)arrayIndex >= (unsigned)aGameArrays[arrayNum].size))
1258
    if (EDUKE32_PREDICT_FALSE((unsigned)arrayNum >= (unsigned)g_gameArrayCount || (unsigned)arrayIndex >= (unsigned)aGameArrays[arrayNum].size))
1256
    {
1259
    {
1257
        OSD_Printf(OSD_ERROR "Gv_SetVar(): tried to set invalid array %d or index out of bounds from "
1260
        OSD_Printf(OSD_ERROR "Gv_SetVar(): tried to set invalid array %d or index out of bounds from "
1258
                             "sprite %d (%d), player %d\n",
1261
                             "sprite %d (%d), player %d\n",
1259
                   (int)arrayNum, vm.spriteNum, vm.pUSprite->picnum, vm.playerNum);
1262
                   (int)arrayNum, vm.spriteNum, vm.pUSprite->picnum, vm.playerNum);
1260
        vm.flags |= VM_RETURN;
1263
        vm.flags |= VM_RETURN;
1261
        return;
1264
        return;
1262
    }
1265
    }
1263
1266
1264
    auto &arr = aGameArrays[arrayNum];
1267
    auto &arr = aGameArrays[arrayNum];
1265
1268
1266
    if (EDUKE32_PREDICT_FALSE(arr.flags & GAMEARRAY_READONLY))
1269
    if (EDUKE32_PREDICT_FALSE(arr.flags & GAMEARRAY_READONLY))
1267
    {
1270
    {
1268
        OSD_Printf(OSD_ERROR "Tried to set value in read-only array `%s'", arr.szLabel);
1271
        OSD_Printf(OSD_ERROR "Tried to set value in read-only array `%s'", arr.szLabel);
1269
        vm.flags |= VM_RETURN;
1272
        vm.flags |= VM_RETURN;
1270
        return;
1273
        return;
1271
    }
1274
    }
1272
1275
1273
    switch (arr.flags & GAMEARRAY_TYPE_MASK)
1276
    switch (arr.flags & GAMEARRAY_TYPE_MASK)
1274
    {
1277
    {
1275
        case 0: arr.pValues[arrayIndex]                              = newValue; break;
1278
        case 0: arr.pValues[arrayIndex]                              = newValue; break;
1276
        case GAMEARRAY_INT16: ((int16_t *)arr.pValues)[arrayIndex]   = newValue; break;
1279
        case GAMEARRAY_INT16: ((int16_t *)arr.pValues)[arrayIndex]   = newValue; break;
1277
        case GAMEARRAY_INT8: ((int8_t *)arr.pValues)[arrayIndex]     = newValue; break;
1280
        case GAMEARRAY_INT8: ((int8_t *)arr.pValues)[arrayIndex]     = newValue; break;
1278
        case GAMEARRAY_UINT16: ((uint16_t *)arr.pValues)[arrayIndex] = newValue; break;
1281
        case GAMEARRAY_UINT16: ((uint16_t *)arr.pValues)[arrayIndex] = newValue; break;
1279
        case GAMEARRAY_UINT8: ((int8_t *)arr.pValues)[arrayIndex]    = newValue; break;
1282
        case GAMEARRAY_UINT8: ((int8_t *)arr.pValues)[arrayIndex]    = newValue; break;
1280
        case GAMEARRAY_BITMAP:
1283
        case GAMEARRAY_BITMAP:
1281
        {
1284
        {
1282
            uint32_t const mask  = pow2char[arrayIndex&7];
1285
            uint32_t const mask  = pow2char[arrayIndex&7];
1283
            uint8_t &value = ((uint8_t *)arr.pValues)[arrayIndex>>3];
1286
            uint8_t &value = ((uint8_t *)arr.pValues)[arrayIndex>>3];
1284
            value = (value & ~mask) | (-!!newValue & mask);
1287
            value = (value & ~mask) | (-!!newValue & mask);
1285
            break;
1288
            break;
1286
        }
1289
        }
1287
    }
1290
    }
1288
}
1291
}
1289
1292
1290
static void ResizeArray(int const arrayNum, int const newSize)
1293
static void ResizeArray(int const arrayNum, int const newSize)
1291
{
1294
{
1292
    auto &arr = aGameArrays[arrayNum];
1295
    auto &arr = aGameArrays[arrayNum];
1293
1296
1294
    int const oldSize = arr.size;
1297
    int const oldSize = arr.size;
1295
1298
1296
    if (newSize == oldSize || newSize < 0)
1299
    if (newSize == oldSize || newSize < 0)
1297
        return;
1300
        return;
1298
#if 0
1301
#if 0
1299
    OSD_Printf(OSDTEXT_GREEN "CON_RESIZEARRAY: resizing array %s from %d to %d\n",
1302
    OSD_Printf(OSDTEXT_GREEN "CON_RESIZEARRAY: resizing array %s from %d to %d\n",
1300
               array.szLabel, array.size, newSize);
1303
               array.szLabel, array.size, newSize);
1301
#endif
1304
#endif
1302
    if (newSize == 0)
1305
    if (newSize == 0)
1303
    {
1306
    {
1304
        Xaligned_free(arr.pValues);
1307
        Xaligned_free(arr.pValues);
1305
        arr.pValues = nullptr;
1308
        arr.pValues = nullptr;
1306
        arr.size = 0;
1309
        arr.size = 0;
1307
        return;
1310
        return;
1308
    }
1311
    }
1309
1312
1310
    size_t const oldBytes = Gv_GetArrayAllocSizeForCount(arrayNum, oldSize);
1313
    size_t const oldBytes = Gv_GetArrayAllocSizeForCount(arrayNum, oldSize);
1311
    size_t const newBytes = Gv_GetArrayAllocSizeForCount(arrayNum, newSize);
1314
    size_t const newBytes = Gv_GetArrayAllocSizeForCount(arrayNum, newSize);
1312
1315
1313
    auto const oldArray = arr.pValues;
1316
    auto const oldArray = arr.pValues;
1314
    auto const newArray = (intptr_t *)Xaligned_alloc(ARRAY_ALIGNMENT, newBytes);
1317
    auto const newArray = (intptr_t *)Xaligned_alloc(ARRAY_ALIGNMENT, newBytes);
1315
1318
1316
    if (oldSize != 0)
1319
    if (oldSize != 0)
1317
        Bmemcpy(newArray, oldArray, min(oldBytes, newBytes));
1320
        Bmemcpy(newArray, oldArray, min(oldBytes, newBytes));
1318
1321
1319
    if (newSize > oldSize)
1322
    if (newSize > oldSize)
1320
        Bmemset((char *)newArray + oldBytes, 0, newBytes - oldBytes);
1323
        Bmemset((char *)newArray + oldBytes, 0, newBytes - oldBytes);
1321
1324
1322
    arr.pValues = newArray;
1325
    arr.pValues = newArray;
1323
    arr.size = newSize;
1326
    arr.size = newSize;
1324
1327
1325
    Xaligned_free(oldArray);
1328
    Xaligned_free(oldArray);
1326
}
1329
}
1327
1330
1328
#if !defined LUNATIC
1331
#if !defined LUNATIC
1329
#if defined __GNUC__ || defined __clang__
1332
#if defined __GNUC__ || defined __clang__
1330
# define CON_USE_COMPUTED_GOTO
1333
# define CON_USE_COMPUTED_GOTO
1331
#endif
1334
#endif
1332
1335
1333
#ifdef CON_USE_COMPUTED_GOTO
1336
#ifdef CON_USE_COMPUTED_GOTO
1334
# define vInstruction(KEYWORDID) VINST_ ## KEYWORDID
1337
# define vInstruction(KEYWORDID) VINST_ ## KEYWORDID
1335
# define vmErrorCase VINST_CON_OPCODE_END
1338
# define vmErrorCase VINST_CON_OPCODE_END
1336
# define eval(INSTRUCTION) { goto *jumpTable[min<uint16_t>(INSTRUCTION, CON_OPCODE_END)]; }
1339
# define eval(INSTRUCTION) { goto *jumpTable[min<uint16_t>(INSTRUCTION, CON_OPCODE_END)]; }
1337
# define dispatch_unconditionally(...) { g_tw = tw = *insptr; eval((VM_DECODE_INST(tw))) }
1340
# define dispatch_unconditionally(...) { g_tw = tw = *insptr; eval((VM_DECODE_INST(tw))) }
1338
# define dispatch(...) { if (vm_execution_depth && (vm.flags & (VM_RETURN|VM_KILL|VM_NOEXECUTE)) == 0) dispatch_unconditionally(__VA_ARGS__); return; }
1341
# define dispatch(...) { if (vm_execution_depth && (vm.flags & (VM_RETURN|VM_KILL|VM_NOEXECUTE)) == 0) dispatch_unconditionally(__VA_ARGS__); return; }
1339
# define abort_after_error(...) return
1342
# define abort_after_error(...) return
1340
# define vInstructionPointer(KEYWORDID) &&VINST_ ## KEYWORDID
1343
# define vInstructionPointer(KEYWORDID) &&VINST_ ## KEYWORDID
1341
# define COMMA ,
1344
# define COMMA ,
1342
# define JUMP_TABLE_ARRAY_LITERAL { TRANSFORM_SCRIPT_KEYWORDS_LIST(vInstructionPointer, COMMA) }
1345
# define JUMP_TABLE_ARRAY_LITERAL { TRANSFORM_SCRIPT_KEYWORDS_LIST(vInstructionPointer, COMMA) }
1343
#else
1346
#else
1344
# define vInstruction(KEYWORDID) case KEYWORDID
1347
# define vInstruction(KEYWORDID) case KEYWORDID
1345
# define vmErrorCase default
1348
# define vmErrorCase default
1346
# define dispatch_unconditionally(...) continue
1349
# define dispatch_unconditionally(...) continue
1347
# define dispatch(...) continue
1350
# define dispatch(...) continue
1348
# define eval(INSTRUCTION) switch(INSTRUCTION)
1351
# define eval(INSTRUCTION) switch(INSTRUCTION)
1349
# define abort_after_error(...) continue // non-threaded dispatch handles this in the loop condition in VM_Execute()
1352
# define abort_after_error(...) continue // non-threaded dispatch handles this in the loop condition in VM_Execute()
1350
#endif
1353
#endif
1351
1354
1352
#define VM_ASSERT(condition, ...)                \
1355
#define VM_ASSERT(condition, ...)                \
1353
    do                                           \
1356
    do                                           \
1354
    {                                            \
1357
    {                                            \
1355
        if (EDUKE32_PREDICT_FALSE(!(condition))) \
1358
        if (EDUKE32_PREDICT_FALSE(!(condition))) \
1356
        {                                        \
1359
        {                                        \
1357
            CON_ERRPRINTF(__VA_ARGS__);          \
1360
            CON_ERRPRINTF(__VA_ARGS__);          \
1358
            abort_after_error();                 \
1361
            abort_after_error();                 \
1359
        }                                        \
1362
        }                                        \
1360
    } while (0)
1363
    } while (0)
1361
1364
1362
// be careful when changing this--the assignment used as a condition doubles as a null pointer check
1365
// be careful when changing this--the assignment used as a condition doubles as a null pointer check
1363
#define VM_CONDITIONAL(xxx)                                                                       \
1366
#define VM_CONDITIONAL(xxx)                                                                       \
1364
    do                                                                                            \
1367
    do                                                                                            \
1365
    {                                                                                             \
1368
    {                                                                                             \
1366
        if ((xxx) || ((insptr = (intptr_t *)insptr[1]) && (VM_DECODE_INST(*insptr) == CON_ELSE))) \
1369
        if ((xxx) || ((insptr = (intptr_t *)insptr[1]) && (VM_DECODE_INST(*insptr) == CON_ELSE))) \
1367
        {                                                                                         \
1370
        {                                                                                         \
1368
            insptr += 2;                                                                          \
1371
            insptr += 2;                                                                          \
1369
            VM_Execute();                                                                         \
1372
            VM_Execute();                                                                         \
1370
        }                                                                                         \
1373
        }                                                                                         \
1371
    } while (0)
1374
    } while (0)
1372
1375
1373
GAMEEXEC_STATIC void VM_Execute(int const loop /*= false*/)
1376
GAMEEXEC_STATIC void VM_Execute(int const loop /*= false*/)
1374
{
1377
{
1375
    int vm_execution_depth = loop;
1378
    int vm_execution_depth = loop;
1376
#ifdef CON_USE_COMPUTED_GOTO
1379
#ifdef CON_USE_COMPUTED_GOTO
1377
    static void *const jumpTable[] = JUMP_TABLE_ARRAY_LITERAL;
1380
    static void *const jumpTable[] = JUMP_TABLE_ARRAY_LITERAL;
1378
#else
1381
#else
1379
    do
1382
    do
1380
    {
1383
    {
1381
#endif
1384
#endif
1382
        int32_t tw = *insptr;
1385
        int32_t tw = *insptr;
1383
        g_tw = tw;
1386
        g_tw = tw;
1384
1387
1385
        eval(VM_DECODE_INST(tw))
1388
        eval(VM_DECODE_INST(tw))
1386
        {
1389
        {
1387
            vInstruction(CON_LEFTBRACE):
1390
            vInstruction(CON_LEFTBRACE):
1388
            {
1391
            {
1389
                insptr++, vm_execution_depth++;
1392
                insptr++, vm_execution_depth++;
1390
                dispatch_unconditionally();
1393
                dispatch_unconditionally();
1391
            }
1394
            }
1392
1395
1393
            vInstruction(CON_RIGHTBRACE):
1396
            vInstruction(CON_RIGHTBRACE):
1394
            {
1397
            {
1395
                insptr++, vm_execution_depth--;
1398
                insptr++, vm_execution_depth--;
1396
                dispatch();
1399
                dispatch();
1397
            }
1400
            }
1398
1401
1399
            vInstruction(CON_ELSE):
1402
            vInstruction(CON_ELSE):
1400
            {
1403
            {
1401
                insptr = (intptr_t *)insptr[1];
1404
                insptr = (intptr_t *)insptr[1];
1402
                dispatch_unconditionally();
1405
                dispatch_unconditionally();
1403
            }
1406
            }
1404
1407
1405
            vInstruction(CON_STATE):
1408
            vInstruction(CON_STATE):
1406
            {
1409
            {
1407
                auto tempscrptr = &insptr[2];
1410
                auto tempscrptr = &insptr[2];
1408
                insptr = (intptr_t *)insptr[1];
1411
                insptr = (intptr_t *)insptr[1];
1409
                VM_Execute(true);
1412
                VM_Execute(true);
1410
                insptr = tempscrptr;
1413
                insptr = tempscrptr;
1411
            }
1414
            }
1412
            dispatch();
1415
            dispatch();
1413
1416
1414
#ifdef CON_DISCRETE_VAR_ACCESS
1417
#ifdef CON_DISCRETE_VAR_ACCESS
1415
            vInstruction(CON_IFVARE_GLOBAL):
1418
            vInstruction(CON_IFVARE_GLOBAL):
1416
                insptr++;
1419
                insptr++;
1417
                tw = aGameVars[*insptr++].global;
1420
                tw = aGameVars[*insptr++].global;
1418
                VM_CONDITIONAL(tw == *insptr);
1421
                VM_CONDITIONAL(tw == *insptr);
1419
                dispatch();
1422
                dispatch();
1420
            vInstruction(CON_IFVARN_GLOBAL):
1423
            vInstruction(CON_IFVARN_GLOBAL):
1421
                insptr++;
1424
                insptr++;
1422
                tw = aGameVars[*insptr++].global;
1425
                tw = aGameVars[*insptr++].global;
1423
                VM_CONDITIONAL(tw != *insptr);
1426
                VM_CONDITIONAL(tw != *insptr);
1424
                dispatch();
1427
                dispatch();
1425
            vInstruction(CON_IFVARAND_GLOBAL):
1428
            vInstruction(CON_IFVARAND_GLOBAL):
1426
                insptr++;
1429
                insptr++;
1427
                tw = aGameVars[*insptr++].global;
1430
                tw = aGameVars[*insptr++].global;
1428
                VM_CONDITIONAL(tw & *insptr);
1431
                VM_CONDITIONAL(tw & *insptr);
1429
                dispatch();
1432
                dispatch();
1430
            vInstruction(CON_IFVAROR_GLOBAL):
1433
            vInstruction(CON_IFVAROR_GLOBAL):
1431
                insptr++;
1434
                insptr++;
1432
                tw = aGameVars[*insptr++].global;
1435
                tw = aGameVars[*insptr++].global;
1433
                VM_CONDITIONAL(tw | *insptr);
1436
                VM_CONDITIONAL(tw | *insptr);
1434
                dispatch();
1437
                dispatch();
1435
            vInstruction(CON_IFVARXOR_GLOBAL):
1438
            vInstruction(CON_IFVARXOR_GLOBAL):
1436
                insptr++;
1439
                insptr++;
1437
                tw = aGameVars[*insptr++].global;
1440
                tw = aGameVars[*insptr++].global;
1438
                VM_CONDITIONAL(tw ^ *insptr);
1441
                VM_CONDITIONAL(tw ^ *insptr);
1439
                dispatch();
1442
                dispatch();
1440
            vInstruction(CON_IFVAREITHER_GLOBAL):
1443
            vInstruction(CON_IFVAREITHER_GLOBAL):
1441
                insptr++;
1444
                insptr++;
1442
                tw = aGameVars[*insptr++].global;
1445
                tw = aGameVars[*insptr++].global;
1443
                VM_CONDITIONAL(tw || *insptr);
1446
                VM_CONDITIONAL(tw || *insptr);
1444
                dispatch();
1447
                dispatch();
1445
            vInstruction(CON_IFVARBOTH_GLOBAL):
1448
            vInstruction(CON_IFVARBOTH_GLOBAL):
1446
                insptr++;
1449
                insptr++;
1447
                tw = aGameVars[*insptr++].global;
1450
                tw = aGameVars[*insptr++].global;
1448
                VM_CONDITIONAL(tw && *insptr);
1451
                VM_CONDITIONAL(tw && *insptr);
1449
                dispatch();
1452
                dispatch();
1450
            vInstruction(CON_IFVARG_GLOBAL):
1453
            vInstruction(CON_IFVARG_GLOBAL):
1451
                insptr++;
1454
                insptr++;
1452
                tw = aGameVars[*insptr++].global;
1455
                tw = aGameVars[*insptr++].global;
1453
                VM_CONDITIONAL(tw > *insptr);
1456
                VM_CONDITIONAL(tw > *insptr);
1454
                dispatch();
1457
                dispatch();
1455
            vInstruction(CON_IFVARGE_GLOBAL):
1458
            vInstruction(CON_IFVARGE_GLOBAL):
1456
                insptr++;
1459
                insptr++;
1457
                tw = aGameVars[*insptr++].global;
1460
                tw = aGameVars[*insptr++].global;
1458
                VM_CONDITIONAL(tw >= *insptr);
1461
                VM_CONDITIONAL(tw >= *insptr);
1459
                dispatch();
1462
                dispatch();
1460
            vInstruction(CON_IFVARL_GLOBAL):
1463
            vInstruction(CON_IFVARL_GLOBAL):
1461
                insptr++;
1464
                insptr++;
1462
                tw = aGameVars[*insptr++].global;
1465
                tw = aGameVars[*insptr++].global;
1463
                VM_CONDITIONAL(tw < *insptr);
1466
                VM_CONDITIONAL(tw < *insptr);
1464
                dispatch();
1467
                dispatch();
1465
            vInstruction(CON_IFVARLE_GLOBAL):
1468
            vInstruction(CON_IFVARLE_GLOBAL):
1466
                insptr++;
1469
                insptr++;
1467
                tw = aGameVars[*insptr++].global;
1470
                tw = aGameVars[*insptr++].global;
1468
                VM_CONDITIONAL(tw <= *insptr);
1471
                VM_CONDITIONAL(tw <= *insptr);
1469
                dispatch();
1472
                dispatch();
1470
            vInstruction(CON_IFVARA_GLOBAL):
1473
            vInstruction(CON_IFVARA_GLOBAL):
1471
                insptr++;
1474
                insptr++;
1472
                tw = aGameVars[*insptr++].global;
1475
                tw = aGameVars[*insptr++].global;
1473
                VM_CONDITIONAL((uint32_t)tw > (uint32_t)*insptr);
1476
                VM_CONDITIONAL((uint32_t)tw > (uint32_t)*insptr);
1474
                dispatch();
1477
                dispatch();
1475
            vInstruction(CON_IFVARAE_GLOBAL):
1478
            vInstruction(CON_IFVARAE_GLOBAL):
1476
                insptr++;
1479
                insptr++;
1477
                tw = aGameVars[*insptr++].global;
1480
                tw = aGameVars[*insptr++].global;
1478
                VM_CONDITIONAL((uint32_t)tw >= (uint32_t)*insptr);
1481
                VM_CONDITIONAL((uint32_t)tw >= (uint32_t)*insptr);
1479
                dispatch();
1482
                dispatch();
1480
            vInstruction(CON_IFVARB_GLOBAL):
1483
            vInstruction(CON_IFVARB_GLOBAL):
1481
                insptr++;
1484
                insptr++;
1482
                tw = aGameVars[*insptr++].global;
1485
                tw = aGameVars[*insptr++].global;
1483
                VM_CONDITIONAL((uint32_t)tw < (uint32_t)*insptr);
1486
                VM_CONDITIONAL((uint32_t)tw < (uint32_t)*insptr);
1484
                dispatch();
1487
                dispatch();
1485
            vInstruction(CON_IFVARBE_GLOBAL):
1488
            vInstruction(CON_IFVARBE_GLOBAL):
1486
                insptr++;
1489
                insptr++;
1487
                tw = aGameVars[*insptr++].global;
1490
                tw = aGameVars[*insptr++].global;
1488
                VM_CONDITIONAL((uint32_t)tw <= (uint32_t)*insptr);
1491
                VM_CONDITIONAL((uint32_t)tw <= (uint32_t)*insptr);
1489
                dispatch();
1492
                dispatch();
1490
1493
1491
            vInstruction(CON_SETVAR_GLOBAL):
1494
            vInstruction(CON_SETVAR_GLOBAL):
1492
                insptr++;
1495
                insptr++;
1493
                aGameVars[*insptr].global = insptr[1];
1496
                aGameVars[*insptr].global = insptr[1];
1494
                insptr += 2;
1497
                insptr += 2;
1495
                dispatch();
1498
                dispatch();
1496
            vInstruction(CON_ADDVAR_GLOBAL):
1499
            vInstruction(CON_ADDVAR_GLOBAL):
1497
                insptr++;
1500
                insptr++;
1498
                aGameVars[*insptr].global += insptr[1];
1501
                aGameVars[*insptr].global += insptr[1];
1499
                insptr += 2;
1502
                insptr += 2;
1500
                dispatch();
1503
                dispatch();
1501
            vInstruction(CON_SUBVAR_GLOBAL):
1504
            vInstruction(CON_SUBVAR_GLOBAL):
1502
                insptr++;
1505
                insptr++;
1503
                aGameVars[*insptr].global -= insptr[1];
1506
                aGameVars[*insptr].global -= insptr[1];
1504
                insptr += 2;
1507
                insptr += 2;
1505
                dispatch();
1508
                dispatch();
1506
            vInstruction(CON_MULVAR_GLOBAL):
1509
            vInstruction(CON_MULVAR_GLOBAL):
1507
                insptr++;
1510
                insptr++;
1508
                aGameVars[*insptr].global *= insptr[1];
1511
                aGameVars[*insptr].global *= insptr[1];
1509
                insptr += 2;
1512
                insptr += 2;
1510
                dispatch();
1513
                dispatch();
1511
            vInstruction(CON_ANDVAR_GLOBAL):
1514
            vInstruction(CON_ANDVAR_GLOBAL):
1512
                insptr++;
1515
                insptr++;
1513
                aGameVars[*insptr].global &= insptr[1];
1516
                aGameVars[*insptr].global &= insptr[1];
1514
                insptr += 2;
1517
                insptr += 2;
1515
                dispatch();
1518
                dispatch();
1516
            vInstruction(CON_XORVAR_GLOBAL):
1519
            vInstruction(CON_XORVAR_GLOBAL):
1517
                insptr++;
1520
                insptr++;
1518
                aGameVars[*insptr].global ^= insptr[1];
1521
                aGameVars[*insptr].global ^= insptr[1];
1519
                insptr += 2;
1522
                insptr += 2;
1520
                dispatch();
1523
                dispatch();
1521
            vInstruction(CON_ORVAR_GLOBAL):
1524
            vInstruction(CON_ORVAR_GLOBAL):
1522
                insptr++;
1525
                insptr++;
1523
                aGameVars[*insptr].global |= insptr[1];
1526
                aGameVars[*insptr].global |= insptr[1];
1524
                insptr += 2;
1527
                insptr += 2;
1525
                dispatch();
1528
                dispatch();
1526
            vInstruction(CON_SHIFTVARL_GLOBAL):
1529
            vInstruction(CON_SHIFTVARL_GLOBAL):
1527
                insptr++;
1530
                insptr++;
1528
                aGameVars[*insptr].global <<= insptr[1];
1531
                aGameVars[*insptr].global <<= insptr[1];
1529
                insptr += 2;
1532
                insptr += 2;
1530
                dispatch();
1533
                dispatch();
1531
            vInstruction(CON_SHIFTVARR_GLOBAL):
1534
            vInstruction(CON_SHIFTVARR_GLOBAL):
1532
                insptr++;
1535
                insptr++;
1533
                aGameVars[*insptr].global >>= insptr[1];
1536
                aGameVars[*insptr].global >>= insptr[1];
1534
                insptr += 2;
1537
                insptr += 2;
1535
                dispatch();
1538
                dispatch();
1536
1539
1537
            vInstruction(CON_IFVARE_ACTOR):
1540
            vInstruction(CON_IFVARE_ACTOR):
1538
                insptr++;
1541
                insptr++;
1539
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1542
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1540
                VM_CONDITIONAL(tw == *insptr);
1543
                VM_CONDITIONAL(tw == *insptr);
1541
                dispatch();
1544
                dispatch();
1542
            vInstruction(CON_IFVARN_ACTOR):
1545
            vInstruction(CON_IFVARN_ACTOR):
1543
                insptr++;
1546
                insptr++;
1544
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1547
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1545
                VM_CONDITIONAL(tw != *insptr);
1548
                VM_CONDITIONAL(tw != *insptr);
1546
                dispatch();
1549
                dispatch();
1547
            vInstruction(CON_IFVARAND_ACTOR):
1550
            vInstruction(CON_IFVARAND_ACTOR):
1548
                insptr++;
1551
                insptr++;
1549
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1552
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1550
                VM_CONDITIONAL(tw & *insptr);
1553
                VM_CONDITIONAL(tw & *insptr);
1551
                dispatch();
1554
                dispatch();
1552
            vInstruction(CON_IFVAROR_ACTOR):
1555
            vInstruction(CON_IFVAROR_ACTOR):
1553
                insptr++;
1556
                insptr++;
1554
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1557
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1555
                VM_CONDITIONAL(tw | *insptr);
1558
                VM_CONDITIONAL(tw | *insptr);
1556
                dispatch();
1559
                dispatch();
1557
            vInstruction(CON_IFVARXOR_ACTOR):
1560
            vInstruction(CON_IFVARXOR_ACTOR):
1558
                insptr++;
1561
                insptr++;
1559
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1562
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1560
                VM_CONDITIONAL(tw ^ *insptr);
1563
                VM_CONDITIONAL(tw ^ *insptr);
1561
                dispatch();
1564
                dispatch();
1562
            vInstruction(CON_IFVAREITHER_ACTOR):
1565
            vInstruction(CON_IFVAREITHER_ACTOR):
1563
                insptr++;
1566
                insptr++;
1564
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1567
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1565
                VM_CONDITIONAL(tw || *insptr);
1568
                VM_CONDITIONAL(tw || *insptr);
1566
                dispatch();
1569
                dispatch();
1567
            vInstruction(CON_IFVARBOTH_ACTOR):
1570
            vInstruction(CON_IFVARBOTH_ACTOR):
1568
                insptr++;
1571
                insptr++;
1569
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1572
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1570
                VM_CONDITIONAL(tw && *insptr);
1573
                VM_CONDITIONAL(tw && *insptr);
1571
                dispatch();
1574
                dispatch();
1572
            vInstruction(CON_IFVARG_ACTOR):
1575
            vInstruction(CON_IFVARG_ACTOR):
1573
                insptr++;
1576
                insptr++;
1574
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1577
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1575
                VM_CONDITIONAL(tw > *insptr);
1578
                VM_CONDITIONAL(tw > *insptr);
1576
                dispatch();
1579
                dispatch();
1577
            vInstruction(CON_IFVARGE_ACTOR):
1580
            vInstruction(CON_IFVARGE_ACTOR):
1578
                insptr++;
1581
                insptr++;
1579
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1582
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1580
                VM_CONDITIONAL(tw >= *insptr);
1583
                VM_CONDITIONAL(tw >= *insptr);
1581
                dispatch();
1584
                dispatch();
1582
            vInstruction(CON_IFVARL_ACTOR):
1585
            vInstruction(CON_IFVARL_ACTOR):
1583
                insptr++;
1586
                insptr++;
1584
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1587
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1585
                VM_CONDITIONAL(tw < *insptr);
1588
                VM_CONDITIONAL(tw < *insptr);
1586
                dispatch();
1589
                dispatch();
1587
            vInstruction(CON_IFVARLE_ACTOR):
1590
            vInstruction(CON_IFVARLE_ACTOR):
1588
                insptr++;
1591
                insptr++;
1589
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1592
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1590
                VM_CONDITIONAL(tw <= *insptr);
1593
                VM_CONDITIONAL(tw <= *insptr);
1591
                dispatch();
1594
                dispatch();
1592
            vInstruction(CON_IFVARA_ACTOR):
1595
            vInstruction(CON_IFVARA_ACTOR):
1593
                insptr++;
1596
                insptr++;
1594
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1597
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1595
                VM_CONDITIONAL((uint32_t)tw > (uint32_t)*insptr);
1598
                VM_CONDITIONAL((uint32_t)tw > (uint32_t)*insptr);
1596
                dispatch();
1599
                dispatch();
1597
            vInstruction(CON_IFVARAE_ACTOR):
1600
            vInstruction(CON_IFVARAE_ACTOR):
1598
                insptr++;
1601
                insptr++;
1599
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1602
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1600
                VM_CONDITIONAL((uint32_t)tw >= (uint32_t)*insptr);
1603
                VM_CONDITIONAL((uint32_t)tw >= (uint32_t)*insptr);
1601
                dispatch();
1604
                dispatch();
1602
            vInstruction(CON_IFVARB_ACTOR):
1605
            vInstruction(CON_IFVARB_ACTOR):
1603
                insptr++;
1606
                insptr++;
1604
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1607
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1605
                VM_CONDITIONAL((uint32_t)tw < (uint32_t)*insptr);
1608
                VM_CONDITIONAL((uint32_t)tw < (uint32_t)*insptr);
1606
                dispatch();
1609
                dispatch();
1607
            vInstruction(CON_IFVARBE_ACTOR):
1610
            vInstruction(CON_IFVARBE_ACTOR):
1608
                insptr++;
1611
                insptr++;
1609
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1612
                tw = aGameVars[*insptr++].pValues[vm.spriteNum & (MAXSPRITES-1)];
1610
                VM_CONDITIONAL((uint32_t)tw <= (uint32_t)*insptr);
1613
                VM_CONDITIONAL((uint32_t)tw <= (uint32_t)*insptr);
1611
                dispatch();
1614
                dispatch();
1612
1615
1613
            vInstruction(CON_SETVAR_ACTOR):
1616
            vInstruction(CON_SETVAR_ACTOR):
1614
                insptr++;
1617
                insptr++;
1615
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] = insptr[1];
1618
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] = insptr[1];
1616
                insptr += 2;
1619
                insptr += 2;
1617
                dispatch();
1620
                dispatch();
1618
            vInstruction(CON_ADDVAR_ACTOR):
1621
            vInstruction(CON_ADDVAR_ACTOR):
1619
                insptr++;
1622
                insptr++;
1620
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] += insptr[1];
1623
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] += insptr[1];
1621
                insptr += 2;
1624
                insptr += 2;
1622
                dispatch();
1625
                dispatch();
1623
            vInstruction(CON_SUBVAR_ACTOR):
1626
            vInstruction(CON_SUBVAR_ACTOR):
1624
                insptr++;
1627
                insptr++;
1625
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] -= insptr[1];
1628
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] -= insptr[1];
1626
                insptr += 2;
1629
                insptr += 2;
1627
                dispatch();
1630
                dispatch();
1628
            vInstruction(CON_MULVAR_ACTOR):
1631
            vInstruction(CON_MULVAR_ACTOR):
1629
                insptr++;
1632
                insptr++;
1630
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] *= insptr[1];
1633
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] *= insptr[1];
1631
                insptr += 2;
1634
                insptr += 2;
1632
                dispatch();
1635
                dispatch();
1633
            vInstruction(CON_ANDVAR_ACTOR):
1636
            vInstruction(CON_ANDVAR_ACTOR):
1634
                insptr++;
1637
                insptr++;
1635
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] &= insptr[1];
1638
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] &= insptr[1];
1636
                insptr += 2;
1639
                insptr += 2;
1637
                dispatch();
1640
                dispatch();
1638
            vInstruction(CON_XORVAR_ACTOR):
1641
            vInstruction(CON_XORVAR_ACTOR):
1639
                insptr++;
1642
                insptr++;
1640
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] ^= insptr[1];
1643
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] ^= insptr[1];
1641
                insptr += 2;
1644
                insptr += 2;
1642
                dispatch();
1645
                dispatch();
1643
            vInstruction(CON_ORVAR_ACTOR):
1646
            vInstruction(CON_ORVAR_ACTOR):
1644
                insptr++;
1647
                insptr++;
1645
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] |= insptr[1];
1648
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] |= insptr[1];
1646
                insptr += 2;
1649
                insptr += 2;
1647
                dispatch();
1650
                dispatch();
1648
            vInstruction(CON_SHIFTVARL_ACTOR):
1651
            vInstruction(CON_SHIFTVARL_ACTOR):
1649
                insptr++;
1652
                insptr++;
1650
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] <<= insptr[1];
1653
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] <<= insptr[1];
1651
                insptr += 2;
1654
                insptr += 2;
1652
                dispatch();
1655
                dispatch();
1653
            vInstruction(CON_SHIFTVARR_ACTOR):
1656
            vInstruction(CON_SHIFTVARR_ACTOR):
1654
                insptr++;
1657
                insptr++;
1655
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] >>= insptr[1];
1658
                aGameVars[*insptr].pValues[vm.spriteNum & (MAXSPRITES-1)] >>= insptr[1]