2020-05-17 06:51:49 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 1996 , 2003 - 3 D Realms Entertainment
Copyright ( C ) 2000 , 2003 - Matt Saettler ( EDuke Enhancements )
2020-06-28 07:03:31 +00:00
Copyright ( C ) 2020 - Christoph Oelckers
2020-05-17 06:51:49 +00:00
This file is part of Enhanced Duke Nukem 3 D version 1.5 - Atomic Edition
Duke Nukem 3 D 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
2020-05-17 11:51:18 +00:00
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
2020-05-17 06:51:49 +00:00
Original Source : 1996 - Todd Replogle
Prepared for public release : 03 / 21 / 2003 - Charlie Wiederhold , 3 D 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"
2020-05-17 11:25:39 +00:00
# include "game.h"
2020-05-17 06:51:49 +00:00
BEGIN_DUKE_NS
//---------------------------------------------------------------------------
//
2020-05-17 11:25:39 +00:00
// handles all HUD related input, i.e. inventory item selection and activation plus weapon selection.
//
// Note: This doesn't restrict the events to WW2GI - since the other games do
// not define any by default there is no harm done keeping the code clean.
2020-05-17 06:51:49 +00:00
//
//---------------------------------------------------------------------------
2020-05-17 11:25:39 +00:00
void hud_input ( int snum )
{
int i , k ;
uint8_t dainv ;
unsigned int j ;
struct player_struct * p ;
short unk ;
unk = 0 ;
p = & ps [ snum ] ;
i = p - > aim_mode ;
2020-07-06 11:26:26 +00:00
p - > aim_mode = PlayerInput ( snum , SKB_AIMMODE ) ;
2020-05-17 11:25:39 +00:00
if ( p - > aim_mode < i )
p - > return_to_center = 9 ;
if ( isRR ( ) )
{
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_QUICK_KICK ) & & p - > last_pissed_time = = 0 )
2020-05-17 11:25:39 +00:00
{
if ( ! isRRRA ( ) | | sprite [ p - > i ] . extra > 0 )
{
p - > last_pissed_time = 4000 ;
if ( ! ud . lockout )
spritesound ( 437 , p - > i ) ;
if ( sprite [ p - > i ] . extra < = max_player_health - max_player_health / 10 )
{
sprite [ p - > i ] . extra + = 2 ;
p - > last_extra = sprite [ p - > i ] . extra ;
}
else if ( sprite [ p - > i ] . extra < max_player_health )
sprite [ p - > i ] . extra = max_player_health ;
}
}
}
else
{
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_QUICK_KICK ) & & p - > quick_kick = = 0 & & ( p - > curr_weapon ! = KNEE_WEAPON | | p - > kickback_pic = = 0 ) )
2020-05-17 11:25:39 +00:00
{
SetGameVarID ( g_iReturnVarID , 0 , - 1 , snum ) ;
OnEvent ( EVENT_QUICKKICK , - 1 , snum , - 1 ) ;
if ( GetGameVarID ( g_iReturnVarID , - 1 , snum ) = = 0 )
{
p - > quick_kick = 14 ;
FTA ( QUOTE_MIGHTY_FOOT , p ) ;
}
}
}
// WTF??? In the original source this was a soup of numeric literals, i.e. totally incomprehensible.
// The bit mask has been exported to the bit type enum.
2020-07-06 11:26:26 +00:00
if ( ! PlayerInputBits ( snum , SKB_INTERFACE_BITS ) )
2020-05-17 11:25:39 +00:00
p - > interface_toggle_flag = 0 ;
else if ( p - > interface_toggle_flag = = 0 )
{
p - > interface_toggle_flag = 1 ;
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_PAUSE ) )
2020-05-17 11:25:39 +00:00
{
ud . pause_on = ! ud . pause_on ;
2020-07-06 11:26:26 +00:00
if ( ud . pause_on = = 1 & & PlayerInput ( snum , SKB_RUN ) ) ud . pause_on = 2 ; // Mode 2 is silent, i.e. prints no notification.
2020-05-17 11:25:39 +00:00
Mus_SetPaused ( ud . pause_on ) ;
S_PauseSounds ( ud . pause_on ) ;
}
2020-05-17 11:51:18 +00:00
// Don't go on if paused or dead.
if ( ud . pause_on ) return ;
if ( sprite [ p - > i ] . extra < = 0 ) return ;
// Activate an inventory item. This just forwards to the other inventory bits. If the inventory selector was taken out of the playsim this could be removed.
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_INVENTORY ) & & p - > newowner = = - 1 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
SetGameVarID ( g_iReturnVarID , 0 , - 1 , snum ) ;
OnEvent ( EVENT_INVENTORY , - 1 , snum , - 1 ) ;
if ( GetGameVarID ( g_iReturnVarID , - 1 , snum ) = = 0 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
switch ( p - > inven_icon )
{
// Yet another place where no symbolic constants were used. :(
2020-07-06 11:26:26 +00:00
case ICON_JETPACK : PlayerSetInput ( snum , SKB_JETPACK ) ; break ;
case ICON_HOLODUKE : PlayerSetInput ( snum , SKB_HOLODUKE ) ; break ;
case ICON_HEATS : PlayerSetInput ( snum , SKB_NIGHTVISION ) ; break ;
case ICON_FIRSTAID : PlayerSetInput ( snum , SKB_MEDKIT ) ; break ;
case ICON_STEROIDS : PlayerSetInput ( snum , SKB_STEROIDS ) ; break ;
2020-05-17 11:51:18 +00:00
}
2020-05-17 11:25:39 +00:00
}
}
2020-07-06 11:26:26 +00:00
if ( ! isRR ( ) & & PlayerInput ( snum , SKB_NIGHTVISION ) )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
SetGameVarID ( g_iReturnVarID , 0 , - 1 , snum ) ;
OnEvent ( EVENT_USENIGHTVISION , - 1 , snum , - 1 ) ;
if ( GetGameVarID ( g_iReturnVarID , - 1 , snum ) = = 0 & & p - > heat_amount > 0 )
{
p - > heat_on = ! p - > heat_on ;
setpal ( p ) ;
p - > inven_icon = 5 ;
spritesound ( NITEVISION_ONOFF , p - > i ) ;
FTA ( 106 + ( ! p - > heat_on ) , p ) ;
}
2020-05-17 11:25:39 +00:00
}
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_STEROIDS ) )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
SetGameVarID ( g_iReturnVarID , 0 , - 1 , snum ) ;
OnEvent ( EVENT_USESTEROIDS , - 1 , snum , - 1 ) ;
if ( GetGameVarID ( g_iReturnVarID , - 1 , snum ) = = 0 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( p - > steroids_amount = = 400 )
{
p - > steroids_amount - - ;
spritesound ( DUKE_TAKEPILLS , p - > i ) ;
p - > inven_icon = ICON_STEROIDS ;
FTA ( 12 , p ) ;
}
2020-05-17 11:25:39 +00:00
}
2020-05-17 11:51:18 +00:00
return ;
2020-05-17 11:25:39 +00:00
}
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_INV_LEFT ) | | PlayerInput ( snum , SKB_INV_RIGHT ) )
2020-05-17 11:51:18 +00:00
{
p - > invdisptime = 26 * 2 ;
2020-05-17 11:25:39 +00:00
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_INV_RIGHT ) ) k = 1 ;
2020-05-17 11:51:18 +00:00
else k = 0 ;
2020-05-17 11:25:39 +00:00
2020-05-17 11:51:18 +00:00
dainv = p - > inven_icon ;
2020-05-17 11:25:39 +00:00
2020-05-17 11:51:18 +00:00
i = 0 ;
CHECKINV1 :
2020-05-17 11:25:39 +00:00
2020-05-17 11:51:18 +00:00
if ( i < 9 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
i + + ;
switch ( dainv )
{
case 4 :
if ( p - > jetpack_amount > 0 & & i > 1 )
break ;
if ( k ) dainv = 5 ;
else dainv = 3 ;
goto CHECKINV1 ;
case 6 :
if ( p - > scuba_amount > 0 & & i > 1 )
break ;
if ( k ) dainv = 7 ;
else dainv = 5 ;
goto CHECKINV1 ;
case 2 :
if ( p - > steroids_amount > 0 & & i > 1 )
break ;
if ( k ) dainv = 3 ;
else dainv = 1 ;
goto CHECKINV1 ;
case 3 :
if ( p - > holoduke_amount > 0 & & i > 1 )
break ;
if ( k ) dainv = 4 ;
else dainv = 2 ;
goto CHECKINV1 ;
case 0 :
case 1 :
if ( p - > firstaid_amount > 0 & & i > 1 )
break ;
if ( k ) dainv = 2 ;
else dainv = 7 ;
goto CHECKINV1 ;
case 5 :
if ( p - > heat_amount > 0 & & i > 1 )
break ;
if ( k ) dainv = 6 ;
else dainv = 4 ;
goto CHECKINV1 ;
case 7 :
if ( p - > boot_amount > 0 & & i > 1 )
break ;
if ( k ) dainv = 1 ;
else dainv = 6 ;
goto CHECKINV1 ;
}
2020-05-17 11:25:39 +00:00
}
2020-05-17 11:51:18 +00:00
else dainv = 0 ;
2020-05-17 11:25:39 +00:00
2020-05-17 11:51:18 +00:00
// These events force us to keep the inventory selector in the playsim as opposed to the UI where it really belongs.
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_INV_LEFT ) )
2020-05-17 11:51:18 +00:00
{
SetGameVarID ( g_iReturnVarID , dainv , - 1 , snum ) ;
OnEvent ( EVENT_INVENTORYLEFT , - 1 , snum , - 1 ) ;
dainv = GetGameVarID ( g_iReturnVarID , - 1 , snum ) ;
}
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_INV_RIGHT ) )
2020-05-17 11:51:18 +00:00
{
SetGameVarID ( g_iReturnVarID , dainv , - 1 , snum ) ;
OnEvent ( EVENT_INVENTORYRIGHT , - 1 , snum , - 1 ) ;
dainv = GetGameVarID ( g_iReturnVarID , - 1 , snum ) ;
}
p - > inven_icon = dainv ;
// Someone must have really hated constant data, doing this with a switch/case (and of course also with literal numbers...)
static const uint8_t invquotes [ ] = { QUOTE_MEDKIT , QUOTE_STEROIDS , QUOTE_HOLODUKE , QUOTE_JETPACK , QUOTE_NVG , QUOTE_SCUBA , QUOTE_BOOTS } ;
if ( dainv > = 1 & & dainv < 8 ) FTA ( invquotes [ dainv - 1 ] , p ) ;
2020-05-17 11:25:39 +00:00
}
2020-07-06 11:26:26 +00:00
j = ( PlayerInputBits ( snum , SKB_WEAPONMASK_BITS ) > > SK_WEAPON_BITS ) - 1 ;
2020-05-17 11:25:39 +00:00
if ( j > 0 & & p - > kickback_pic > 0 )
p - > wantweaponfire = j ;
// Here we have to be extra careful that the weapons do not get mixed up, so let's keep the code for Duke and RR completely separate.
fi . selectweapon ( snum , j ) ;
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_HOLSTER ) )
2020-05-17 11:25:39 +00:00
{
if ( p - > curr_weapon > KNEE_WEAPON )
{
if ( p - > holster_weapon = = 0 & & p - > weapon_pos = = 0 )
{
p - > holster_weapon = 1 ;
p - > weapon_pos = - 1 ;
FTA ( QUOTE_WEAPON_LOWERED , p ) ;
}
else if ( p - > holster_weapon = = 1 & & p - > weapon_pos = = - 9 )
{
p - > holster_weapon = 0 ;
p - > weapon_pos = 10 ;
FTA ( QUOTE_WEAPON_RAISED , p ) ;
}
}
}
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_HOLODUKE ) & & ( isRR ( ) | | p - > newowner = = - 1 ) )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
SetGameVarID ( g_iReturnVarID , 0 , - 1 , snum ) ;
OnEvent ( EVENT_HOLODUKEON , - 1 , snum , - 1 ) ;
if ( GetGameVarID ( g_iReturnVarID , - 1 , snum ) = = 0 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( ! isRR ( ) )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( p - > holoduke_on = = - 1 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( p - > holoduke_amount > 0 )
{
p - > inven_icon = 3 ;
p - > holoduke_on = i =
EGS ( p - > cursectnum ,
p - > posx ,
p - > posy ,
p - > posz + ( 30 < < 8 ) , TILE_APLAYER , - 64 , 0 , 0 , p - > getang ( ) , 0 , 0 , - 1 , 10 ) ;
hittype [ i ] . temp_data [ 3 ] = hittype [ i ] . temp_data [ 4 ] = 0 ;
sprite [ i ] . yvel = snum ;
sprite [ i ] . extra = 0 ;
FTA ( 47 , p ) ;
}
else FTA ( QUOTE_HOLODUKE_ON , p ) ;
spritesound ( TELEPORTER , p - > holoduke_on ) ;
2020-05-17 11:25:39 +00:00
}
2020-05-17 11:51:18 +00:00
else
{
spritesound ( TELEPORTER , p - > holoduke_on ) ;
p - > holoduke_on = - 1 ;
FTA ( QUOTE_HOLODUKE_NOT_FOUND , p ) ;
}
2020-05-17 11:25:39 +00:00
}
2020-05-17 11:51:18 +00:00
else // In RR this means drinking whiskey.
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( p - > holoduke_amount > 0 & & sprite [ p - > i ] . extra < max_player_health )
{
p - > holoduke_amount - = 400 ;
sprite [ p - > i ] . extra + = 5 ;
if ( sprite [ p - > i ] . extra > max_player_health )
sprite [ p - > i ] . extra = max_player_health ;
p - > drink_amt + = 5 ;
p - > inven_icon = 3 ;
if ( p - > holoduke_amount = = 0 )
checkavailinven ( p ) ;
if ( p - > drink_amt < 99 & & ! A_CheckSoundPlaying ( p - > i , 425 ) )
spritesound ( 425 , p - > i ) ;
}
2020-05-17 11:25:39 +00:00
}
}
}
2020-07-06 11:26:26 +00:00
if ( isRR ( ) & & PlayerInput ( snum , SKB_NIGHTVISION ) & & p - > newowner = = - 1 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
SetGameVarID ( g_iReturnVarID , 0 , - 1 , snum ) ;
OnEvent ( EVENT_USENIGHTVISION , - 1 , snum , - 1 ) ;
if ( GetGameVarID ( g_iReturnVarID , - 1 , snum ) = = 0 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( p - > yehaa_timer = = 0 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
p - > yehaa_timer = 126 ;
spritesound ( 390 , p - > i ) ;
p - > noise_radius = 16384 ;
madenoise ( snum ) ;
if ( sector [ p - > cursectnum ] . lotag = = 857 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( sprite [ p - > i ] . extra < = max_player_health )
{
sprite [ p - > i ] . extra + = 10 ;
if ( sprite [ p - > i ] . extra > = max_player_health )
sprite [ p - > i ] . extra = max_player_health ;
}
2020-05-17 11:25:39 +00:00
}
2020-05-17 11:51:18 +00:00
else
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( sprite [ p - > i ] . extra + 1 < = max_player_health )
{
sprite [ p - > i ] . extra + + ;
}
2020-05-17 11:25:39 +00:00
}
}
}
}
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_MEDKIT ) )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
SetGameVarID ( g_iReturnVarID , 0 , - 1 , snum ) ;
OnEvent ( EVENT_USEMEDKIT , - 1 , snum , - 1 ) ;
if ( GetGameVarID ( g_iReturnVarID , - 1 , snum ) = = 0 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( p - > firstaid_amount > 0 & & sprite [ p - > i ] . extra < max_player_health )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( ! isRR ( ) )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
j = max_player_health - sprite [ p - > i ] . extra ;
if ( ( unsigned int ) p - > firstaid_amount > j )
{
p - > firstaid_amount - = j ;
sprite [ p - > i ] . extra = max_player_health ;
p - > inven_icon = 1 ;
}
else
{
sprite [ p - > i ] . extra + = p - > firstaid_amount ;
p - > firstaid_amount = 0 ;
checkavailinven ( p ) ;
}
spritesound ( DUKE_USEMEDKIT , p - > i ) ;
2020-05-17 11:25:39 +00:00
}
else
{
2020-05-17 11:51:18 +00:00
j = 10 ;
if ( p - > firstaid_amount > j )
{
p - > firstaid_amount - = j ;
sprite [ p - > i ] . extra + = j ;
if ( sprite [ p - > i ] . extra > max_player_health )
sprite [ p - > i ] . extra = max_player_health ;
p - > inven_icon = 1 ;
}
else
{
sprite [ p - > i ] . extra + = p - > firstaid_amount ;
p - > firstaid_amount = 0 ;
checkavailinven ( p ) ;
}
2020-05-17 11:25:39 +00:00
if ( sprite [ p - > i ] . extra > max_player_health )
sprite [ p - > i ] . extra = max_player_health ;
2020-05-17 11:51:18 +00:00
p - > drink_amt + = 10 ;
if ( p - > drink_amt < = 100 & & ! A_CheckSoundPlaying ( p - > i , DUKE_USEMEDKIT ) )
spritesound ( DUKE_USEMEDKIT , p - > i ) ;
2020-05-17 11:25:39 +00:00
}
}
}
}
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_JETPACK ) & & ( isRR ( ) | | p - > newowner = = - 1 ) )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
SetGameVarID ( g_iReturnVarID , 0 , - 1 , snum ) ;
OnEvent ( EVENT_USEJETPACK , - 1 , snum , - 1 ) ;
if ( GetGameVarID ( g_iReturnVarID , - 1 , snum ) = = 0 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( ! isRR ( ) )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( p - > jetpack_amount > 0 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
p - > jetpack_on = ! p - > jetpack_on ;
if ( p - > jetpack_on )
{
p - > inven_icon = 4 ;
S_StopEnvSound ( - 1 , p - > i , CHAN_VOICE ) ; // this will stop the falling scream
A_PlaySound ( DUKE_JETPACK_ON , p - > i ) ;
FTA ( QUOTE_JETPACK_ON , p ) ;
}
else
{
p - > hard_landing = 0 ;
p - > poszv = 0 ;
spritesound ( DUKE_JETPACK_OFF , p - > i ) ;
S_StopEnvSound ( DUKE_JETPACK_IDLE , p - > i ) ;
S_StopEnvSound ( DUKE_JETPACK_ON , p - > i ) ;
FTA ( QUOTE_JETPACK_OFF , p ) ;
}
2020-05-17 11:25:39 +00:00
}
2020-05-17 11:51:18 +00:00
else FTA ( QUOTE_JETPACK_NOT_FOUND , p ) ;
2020-05-17 11:25:39 +00:00
}
2020-05-17 11:51:18 +00:00
else
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
// eat cow pie
if ( p - > jetpack_amount > 0 & & sprite [ p - > i ] . extra < max_player_health )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
if ( ! A_CheckSoundPlaying ( p - > i , 429 ) )
A_PlaySound ( 429 , p - > i ) ;
p - > jetpack_amount - = 100 ;
if ( p - > drink_amt > 0 )
{
p - > drink_amt - = 5 ;
if ( p - > drink_amt < 0 )
p - > drink_amt = 0 ;
}
if ( p - > eat < 100 )
{
p - > eat + = 5 ;
if ( p - > eat > 100 )
p - > eat = 100 ;
}
sprite [ p - > i ] . extra + = 5 ;
2020-05-17 11:25:39 +00:00
2020-05-17 11:51:18 +00:00
p - > inven_icon = 4 ;
2020-05-17 11:25:39 +00:00
2020-05-17 11:51:18 +00:00
if ( sprite [ p - > i ] . extra > max_player_health )
sprite [ p - > i ] . extra = max_player_health ;
2020-05-17 11:25:39 +00:00
2020-05-17 11:51:18 +00:00
if ( p - > jetpack_amount < = 0 )
checkavailinven ( p ) ;
}
2020-05-17 11:25:39 +00:00
}
}
}
2020-07-06 11:26:26 +00:00
if ( PlayerInput ( snum , SKB_TURNAROUND ) & & p - > one_eighty_count = = 0 )
2020-05-17 11:25:39 +00:00
{
2020-05-17 11:51:18 +00:00
SetGameVarID ( g_iReturnVarID , 0 , - 1 , snum ) ;
OnEvent ( EVENT_TURNAROUND , - 1 , snum , - 1 ) ;
if ( GetGameVarID ( g_iReturnVarID , - 1 , snum ) = = 0 )
{
p - > one_eighty_count = - 1024 ;
}
2020-05-17 11:25:39 +00:00
}
}
}
END_DUKE_NS