mirror of
https://github.com/ZDoom/Raze.git
synced 2024-12-11 13:21:49 +00:00
551 lines
13 KiB
C++
551 lines
13 KiB
C++
|
//-------------------------------------------------------------------------
|
||
|
/*
|
||
|
Copyright (C) 1996, 2003 - 3D Realms Entertainment
|
||
|
Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements)
|
||
|
|
||
|
This file is part of Enhanced Duke Nukem 3D version 1.5 - Atomic Edition
|
||
|
|
||
|
Duke Nukem 3D is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License
|
||
|
as published by the Free Software Foundation; either version 2
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
|
||
|
See the GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
|
||
|
Original Source: 1996 - Todd Replogle
|
||
|
Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
|
||
|
|
||
|
EDuke enhancements integrated: 04/13/2003 - Matt Saettler
|
||
|
|
||
|
Note: EDuke source was in transition. Changes are in-progress in the
|
||
|
source as it is released.
|
||
|
|
||
|
*/
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
#include "ns.h"
|
||
|
#include "global.h"
|
||
|
#include "game.h"
|
||
|
#include "gamevar.h"
|
||
|
#include "player.h"
|
||
|
#include "names.h"
|
||
|
#include "macros.h"
|
||
|
|
||
|
BEGIN_DUKE_NS
|
||
|
|
||
|
int operateTripbomb(int snum);
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
void DoFire(struct player_struct *p, short snum)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if(aplWeaponWorksLike[p->curr_weapon][snum]!=KNEE_WEAPON)
|
||
|
{
|
||
|
p->ammo_amount[p->curr_weapon]--;
|
||
|
}
|
||
|
|
||
|
if(aplWeaponFireSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponFireSound[p->curr_weapon][snum],p->i);
|
||
|
}
|
||
|
|
||
|
SetGameVarID(g_iWeaponVarID,p->curr_weapon,p->i,snum);
|
||
|
SetGameVarID(g_iWorksLikeVarID,aplWeaponWorksLike[p->curr_weapon][snum], p->i, snum);
|
||
|
fi.shoot(p->i,aplWeaponShoots[p->curr_weapon][snum]);
|
||
|
for(i=1;i<aplWeaponShotsPerBurst[p->curr_weapon][snum];i++)
|
||
|
{
|
||
|
fi.shoot(p->i,aplWeaponShoots[p->curr_weapon][snum]);
|
||
|
if( aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_AMMOPERSHOT)
|
||
|
{
|
||
|
p->ammo_amount[p->curr_weapon]--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(! (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_NOVISIBLE ))
|
||
|
{
|
||
|
// make them visible if not set...
|
||
|
lastvisinc = (int)totalclock+32;
|
||
|
p->visibility = 0;
|
||
|
}
|
||
|
|
||
|
if( //!(aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_CHECKATRELOAD) &&
|
||
|
aplWeaponReload[p->curr_weapon][snum] > aplWeaponTotalTime[p->curr_weapon][snum]
|
||
|
&& p->ammo_amount[p->curr_weapon] > 0
|
||
|
&& (aplWeaponClip[p->curr_weapon][snum])
|
||
|
&& ((p->ammo_amount[p->curr_weapon]%(aplWeaponClip[p->curr_weapon][snum]))==0)
|
||
|
)
|
||
|
{
|
||
|
// do clip check...
|
||
|
p->kickback_pic=aplWeaponTotalTime[p->curr_weapon][snum];
|
||
|
// is same as (*kb)....
|
||
|
}
|
||
|
|
||
|
if(aplWeaponWorksLike[p->curr_weapon][snum]!=KNEE_WEAPON)
|
||
|
{
|
||
|
checkavailweapon(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
void DoSpawn(struct player_struct *p, short snum)
|
||
|
{
|
||
|
int j;
|
||
|
if(!aplWeaponSpawn[p->curr_weapon][snum])
|
||
|
return;
|
||
|
|
||
|
j = fi.spawn(p->i, aplWeaponSpawn[p->curr_weapon][snum]);
|
||
|
|
||
|
if((aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_SPAWNTYPE2 ) )
|
||
|
{
|
||
|
// like shotgun shells
|
||
|
sprite[j].ang += 1024;
|
||
|
ssp(j,CLIPMASK0);
|
||
|
sprite[j].ang += 1024;
|
||
|
// p->kickback_pic++;
|
||
|
}
|
||
|
else if((aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_SPAWNTYPE3 ) )
|
||
|
{
|
||
|
// like chaingun shells
|
||
|
sprite[j].ang += 1024;
|
||
|
sprite[j].ang &= 2047;
|
||
|
sprite[j].xvel += 32;
|
||
|
sprite[j].z += (3<<8);
|
||
|
ssp(j,CLIPMASK0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
void fireweapon_ww(int snum, int* kb)
|
||
|
{
|
||
|
auto p = &ps[snum];
|
||
|
int pi = p->i;
|
||
|
|
||
|
p->crack_time = 777;
|
||
|
|
||
|
if (p->holster_weapon == 1)
|
||
|
{
|
||
|
if (p->last_pissed_time <= (26 * 218) && p->weapon_pos == -9)
|
||
|
{
|
||
|
p->holster_weapon = 0;
|
||
|
p->weapon_pos = 10;
|
||
|
FTA(74, p);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetGameVarID(g_iReturnVarID, 0, pi, snum);
|
||
|
SetGameVarID(g_iWeaponVarID, p->curr_weapon, pi, snum);
|
||
|
SetGameVarID(g_iWorksLikeVarID, aplWeaponWorksLike[p->curr_weapon][snum], pi, snum);
|
||
|
OnEvent(EVENT_FIRE, pi, snum, -1);
|
||
|
if (GetGameVarID(g_iReturnVarID, pi, snum) == 0)
|
||
|
{
|
||
|
switch (aplWeaponWorksLike[p->curr_weapon][snum])
|
||
|
{
|
||
|
case HANDBOMB_WEAPON:
|
||
|
p->hbomb_hold_delay = 0;
|
||
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case HANDREMOTE_WEAPON:
|
||
|
p->hbomb_hold_delay = 0;
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case PISTOL_WEAPON:
|
||
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
||
|
{
|
||
|
// p->ammo_amount[p->curr_weapon]--;
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
|
||
|
case CHAINGUN_WEAPON:
|
||
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SHOTGUN_WEAPON:
|
||
|
if (p->ammo_amount[p->curr_weapon] > 0 && p->random_club_frame == 0)
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case TRIPBOMB_WEAPON:
|
||
|
if (operateTripbomb(snum))
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SHRINKER_WEAPON:
|
||
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case GROW_WEAPON:
|
||
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case FREEZE_WEAPON:
|
||
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case DEVISTATOR_WEAPON:
|
||
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
p->hbomb_hold_delay = !p->hbomb_hold_delay;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case RPG_WEAPON:
|
||
|
if (p->ammo_amount[RPG_WEAPON] > 0)
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case KNEE_WEAPON:
|
||
|
if (p->quick_kick == 0)
|
||
|
{
|
||
|
(*kb) = 1;
|
||
|
if (aplWeaponInitialSound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponInitialSound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
void operateweapon_ww(int snum, int sb_snum, int psect, int* kb)
|
||
|
{
|
||
|
auto p = &ps[snum];
|
||
|
int pi = p->i;
|
||
|
int i, j, k;
|
||
|
int psectlotag = sector[psect].lotag;
|
||
|
|
||
|
// already firing...
|
||
|
if (aplWeaponWorksLike[p->curr_weapon][snum] == HANDBOMB_WEAPON)
|
||
|
{
|
||
|
if (aplWeaponHoldDelay[p->curr_weapon][snum] // there is a hold delay
|
||
|
&& ((*kb) == aplWeaponFireDelay[p->curr_weapon][snum]) // and we are 'at' hold
|
||
|
&& (sb_snum & (1 << 2)) // and 'fire' button is still down
|
||
|
)
|
||
|
// just hold here...
|
||
|
{
|
||
|
p->rapid_fire_hold = 1;
|
||
|
return;
|
||
|
}
|
||
|
(*kb)++;
|
||
|
if ((*kb) == aplWeaponHoldDelay[p->curr_weapon][snum])
|
||
|
{
|
||
|
p->ammo_amount[p->curr_weapon]--;
|
||
|
|
||
|
if (p->on_ground && (sb_snum & SKB_CROUCH))
|
||
|
{
|
||
|
k = 15;
|
||
|
i = ((p->gethorizsum() - 100) * 20);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
k = 140;
|
||
|
i = -512 - ((p->gethorizsum() - 100) * 20);
|
||
|
}
|
||
|
|
||
|
j = EGS(p->cursectnum,
|
||
|
p->posx + (sintable[(p->getang() + 512) & 2047] >> 6),
|
||
|
p->posy + (sintable[p->getang() & 2047] >> 6),
|
||
|
p->posz, HEAVYHBOMB, -16, 9, 9,
|
||
|
p->getang(), (k + (p->hbomb_hold_delay << 5)), i, pi, 1);
|
||
|
|
||
|
{
|
||
|
long lGrenadeLifetime = GetGameVar("GRENADE_LIFETIME", NAM_GRENADE_LIFETIME, -1, snum);
|
||
|
long lGrenadeLifetimeVar = GetGameVar("GRENADE_LIFETIME_VAR", NAM_GRENADE_LIFETIME_VAR, -1, snum);
|
||
|
// set timer. blows up when at zero....
|
||
|
sprite[j].extra = lGrenadeLifetime
|
||
|
+ mulscale(krand(), lGrenadeLifetimeVar, 14)
|
||
|
- lGrenadeLifetimeVar;
|
||
|
}
|
||
|
|
||
|
if (k == 15)
|
||
|
{
|
||
|
sprite[j].yvel = 3;
|
||
|
sprite[j].z += (8 << 8);
|
||
|
}
|
||
|
|
||
|
k = hits(pi);
|
||
|
if (k < 512)
|
||
|
{
|
||
|
sprite[j].ang += 1024;
|
||
|
sprite[j].zvel /= 3;
|
||
|
sprite[j].xvel /= 3;
|
||
|
}
|
||
|
|
||
|
p->hbomb_on = 1;
|
||
|
|
||
|
}
|
||
|
else if ((*kb) < aplWeaponHoldDelay[p->curr_weapon][snum] &&
|
||
|
(sb_snum & SKB_CROUCH))
|
||
|
{
|
||
|
p->hbomb_hold_delay++;
|
||
|
}
|
||
|
else if ((*kb) > aplWeaponTotalTime[p->curr_weapon][snum])
|
||
|
{
|
||
|
(*kb) = 0;
|
||
|
// don't change to remote when in NAM: grenades are timed
|
||
|
checkavailweapon(p);
|
||
|
}
|
||
|
}
|
||
|
else if (aplWeaponWorksLike[p->curr_weapon][snum] == HANDREMOTE_WEAPON)
|
||
|
{
|
||
|
(*kb)++;
|
||
|
|
||
|
if ((*kb) == aplWeaponFireDelay[p->curr_weapon][snum])
|
||
|
{
|
||
|
if (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_BOMB_TRIGGER)
|
||
|
{
|
||
|
p->hbomb_on = 0;
|
||
|
}
|
||
|
if (aplWeaponShoots[p->curr_weapon][snum] != 0)
|
||
|
{
|
||
|
if (!(aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_NOVISIBLE))
|
||
|
{
|
||
|
// make them visible if not set...
|
||
|
lastvisinc = (int)totalclock + 32;
|
||
|
p->visibility = 0;
|
||
|
}
|
||
|
SetGameVarID(g_iWeaponVarID, p->curr_weapon, p->i, snum);
|
||
|
SetGameVarID(g_iWorksLikeVarID, aplWeaponWorksLike[p->curr_weapon][snum], p->i, snum);
|
||
|
fi.shoot(pi, aplWeaponShoots[p->curr_weapon][snum]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((*kb) >= aplWeaponTotalTime[p->curr_weapon][snum])
|
||
|
{
|
||
|
(*kb) = 0;
|
||
|
/// WHAT THE HELL DOES THIS DO....?????????????
|
||
|
if (p->ammo_amount[TRIPBOMB_WEAPON] > 0)
|
||
|
fi.addweapon(p, TRIPBOMB_WEAPON);
|
||
|
else
|
||
|
checkavailweapon(p);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// the basic weapon...
|
||
|
(*kb)++;
|
||
|
|
||
|
if (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_CHECKATRELOAD)
|
||
|
{
|
||
|
if (*kb == aplWeaponReload[p->curr_weapon][snum])
|
||
|
{
|
||
|
checkavailweapon(p);
|
||
|
}
|
||
|
}
|
||
|
if (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_STANDSTILL
|
||
|
&& *kb < (aplWeaponFireDelay[p->curr_weapon][snum] + 1))
|
||
|
{
|
||
|
p->posz = p->oposz;
|
||
|
p->poszv = 0;
|
||
|
}
|
||
|
if (*kb == aplWeaponSound2Time[p->curr_weapon][snum])
|
||
|
{
|
||
|
if (aplWeaponSound2Sound[p->curr_weapon][snum])
|
||
|
{
|
||
|
spritesound(aplWeaponSound2Sound[p->curr_weapon][snum], pi);
|
||
|
}
|
||
|
}
|
||
|
if (*kb == aplWeaponSpawnTime[p->curr_weapon][snum])
|
||
|
{
|
||
|
DoSpawn(p, snum);
|
||
|
}
|
||
|
if (*kb == aplWeaponFireDelay[p->curr_weapon][snum])
|
||
|
{
|
||
|
DoFire(p, snum);
|
||
|
}
|
||
|
|
||
|
if (*kb > aplWeaponFireDelay[p->curr_weapon][snum]
|
||
|
&& (*kb) < aplWeaponTotalTime[p->curr_weapon][snum])
|
||
|
{
|
||
|
|
||
|
if (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_AUTOMATIC)
|
||
|
{ // an 'automatic'
|
||
|
if ((sb_snum & (1 << 2)) == 0)
|
||
|
{
|
||
|
*kb = aplWeaponTotalTime[p->curr_weapon][snum];
|
||
|
}
|
||
|
|
||
|
if (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_FIREEVERYTHIRD)
|
||
|
{
|
||
|
if (((*(kb)) % 3) == 0)
|
||
|
{
|
||
|
DoFire(p, snum);
|
||
|
DoSpawn(p, snum);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
if (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_FIREEVERYOTHER)
|
||
|
{
|
||
|
// fire every other...
|
||
|
DoFire(p, snum);
|
||
|
DoSpawn(p, snum);
|
||
|
}
|
||
|
|
||
|
} // 'automatic
|
||
|
}
|
||
|
else if ((*kb) >= aplWeaponTotalTime[p->curr_weapon][snum])
|
||
|
{
|
||
|
if ( //!(aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_CHECKATRELOAD) &&
|
||
|
aplWeaponReload[p->curr_weapon][snum] > aplWeaponTotalTime[p->curr_weapon][snum]
|
||
|
&& p->ammo_amount[p->curr_weapon] > 0
|
||
|
&& (aplWeaponClip[p->curr_weapon][snum])
|
||
|
&& ((p->ammo_amount[p->curr_weapon] % (aplWeaponClip[p->curr_weapon][snum])) == 0)
|
||
|
)
|
||
|
{
|
||
|
// reload in progress...
|
||
|
int i;
|
||
|
i = aplWeaponReload[p->curr_weapon][snum] - aplWeaponTotalTime[p->curr_weapon][snum];
|
||
|
// time for 'reload'
|
||
|
|
||
|
if ((*kb) == (aplWeaponTotalTime[p->curr_weapon][snum] + 1))
|
||
|
{ // eject shortly after 'total time'
|
||
|
spritesound(EJECT_CLIP, pi);
|
||
|
}
|
||
|
else if ((*kb) == (aplWeaponReload[p->curr_weapon][snum] - (i / 3)))
|
||
|
{
|
||
|
// insert occurs 2/3 of way through reload delay
|
||
|
spritesound(INSERT_CLIP, pi);
|
||
|
}
|
||
|
|
||
|
if ((*kb) >= (aplWeaponReload[p->curr_weapon][snum]))
|
||
|
{
|
||
|
*kb = 0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_AUTOMATIC)
|
||
|
{ // an 'automatic'
|
||
|
if (sb_snum & (1 << 2))
|
||
|
{
|
||
|
// we are an AUTOMATIC. Fire again...
|
||
|
if (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_RANDOMRESTART)
|
||
|
{
|
||
|
*kb = 1 + (krand() & 3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*kb = 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*kb = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // not 'automatic' and >totaltime
|
||
|
*kb = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} // process the event ourselves if no handler provided.
|
||
|
}
|
||
|
|
||
|
|
||
|
END_DUKE_NS
|