2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING . txt .
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below .
* See COPYING . txt for license details .
2006-03-20 17:12:09 +00:00
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ( " PARALLAX " ) . PARALLAX , IN DISTRIBUTING THE CODE TO
END - USERS , AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN , GRANTS A
ROYALTY - FREE , PERPETUAL LICENSE TO SUCH END - USERS FOR USE BY SUCH END - USERS
IN USING , DISPLAYING , AND CREATING DERIVATIVE WORKS THEREOF , SO LONG AS
SUCH USE , DISPLAY OR CREATION IS FOR NON - COMMERCIAL , ROYALTY OR REVENUE
FREE PURPOSES . IN NO EVENT SHALL THE END - USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE - BEARING PURPOSES . THE END - USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE .
COPYRIGHT 1993 - 1999 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
/*
*
* New Triggers and Switches .
*
*/
2015-03-22 04:16:49 +00:00
# include <stdexcept>
2006-03-20 17:12:09 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
# include <string.h>
# include "newmenu.h"
# include "game.h"
# include "switch.h"
# include "inferno.h"
# include "segment.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "gameseg.h"
# include "wall.h"
2014-11-23 04:36:58 +00:00
# include "object.h"
2006-03-20 17:12:09 +00:00
# include "fuelcen.h"
# include "newdemo.h"
# include "player.h"
# include "endlevel.h"
# include "gameseq.h"
2020-12-20 20:39:07 +00:00
# include "net_udp.h"
2006-03-20 17:12:09 +00:00
# include "palette.h"
2015-04-19 04:18:51 +00:00
# include "hudmsg.h"
2006-03-20 17:12:09 +00:00
# include "robot.h"
# include "bm.h"
2014-01-12 23:00:43 +00:00
# include "physfs-serial.h"
2020-08-10 03:45:14 +00:00
# include "d_levelstate.h"
2021-09-04 12:17:14 +00:00
# include "d_underlying_value.h"
2022-01-15 20:39:10 +00:00
# include "d_zip.h"
2014-12-08 04:19:26 +00:00
# include "compiler-range_for.h"
# include "partial_range.h"
2014-01-12 23:00:43 +00:00
2019-01-01 04:54:35 +00:00
template < typename SF , typename O , typename . . . Oa >
static inline void trigger_wall_op ( const trigger & t , SF & segment_factory , const O & op , Oa & & . . . oargs )
2016-01-09 16:38:11 +00:00
{
for ( unsigned i = 0 , num_links = t . num_links ; i ! = num_links ; + + i )
2022-01-09 15:25:42 +00:00
op ( std : : forward < Oa > ( oargs ) . . . , segment_factory ( t . seg [ i ] ) , static_cast < sidenum_t > ( t . side [ i ] ) ) ;
2016-01-09 16:38:11 +00:00
}
2006-03-20 17:12:09 +00:00
//-----------------------------------------------------------------
// Executes a link, attached to a trigger.
// Toggles all walls linked to the switch.
// Opens doors, Blasts blast walls, turns off illusions.
2016-01-09 16:38:11 +00:00
static void do_link ( const trigger & t )
2006-03-20 17:12:09 +00:00
{
2018-12-30 00:43:58 +00:00
auto & Walls = LevelUniqueWallSubsystemState . Walls ;
auto & vmwallptr = Walls . vmptr ;
2019-01-01 04:54:35 +00:00
trigger_wall_op ( t , vmsegptridx , wall_toggle , vmwallptr ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2016-08-25 04:05:32 +00:00
namespace dsx {
2006-03-20 17:12:09 +00:00
//close a door
2016-01-09 16:38:11 +00:00
static void do_close_door ( const trigger & t )
2006-03-20 17:12:09 +00:00
{
2018-12-30 00:43:58 +00:00
auto & Walls = LevelUniqueWallSubsystemState . Walls ;
2019-01-01 04:54:35 +00:00
trigger_wall_op ( t , vmsegptridx , wall_close_door , Walls ) ;
2006-03-20 17:12:09 +00:00
}
//turns lighting on. returns true if lights were actually turned on. (they
//would not be if they had previously been shot out).
2019-01-01 04:54:35 +00:00
static int do_light_on ( const d_level_shared_destructible_light_state & LevelSharedDestructibleLightState , const d_level_unique_tmap_info_state : : TmapInfo_array & TmapInfo , d_flickering_light_state & Flickering_light_state , const trigger & t )
2006-03-20 17:12:09 +00:00
{
2016-01-09 16:38:11 +00:00
int ret = 0 ;
2022-01-09 15:25:42 +00:00
const auto op = [ & LevelSharedDestructibleLightState , & Flickering_light_state , & TmapInfo , & ret ] ( const vmsegptridx_t segnum , const sidenum_t sidenum ) {
2006-03-20 17:12:09 +00:00
//check if tmap2 casts light before turning the light on. This
//is to keep us from turning on blown-out lights
2020-08-24 01:31:28 +00:00
const auto tm2 = get_texture_index ( segnum - > unique_segment : : sides [ sidenum ] . tmap_num2 ) ;
if ( TmapInfo [ tm2 ] . lighting ) {
2018-12-30 00:43:58 +00:00
ret | = add_light ( LevelSharedDestructibleLightState , segnum , sidenum ) ; //any light sets flag
2018-03-31 21:53:01 +00:00
enable_flicker ( Flickering_light_state , segnum , sidenum ) ;
2006-03-20 17:12:09 +00:00
}
2016-01-09 16:38:11 +00:00
} ;
2017-06-10 03:31:02 +00:00
trigger_wall_op ( t , vmsegptridx , op ) ;
2006-03-20 17:12:09 +00:00
return ret ;
}
//turns lighting off. returns true if lights were actually turned off. (they
//would not be if they had previously been shot out).
2019-01-01 04:54:35 +00:00
static int do_light_off ( const d_level_shared_destructible_light_state & LevelSharedDestructibleLightState , const d_level_unique_tmap_info_state : : TmapInfo_array & TmapInfo , d_flickering_light_state & Flickering_light_state , const trigger & t )
2006-03-20 17:12:09 +00:00
{
2016-01-09 16:38:11 +00:00
int ret = 0 ;
2022-01-09 15:25:42 +00:00
const auto op = [ & LevelSharedDestructibleLightState , & Flickering_light_state , & TmapInfo , & ret ] ( const vmsegptridx_t segnum , const sidenum_t sidenum ) {
2006-03-20 17:12:09 +00:00
//check if tmap2 casts light before turning the light off. This
//is to keep us from turning off blown-out lights
2020-08-24 01:31:28 +00:00
const auto tm2 = get_texture_index ( segnum - > unique_segment : : sides [ sidenum ] . tmap_num2 ) ;
if ( TmapInfo [ tm2 ] . lighting ) {
2018-12-30 00:43:58 +00:00
ret | = subtract_light ( LevelSharedDestructibleLightState , segnum , sidenum ) ; //any light sets flag
2018-03-31 21:53:01 +00:00
disable_flicker ( Flickering_light_state , segnum , sidenum ) ;
2006-03-20 17:12:09 +00:00
}
2016-01-09 16:38:11 +00:00
} ;
2017-06-10 03:31:02 +00:00
trigger_wall_op ( t , vmsegptridx , op ) ;
2006-03-20 17:12:09 +00:00
return ret ;
}
// Unlocks all doors linked to the switch.
2019-01-01 04:54:35 +00:00
static void do_unlock_doors ( fvcsegptr & vcsegptr , fvmwallptr & vmwallptr , const trigger & t )
2006-03-20 17:12:09 +00:00
{
2022-01-15 20:39:10 +00:00
const auto op = [ & vmwallptr ] ( const shared_segment & segp , const sidenum_t sidenum ) {
2018-12-13 02:31:38 +00:00
const auto wall_num = segp . sides [ sidenum ] . wall_num ;
2021-06-14 03:16:56 +00:00
if ( wall_num = = wall_none )
return ;
2017-06-10 03:31:02 +00:00
auto & w = * vmwallptr ( wall_num ) ;
2021-11-01 03:37:19 +00:00
w . flags & = ~ wall_flag : : door_locked ;
2020-12-19 16:13:26 +00:00
w . keys = wall_key : : none ;
2016-01-09 16:38:11 +00:00
} ;
2018-12-13 02:31:38 +00:00
trigger_wall_op ( t , vcsegptr , op ) ;
2006-03-20 17:12:09 +00:00
}
// Locks all doors linked to the switch.
2019-01-01 04:54:35 +00:00
static void do_lock_doors ( fvcsegptr & vcsegptr , fvmwallptr & vmwallptr , const trigger & t )
2006-03-20 17:12:09 +00:00
{
2022-01-15 20:39:10 +00:00
const auto op = [ & vmwallptr ] ( const shared_segment & segp , const sidenum_t sidenum ) {
2018-12-13 02:31:38 +00:00
const auto wall_num = segp . sides [ sidenum ] . wall_num ;
2021-06-14 03:16:56 +00:00
if ( wall_num = = wall_none )
return ;
2017-06-10 03:31:02 +00:00
auto & w = * vmwallptr ( wall_num ) ;
2021-11-01 03:37:19 +00:00
w . flags | = wall_flag : : door_locked ;
2016-01-09 16:38:11 +00:00
} ;
2018-12-13 02:31:38 +00:00
trigger_wall_op ( t , vcsegptr , op ) ;
2006-03-20 17:12:09 +00:00
}
// Changes walls pointed to by a trigger. returns true if any walls changed
2016-01-09 16:38:11 +00:00
static int do_change_walls ( const trigger & t , const uint8_t new_wall_type )
2006-03-20 17:12:09 +00:00
{
2020-05-17 23:35:25 +00:00
auto & LevelSharedVertexState = LevelSharedSegmentState . get_vertex_state ( ) ;
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
2020-05-17 23:35:25 +00:00
auto & Vertices = LevelSharedVertexState . get_vertices ( ) ;
2019-03-03 00:31:08 +00:00
auto & vmobjptr = Objects . vmptr ;
2016-01-09 16:38:11 +00:00
int ret = 0 ;
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:59 +00:00
auto & TmapInfo = LevelUniqueTmapInfoState . TmapInfo ;
2018-12-30 00:43:58 +00:00
auto & Walls = LevelUniqueWallSubsystemState . Walls ;
auto & vmwallptr = Walls . vmptr ;
2016-01-09 16:38:11 +00:00
for ( unsigned i = 0 ; i < t . num_links ; + + i )
2015-04-26 20:15:50 +00:00
{
2022-01-15 20:39:10 +00:00
sidenum_t cside ;
2017-06-10 03:31:02 +00:00
const auto & & segp = vmsegptridx ( t . seg [ i ] ) ;
2016-01-09 16:38:11 +00:00
const auto side = t . side [ i ] ;
2017-06-10 03:31:02 +00:00
imsegptridx_t csegp = segment_none ;
2006-03-20 17:12:09 +00:00
2015-04-26 20:15:50 +00:00
if ( ! IS_CHILD ( segp - > children [ side ] ) )
2006-03-20 17:12:09 +00:00
{
2016-01-09 16:38:11 +00:00
cside = side_none ;
2006-03-20 17:12:09 +00:00
}
else
{
2017-06-10 03:31:02 +00:00
csegp = imsegptridx ( segp - > children [ side ] ) ;
2006-03-20 17:12:09 +00:00
cside = find_connect_side ( segp , csegp ) ;
2016-01-03 20:21:35 +00:00
Assert ( cside ! = side_none ) ;
2006-03-20 17:12:09 +00:00
}
2016-10-08 18:02:34 +00:00
wall * w0p ;
2018-12-13 02:31:38 +00:00
const auto w0num = segp - > shared_segment : : sides [ side ] . wall_num ;
2017-06-10 03:31:02 +00:00
if ( const auto & & uw0p = vmwallptr . check_untrusted ( w0num ) )
2017-01-28 18:12:20 +00:00
w0p = * uw0p ;
else
{
2022-06-05 17:44:52 +00:00
LevelError ( " trigger %p link %u tried to open segment %hu, side %u which is an invalid wall; ignoring. " , std : : addressof ( t ) , i , static_cast < segnum_t > ( segp ) , underlying_value ( side ) ) ;
2016-10-08 18:02:34 +00:00
continue ;
}
auto & wall0 = * w0p ;
2017-06-10 03:31:02 +00:00
imwallptr_t wall1 = nullptr ;
2018-12-13 02:31:38 +00:00
if ( ( cside = = side_none | | csegp - > shared_segment : : sides [ cside ] . wall_num = = wall_none | |
( wall1 = vmwallptr ( csegp - > shared_segment : : sides [ cside ] . wall_num ) ) - > type = = new_wall_type ) & &
2016-04-05 01:10:18 +00:00
wall0 . type = = new_wall_type )
2006-03-20 17:12:09 +00:00
continue ; //already in correct state, so skip
2016-01-09 16:38:11 +00:00
ret | = 1 ;
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:57 +00:00
auto & vcvertptr = Vertices . vcptr ;
2016-01-09 16:38:11 +00:00
switch ( t . type )
{
2020-07-05 23:34:32 +00:00
case trigger_action : : open_wall :
2021-11-01 03:37:20 +00:00
if ( ( TmapInfo [ get_texture_index ( segp - > unique_segment : : sides [ side ] . tmap_num ) ] . flags & tmapinfo_flag : : force_field ) )
{
2016-01-09 16:38:11 +00:00
ret | = 2 ;
2018-03-12 03:43:47 +00:00
const auto & & pos = compute_center_point_on_side ( vcvertptr , segp , side ) ;
2014-10-02 03:02:34 +00:00
digi_link_sound_to_pos ( SOUND_FORCEFIELD_OFF , segp , side , pos , 0 , F1_0 ) ;
digi_kill_sound_linked_to_segment ( segp , side , SOUND_FORCEFIELD_HUM ) ;
2016-01-09 16:38:11 +00:00
wall0 . type = new_wall_type ;
if ( wall1 )
2006-03-20 17:12:09 +00:00
{
2016-01-09 16:38:11 +00:00
wall1 - > type = new_wall_type ;
2014-10-02 03:02:34 +00:00
digi_kill_sound_linked_to_segment ( csegp , cside , SOUND_FORCEFIELD_HUM ) ;
2006-03-20 17:12:09 +00:00
}
}
else
start_wall_cloak ( segp , side ) ;
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : close_wall :
2021-11-01 03:37:20 +00:00
if ( ( TmapInfo [ get_texture_index ( segp - > unique_segment : : sides [ side ] . tmap_num ) ] . flags & tmapinfo_flag : : force_field ) )
{
2016-01-09 16:38:11 +00:00
ret | = 2 ;
2016-01-09 16:38:11 +00:00
{
2018-03-12 03:43:47 +00:00
const auto & & pos = compute_center_point_on_side ( vcvertptr , segp , side ) ;
2014-10-02 03:02:34 +00:00
digi_link_sound_to_pos ( SOUND_FORCEFIELD_HUM , segp , side , pos , 1 , F1_0 / 2 ) ;
2016-01-09 16:38:11 +00:00
}
2020-07-05 23:34:32 +00:00
case trigger_action : : illusory_wall :
2016-01-09 16:38:11 +00:00
wall0 . type = new_wall_type ;
if ( wall1 )
wall1 - > type = new_wall_type ;
2006-03-20 17:12:09 +00:00
}
else
start_wall_decloak ( segp , side ) ;
break ;
2016-01-09 16:38:11 +00:00
default :
return 0 ;
2006-03-20 17:12:09 +00:00
}
2018-12-13 02:31:38 +00:00
LevelUniqueStuckObjectState . kill_stuck_objects ( vmobjptr , segp - > shared_segment : : sides [ side ] . wall_num ) ;
2016-01-09 16:38:11 +00:00
if ( wall1 )
2018-12-13 02:31:38 +00:00
LevelUniqueStuckObjectState . kill_stuck_objects ( vmobjptr , csegp - > shared_segment : : sides [ cside ] . wall_num ) ;
2006-03-20 17:12:09 +00:00
}
2016-07-21 01:43:21 +00:00
flush_fcd_cache ( ) ;
2006-03-20 17:12:09 +00:00
return ret ;
}
2013-01-03 16:00:40 +00:00
# define print_trigger_message(pnum,trig,shot,message) \
2016-01-09 16:38:11 +00:00
( ( void ) ( ( print_trigger_message ( pnum , trig , shot ) ) & & \
HUD_init_message ( HM_DEFAULT , message , & " s " [ trig . num_links < = 1 ] ) ) )
2006-03-20 17:12:09 +00:00
2016-01-09 16:38:11 +00:00
static int ( print_trigger_message ) ( int pnum , const trigger & t , int shot )
2013-01-03 16:00:40 +00:00
{
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
if ( shot & & pnum = = Player_num & & ! ( t . flags & trigger_behavior_flags : : no_message ) )
2013-01-03 16:00:40 +00:00
return 1 ;
return 0 ;
2006-03-20 17:12:09 +00:00
}
2016-08-25 04:05:32 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2016-01-09 16:38:11 +00:00
static void do_matcen ( const trigger & t )
2006-03-20 17:12:09 +00:00
{
2016-02-12 04:02:28 +00:00
range_for ( auto & i , partial_const_range ( t . seg , t . num_links ) )
2017-06-10 03:31:02 +00:00
trigger_matcen ( vmsegptridx ( i ) ) ;
2006-03-20 17:12:09 +00:00
}
2019-01-01 04:54:35 +00:00
static void do_il_on ( fvcsegptridx & vcsegptridx , fvmwallptr & vmwallptr , const trigger & t )
2006-03-20 17:12:09 +00:00
{
2019-01-01 04:54:35 +00:00
trigger_wall_op ( t , vcsegptridx , wall_illusion_on , vmwallptr ) ;
2006-03-20 17:12:09 +00:00
}
2016-08-25 04:05:32 +00:00
namespace dsx {
2019-01-01 04:54:35 +00:00
# if defined(DXX_BUILD_DESCENT_I)
static void do_il_off ( fvcsegptridx & vcsegptridx , fvmwallptr & vmwallptr , const trigger & t )
2006-03-20 17:12:09 +00:00
{
2019-01-01 04:54:35 +00:00
trigger_wall_op ( t , vcsegptridx , wall_illusion_off , vmwallptr ) ;
}
# elif defined(DXX_BUILD_DESCENT_II)
static void do_il_off ( fvcsegptridx & vcsegptridx , fvcvertptr & vcvertptr , fvmwallptr & vmwallptr , const trigger & t )
{
2022-01-15 20:39:10 +00:00
const auto & & op = [ & vcvertptr , & vmwallptr ] ( const vcsegptridx_t seg , const sidenum_t side ) {
2018-12-13 02:31:38 +00:00
wall_illusion_off ( vmwallptr , seg , side ) ;
2018-03-12 03:43:47 +00:00
const auto & & cp = compute_center_point_on_side ( vcvertptr , seg , side ) ;
2016-01-09 16:38:11 +00:00
digi_link_sound_to_pos ( SOUND_WALL_REMOVED , seg , side , cp , 0 , F1_0 ) ;
2018-12-13 02:31:38 +00:00
} ;
trigger_wall_op ( t , vcsegptridx , op ) ;
2006-03-20 17:12:09 +00:00
}
2019-01-01 04:54:35 +00:00
# endif
2006-03-20 17:12:09 +00:00
2016-12-24 08:50:29 +00:00
// Slight variation on window_event_result meaning
// 'ignored' means we still want check_trigger to call multi_send_trigger
// 'handled' or 'close' means we don't
// 'close' will still close the game window
2017-08-13 20:38:31 +00:00
window_event_result check_trigger_sub ( object & plrobj , const trgnum_t trigger_num , const playernum_t pnum , const unsigned shot )
2006-03-20 17:12:09 +00:00
{
2020-05-17 23:35:25 +00:00
# if defined(DXX_BUILD_DESCENT_II)
auto & LevelSharedVertexState = LevelSharedSegmentState . get_vertex_state ( ) ;
auto & Vertices = LevelSharedVertexState . get_vertices ( ) ;
# endif
2019-08-15 01:34:22 +00:00
auto & LevelUniqueControlCenterState = LevelUniqueObjectState . ControlCenterState ;
2016-12-24 08:50:29 +00:00
auto result = window_event_result : : ignored ;
2017-08-13 20:38:32 +00:00
if ( ( Game_mode & GM_MULTI ) & & vcplayerptr ( pnum ) - > connected ! = CONNECT_PLAYING ) // as a host we may want to handle triggers for our clients. to do that properly we must check wether we (host) or client is actually playing.
2016-12-24 08:50:29 +00:00
return window_event_result : : handled ;
2018-12-30 00:43:58 +00:00
auto & Triggers = LevelUniqueWallSubsystemState . Triggers ;
auto & vmtrgptr = Triggers . vmptr ;
2017-06-10 03:31:02 +00:00
auto & trigger = * vmtrgptr ( trigger_num ) ;
2019-01-01 04:54:35 +00:00
auto & Walls = LevelUniqueWallSubsystemState . Walls ;
auto & vmwallptr = Walls . vmptr ;
2012-05-25 10:14:28 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
( void ) shot ;
if ( pnum = = Player_num ) {
2016-10-02 00:34:47 +00:00
auto & player_info = plrobj . ctype . player_info ;
2016-01-09 16:38:11 +00:00
if ( trigger . flags & TRIGGER_SHIELD_DAMAGE ) {
2016-10-02 00:34:47 +00:00
plrobj . shields - = trigger . value ;
2013-03-03 01:03:33 +00:00
}
2016-12-24 08:50:29 +00:00
if ( trigger . flags & TRIGGER_EXIT )
{
result = start_endlevel_sequence ( ) ;
if ( result = = window_event_result : : handled )
result = window_event_result : : ignored ; // call multi_send_trigger, or end game anyway
2013-03-03 01:03:33 +00:00
}
2016-01-09 16:38:11 +00:00
if ( trigger . flags & TRIGGER_SECRET_EXIT ) {
2016-12-24 08:50:29 +00:00
if ( trigger . flags & TRIGGER_EXIT )
2021-09-04 12:17:14 +00:00
LevelError ( " Trigger %u is both a regular and secret exit! This is not a recommended combination. " , underlying_value ( trigger_num ) ) ;
2013-03-03 01:03:33 +00:00
if ( Newdemo_state = = ND_STATE_RECORDING ) // stop demo recording
Newdemo_state = ND_STATE_PAUSED ;
if ( Game_mode & GM_MULTI )
2016-11-12 18:10:09 +00:00
multi_send_endlevel_start ( multi_endlevel_type : : secret ) ;
2013-03-03 01:03:33 +00:00
if ( Game_mode & GM_NETWORK )
2020-12-20 20:39:07 +00:00
multi : : dispatch - > do_protocol_frame ( 1 , 1 ) ;
2016-12-24 08:50:29 +00:00
result = std : : max ( PlayerFinishedLevel ( 1 ) , result ) ; //1 means go to secret level
2019-08-15 01:34:22 +00:00
LevelUniqueControlCenterState . Control_center_destroyed = 0 ;
2016-12-24 08:50:29 +00:00
return std : : max ( result , window_event_result : : handled ) ;
2013-03-03 01:03:33 +00:00
}
2016-01-09 16:38:11 +00:00
if ( trigger . flags & TRIGGER_ENERGY_DRAIN ) {
2016-09-11 18:49:13 +00:00
player_info . energy - = trigger . value ;
2013-03-03 01:03:33 +00:00
}
}
2016-01-09 16:38:11 +00:00
if ( trigger . flags & TRIGGER_CONTROL_DOORS ) {
do_link ( trigger ) ;
2013-03-03 01:03:33 +00:00
}
2016-01-09 16:38:11 +00:00
if ( trigger . flags & TRIGGER_MATCEN ) {
2013-03-03 01:03:33 +00:00
if ( ! ( Game_mode & GM_MULTI ) | | ( Game_mode & GM_MULTI_ROBOTS ) )
2016-01-09 16:38:11 +00:00
do_matcen ( trigger ) ;
2013-03-03 01:03:33 +00:00
}
2016-01-09 16:38:11 +00:00
if ( trigger . flags & TRIGGER_ILLUSION_ON ) {
2019-01-01 04:54:35 +00:00
do_il_on ( vcsegptridx , vmwallptr , trigger ) ;
2013-03-03 01:03:33 +00:00
}
2016-01-09 16:38:11 +00:00
if ( trigger . flags & TRIGGER_ILLUSION_OFF ) {
2019-01-01 04:54:35 +00:00
do_il_off ( vcsegptridx , vmwallptr , trigger ) ;
2013-03-03 01:03:33 +00:00
}
# elif defined(DXX_BUILD_DESCENT_II)
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
if ( trigger . flags & trigger_behavior_flags : : disabled )
2016-12-24 08:50:29 +00:00
return window_event_result : : handled ; // don't send trigger hit to other players
2006-03-20 17:12:09 +00:00
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
if ( trigger . flags & trigger_behavior_flags : : one_shot ) //if this is a one-shot...
trigger . flags | = trigger_behavior_flags : : disabled ; //..then don't let it happen again
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:58 +00:00
auto & LevelSharedDestructibleLightState = LevelSharedSegmentState . DestructibleLights ;
2019-01-01 04:54:35 +00:00
auto & TmapInfo = LevelUniqueTmapInfoState . TmapInfo ;
auto & vcvertptr = Vertices . vcptr ;
2016-01-09 16:38:11 +00:00
switch ( trigger . type )
{
2020-07-05 23:34:32 +00:00
case trigger_action : : normal_exit :
2006-03-20 17:12:09 +00:00
if ( pnum ! = Player_num )
2016-12-24 08:50:29 +00:00
break ;
2006-03-20 17:12:09 +00:00
2016-12-24 08:50:29 +00:00
if ( ! EMULATING_D1 )
digi_stop_digi_sounds ( ) ; //Sound shouldn't cut out when exiting a D1 lvl
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
if ( Current_level_num > 0 ) {
2016-12-24 08:50:29 +00:00
result = start_endlevel_sequence ( ) ;
2006-03-20 17:12:09 +00:00
} else if ( Current_level_num < 0 ) {
2016-10-02 00:34:47 +00:00
if ( plrobj . shields < 0 | |
2015-12-15 04:09:35 +00:00
Player_dead_state ! = player_dead_state : : no )
2006-03-20 17:12:09 +00:00
break ;
2007-04-14 20:44:09 +00:00
// NMN 04/09/07 Do endlevel movie if we are
// playing a D1 secret level
2010-06-14 08:13:16 +00:00
if ( EMULATING_D1 )
2007-04-14 20:44:09 +00:00
{
2016-12-24 08:50:29 +00:00
result = start_endlevel_sequence ( ) ;
2007-04-14 20:44:09 +00:00
} else {
2016-12-24 08:50:29 +00:00
result = ExitSecretLevel ( ) ;
2007-04-14 20:44:09 +00:00
}
2016-12-24 08:50:29 +00:00
return std : : max ( result , window_event_result : : handled ) ;
2006-03-20 17:12:09 +00:00
}
2016-12-24 08:50:29 +00:00
return std : : max ( result , window_event_result : : handled ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : secret_exit : {
2006-03-20 17:12:09 +00:00
int truth ;
if ( pnum ! = Player_num )
break ;
2016-10-02 00:34:47 +00:00
if ( plrobj . shields < 0 | |
2015-12-15 04:09:35 +00:00
Player_dead_state ! = player_dead_state : : no )
2006-03-20 17:12:09 +00:00
break ;
2011-06-06 22:21:43 +00:00
if ( is_SHAREWARE | | is_MAC_SHARE ) {
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_DEFAULT , " Secret Level Teleporter disabled in Descent 2 Demo " ) ;
2011-06-06 22:21:43 +00:00
digi_play_sample ( SOUND_BAD_SELECTION , F1_0 ) ;
break ;
}
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_MULTI ) {
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_DEFAULT , " Secret Level Teleporter disabled in multiplayer! " ) ;
2006-03-20 17:12:09 +00:00
digi_play_sample ( SOUND_BAD_SELECTION , F1_0 ) ;
break ;
}
truth = p_secret_level_destroyed ( ) ;
if ( Newdemo_state = = ND_STATE_RECORDING ) // record whether we're really going to the secret level
newdemo_record_secret_exit_blown ( truth ) ;
if ( ( Newdemo_state ! = ND_STATE_PLAYBACK ) & & truth ) {
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_DEFAULT , " Secret Level destroyed. Exit disabled. " ) ;
2006-03-20 17:12:09 +00:00
digi_play_sample ( SOUND_BAD_SELECTION , F1_0 ) ;
break ;
}
if ( Newdemo_state = = ND_STATE_RECORDING ) // stop demo recording
Newdemo_state = ND_STATE_PAUSED ;
2010-06-14 08:13:16 +00:00
digi_stop_digi_sounds ( ) ;
2006-03-20 17:12:09 +00:00
EnterSecretLevel ( ) ;
2019-08-15 01:34:22 +00:00
LevelUniqueControlCenterState . Control_center_destroyed = 0 ;
2016-12-24 08:50:29 +00:00
return window_event_result : : handled ;
2006-03-20 17:12:09 +00:00
}
2020-07-05 23:34:32 +00:00
case trigger_action : : open_door :
2016-01-09 16:38:11 +00:00
do_link ( trigger ) ;
print_trigger_message ( pnum , trigger , shot , " Door%s opened! " ) ;
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : close_door :
2016-01-09 16:38:11 +00:00
do_close_door ( trigger ) ;
print_trigger_message ( pnum , trigger , shot , " Door%s closed! " ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : unlock_door :
2019-01-01 04:54:35 +00:00
do_unlock_doors ( vcsegptr , vmwallptr , trigger ) ;
2016-01-09 16:38:11 +00:00
print_trigger_message ( pnum , trigger , shot , " Door%s unlocked! " ) ;
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : lock_door :
2019-01-01 04:54:35 +00:00
do_lock_doors ( vcsegptr , vmwallptr , trigger ) ;
2016-01-09 16:38:11 +00:00
print_trigger_message ( pnum , trigger , shot , " Door%s locked! " ) ;
2006-03-20 17:12:09 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : open_wall :
2016-01-09 16:38:11 +00:00
if ( const auto w = do_change_walls ( trigger , WALL_OPEN ) )
2016-01-09 16:38:11 +00:00
print_trigger_message ( pnum , trigger , shot , ( w & 2 ) ? " Force field%s deactivated! " : " Wall%s opened! " ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : close_wall :
2016-01-09 16:38:11 +00:00
if ( const auto w = do_change_walls ( trigger , WALL_CLOSED ) )
2016-01-09 16:38:11 +00:00
print_trigger_message ( pnum , trigger , shot , ( w & 2 ) ? " Force field%s activated! " : " Wall%s closed! " ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : illusory_wall :
2006-03-20 17:12:09 +00:00
//don't know what to say, so say nothing
2016-01-09 16:38:11 +00:00
do_change_walls ( trigger , WALL_ILLUSION ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : matcen :
2006-03-20 17:12:09 +00:00
if ( ! ( Game_mode & GM_MULTI ) | | ( Game_mode & GM_MULTI_ROBOTS ) )
2016-01-09 16:38:11 +00:00
do_matcen ( trigger ) ;
2006-03-20 17:12:09 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : illusion_on :
2019-01-01 04:54:35 +00:00
do_il_on ( vcsegptridx , vmwallptr , trigger ) ;
2016-01-09 16:38:11 +00:00
print_trigger_message ( pnum , trigger , shot , " Illusion%s on! " ) ;
2006-03-20 17:12:09 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : illusion_off :
2019-01-01 04:54:35 +00:00
do_il_off ( vcsegptridx , vcvertptr , vmwallptr , trigger ) ;
2016-01-09 16:38:11 +00:00
print_trigger_message ( pnum , trigger , shot , " Illusion%s off! " ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : light_off :
2019-01-01 04:54:35 +00:00
if ( do_light_off ( LevelSharedDestructibleLightState , TmapInfo , Flickering_light_state , trigger ) )
2016-01-09 16:38:11 +00:00
print_trigger_message ( pnum , trigger , shot , " Light%s off! " ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : light_on :
2019-01-01 04:54:35 +00:00
if ( do_light_on ( LevelSharedDestructibleLightState , TmapInfo , Flickering_light_state , trigger ) )
2016-01-09 16:38:11 +00:00
print_trigger_message ( pnum , trigger , shot , " Light%s on! " ) ;
2006-03-20 17:12:09 +00:00
break ;
default :
Int3 ( ) ;
break ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2016-12-24 08:50:29 +00:00
return result ;
2006-03-20 17:12:09 +00:00
}
//-----------------------------------------------------------------
// Checks for a trigger whenever an object hits a trigger side.
2022-01-15 20:39:10 +00:00
window_event_result check_trigger ( const vcsegptridx_t seg , const sidenum_t side , object & plrobj , const vcobjptridx_t objnum , int shot )
2006-03-20 17:12:09 +00:00
{
2015-07-25 23:10:46 +00:00
if ( ( Game_mode & GM_MULTI ) & & ( get_local_player ( ) . connected ! = CONNECT_PLAYING ) ) // as a host we may want to handle triggers for our clients. so this function may be called when we are not playing.
2016-12-24 08:50:29 +00:00
return window_event_result : : ignored ;
2012-05-25 10:14:28 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2016-10-02 00:34:47 +00:00
if ( objnum = = & plrobj )
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2016-10-02 00:34:47 +00:00
if ( objnum = = & plrobj | | ( objnum - > type = = OBJ_ROBOT & & Robot_info [ get_robot_id ( objnum ) ] . companion ) )
2013-03-03 01:03:33 +00:00
# endif
{
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
if ( Newdemo_state = = ND_STATE_PLAYBACK )
2016-12-24 08:50:29 +00:00
return window_event_result : : ignored ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Newdemo_state = = ND_STATE_RECORDING )
2014-10-02 03:02:34 +00:00
newdemo_record_trigger ( seg , side , objnum , shot ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2018-12-13 02:31:38 +00:00
const auto wall_num = seg - > shared_segment : : sides [ side ] . wall_num ;
2016-12-24 08:50:29 +00:00
if ( wall_num = = wall_none ) return window_event_result : : ignored ;
2010-06-14 08:13:16 +00:00
2018-12-30 00:43:58 +00:00
auto & Walls = LevelUniqueWallSubsystemState . Walls ;
auto & vcwallptr = Walls . vcptr ;
const auto trigger_num = vcwallptr ( wall_num ) - > trigger ;
2015-04-26 20:15:50 +00:00
if ( trigger_num = = trigger_none )
2016-12-24 08:50:29 +00:00
return window_event_result : : ignored ;
2006-03-20 17:12:09 +00:00
2016-12-24 08:50:29 +00:00
{
auto result = check_trigger_sub ( plrobj , trigger_num , Player_num , shot ) ;
if ( result ! = window_event_result : : ignored )
return result ;
}
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_MULTI )
multi_send_trigger ( trigger_num ) ;
}
2016-12-24 08:50:29 +00:00
return window_event_result : : handled ;
2006-03-20 17:12:09 +00:00
}
/*
2016-01-09 16:38:14 +00:00
* reads a v29_trigger structure from a PHYSFS_File
2006-03-20 17:12:09 +00:00
*/
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2014-02-09 05:56:44 +00:00
void v26_trigger_read ( PHYSFS_File * fp , trigger & t )
{
2020-07-05 23:34:32 +00:00
switch ( const auto type = static_cast < trigger_action > ( PHYSFSX_readByte ( fp ) ) )
2014-02-09 05:56:44 +00:00
{
2020-07-05 23:34:32 +00:00
case trigger_action : : open_door : // door
2014-02-09 05:56:44 +00:00
t . flags = TRIGGER_CONTROL_DOORS ;
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : matcen : // matcen
2014-02-09 05:56:44 +00:00
t . flags = TRIGGER_MATCEN ;
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : normal_exit : // exit
2014-02-09 05:56:44 +00:00
t . flags = TRIGGER_EXIT ;
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : secret_exit : // secret exit
2014-02-09 05:56:44 +00:00
t . flags = TRIGGER_SECRET_EXIT ;
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : illusion_off : // illusion off
2014-02-09 05:56:44 +00:00
t . flags = TRIGGER_ILLUSION_OFF ;
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : illusion_on : // illusion on
2014-02-09 05:56:44 +00:00
t . flags = TRIGGER_ILLUSION_ON ;
break ;
default :
2020-07-05 23:34:32 +00:00
con_printf ( CON_URGENT , " error: unsupported trigger type %d " , static_cast < int > ( type ) ) ;
2014-02-09 05:56:44 +00:00
throw std : : runtime_error ( " unsupported trigger type " ) ;
}
2016-02-06 22:12:54 +00:00
if ( PHYSFSX_readByte ( fp ) & 2 ) // one shot
t . flags | = TRIGGER_ONE_SHOT ;
2014-02-09 05:56:44 +00:00
t . num_links = PHYSFSX_readShort ( fp ) ;
t . value = PHYSFSX_readInt ( fp ) ;
2016-02-06 22:12:55 +00:00
PHYSFSX_readInt ( fp ) ;
2014-02-09 05:56:44 +00:00
for ( unsigned i = 0 ; i < MAX_WALLS_PER_LINK ; i + + )
t . seg [ i ] = PHYSFSX_readShort ( fp ) ;
for ( unsigned i = 0 ; i < MAX_WALLS_PER_LINK ; i + + )
2022-01-09 15:25:42 +00:00
{
auto s = build_sidenum_from_untrusted ( PHYSFSX_readShort ( fp ) ) ;
t . side [ i ] = s . value_or ( sidenum_t : : WLEFT ) ;
}
2014-02-09 05:56:44 +00:00
}
2016-01-09 16:38:14 +00:00
void v25_trigger_read ( PHYSFS_File * fp , trigger * t )
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2022-01-09 15:25:42 +00:00
void v29_trigger_read ( v29_trigger * t , PHYSFS_File * fp )
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
{
2014-02-08 23:25:29 +00:00
# if defined(DXX_BUILD_DESCENT_I)
PHYSFSX_readByte ( fp ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2011-06-01 07:59:55 +00:00
t - > type = PHYSFSX_readByte ( fp ) ;
2014-02-08 23:25:29 +00:00
# endif
2011-06-01 07:59:55 +00:00
t - > flags = PHYSFSX_readShort ( fp ) ;
t - > value = PHYSFSX_readFix ( fp ) ;
2016-02-06 22:12:55 +00:00
PHYSFSX_readFix ( fp ) ;
2018-12-30 00:43:58 +00:00
PHYSFSX_readByte ( fp ) ;
2011-06-01 07:59:55 +00:00
t - > num_links = PHYSFSX_readShort ( fp ) ;
2017-10-14 17:10:31 +00:00
for ( unsigned i = 0 ; i < MAX_WALLS_PER_LINK ; i + + )
2011-06-01 07:59:55 +00:00
t - > seg [ i ] = PHYSFSX_readShort ( fp ) ;
2017-10-14 17:10:31 +00:00
for ( unsigned i = 0 ; i < MAX_WALLS_PER_LINK ; i + + )
2022-01-09 15:25:42 +00:00
{
auto s = build_sidenum_from_untrusted ( PHYSFSX_readShort ( fp ) ) ;
t - > side [ i ] = s . value_or ( sidenum_t : : WLEFT ) ;
}
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
/*
2016-01-09 16:38:14 +00:00
* reads a v30_trigger structure from a PHYSFS_File
2006-03-20 17:12:09 +00:00
*/
2016-01-09 16:38:14 +00:00
extern void v30_trigger_read ( v30_trigger * t , PHYSFS_File * fp )
2006-03-20 17:12:09 +00:00
{
2011-06-01 07:59:55 +00:00
t - > flags = PHYSFSX_readShort ( fp ) ;
t - > num_links = PHYSFSX_readByte ( fp ) ;
t - > pad = PHYSFSX_readByte ( fp ) ;
t - > value = PHYSFSX_readFix ( fp ) ;
2022-04-16 19:38:02 +00:00
PHYSFSX_readFix ( fp ) ;
2017-10-14 17:10:31 +00:00
for ( unsigned i = 0 ; i < MAX_WALLS_PER_LINK ; i + + )
2011-06-01 07:59:55 +00:00
t - > seg [ i ] = PHYSFSX_readShort ( fp ) ;
2017-10-14 17:10:31 +00:00
for ( unsigned i = 0 ; i < MAX_WALLS_PER_LINK ; i + + )
2022-06-05 17:44:52 +00:00
t - > side [ i ] = build_sidenum_from_untrusted ( PHYSFSX_readShort ( fp ) ) . value_or ( sidenum_t : : WLEFT ) ;
2006-03-20 17:12:09 +00:00
}
2022-01-09 15:25:42 +00:00
namespace {
2014-02-09 05:45:27 +00:00
2020-07-05 23:34:32 +00:00
static trigger_action trigger_type_from_flags ( short flags )
2014-02-09 05:45:27 +00:00
{
if ( flags & TRIGGER_CONTROL_DOORS )
2020-07-05 23:34:32 +00:00
return trigger_action : : open_door ;
2015-11-08 18:55:51 +00:00
else if ( flags & ( TRIGGER_SHIELD_DAMAGE | TRIGGER_ENERGY_DRAIN ) )
{
}
2014-02-09 05:45:27 +00:00
else if ( flags & TRIGGER_EXIT )
2020-07-05 23:34:32 +00:00
return trigger_action : : normal_exit ;
2014-02-09 05:45:27 +00:00
else if ( flags & TRIGGER_MATCEN )
2020-07-05 23:34:32 +00:00
return trigger_action : : matcen ;
2014-02-09 05:45:27 +00:00
else if ( flags & TRIGGER_ILLUSION_OFF )
2020-07-05 23:34:32 +00:00
return trigger_action : : illusion_off ;
2014-02-09 05:45:27 +00:00
else if ( flags & TRIGGER_SECRET_EXIT )
2020-07-05 23:34:32 +00:00
return trigger_action : : secret_exit ;
2014-02-09 05:45:27 +00:00
else if ( flags & TRIGGER_ILLUSION_ON )
2020-07-05 23:34:32 +00:00
return trigger_action : : illusion_on ;
2014-02-09 05:45:27 +00:00
else if ( flags & TRIGGER_UNLOCK_DOORS )
2020-07-05 23:34:32 +00:00
return trigger_action : : unlock_door ;
2014-02-09 05:45:27 +00:00
else if ( flags & TRIGGER_OPEN_WALL )
2020-07-05 23:34:32 +00:00
return trigger_action : : open_wall ;
2014-02-09 05:45:27 +00:00
else if ( flags & TRIGGER_CLOSE_WALL )
2020-07-05 23:34:32 +00:00
return trigger_action : : close_wall ;
2014-02-09 05:45:27 +00:00
else if ( flags & TRIGGER_ILLUSORY_WALL )
2020-07-05 23:34:32 +00:00
return trigger_action : : illusory_wall ;
2015-11-08 18:55:51 +00:00
throw std : : runtime_error ( " unsupported trigger type " ) ;
2014-02-09 05:45:27 +00:00
}
static void v30_trigger_to_v31_trigger ( trigger & t , const v30_trigger & trig )
{
2020-07-07 04:09:44 +00:00
t . type = trigger_type_from_flags ( trig . flags ) ;
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
t . flags = ( trig . flags & TRIGGER_ONE_SHOT ) ? trigger_behavior_flags : : one_shot : trigger_behavior_flags { 0 } ;
2014-02-09 05:45:27 +00:00
t . num_links = trig . num_links ;
t . num_links = trig . num_links ;
t . value = trig . value ;
t . seg = trig . seg ;
2022-01-15 20:39:10 +00:00
for ( auto & & [ w , r ] : zip ( t . side , trig . side ) )
{
2022-06-05 17:44:52 +00:00
w = r ;
2022-01-15 20:39:10 +00:00
}
2014-02-09 05:45:27 +00:00
}
static void v29_trigger_read_as_v30 ( PHYSFS_File * fp , v30_trigger & trig )
{
v29_trigger trig29 ;
v29_trigger_read ( & trig29 , fp ) ;
trig . flags = trig29 . flags ;
// skip trig29.link_num. v30_trigger does not need it
trig . num_links = trig29 . num_links ;
trig . value = trig29 . value ;
trig . seg = trig29 . seg ;
trig . side = trig29 . side ;
}
2022-01-09 15:25:42 +00:00
}
2014-02-09 05:45:27 +00:00
void v29_trigger_read_as_v31 ( PHYSFS_File * fp , trigger & t )
{
v30_trigger trig ;
v29_trigger_read_as_v30 ( fp , trig ) ;
v30_trigger_to_v31_trigger ( t , trig ) ;
}
void v30_trigger_read_as_v31 ( PHYSFS_File * fp , trigger & t )
{
v30_trigger trig ;
v30_trigger_read ( & trig , fp ) ;
v30_trigger_to_v31_trigger ( t , trig ) ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2022-01-15 20:39:10 +00:00
namespace {
template < typename array_type >
struct serialize_wide_trigger_side_numbers
{
array_type & side ;
serialize_wide_trigger_side_numbers ( array_type & t ) :
side ( t )
{
}
} ;
template < typename array_type >
serial : : message < std : : array < uint16_t , std : : tuple_size < array_type > : : value > > udt_to_message ( const serialize_wide_trigger_side_numbers < array_type > & ) ;
template < typename Accessor , typename array_type >
void process_udt ( Accessor & accessor , serialize_wide_trigger_side_numbers < array_type > wrapper )
{
static_assert ( std : : is_const < array_type > : : value ! = std : : is_const < typename Accessor : : value_type > : : value ) ;
std : : array < uint16_t , MAX_WALLS_PER_LINK > a ;
if constexpr ( std : : is_const < array_type > : : value )
{
/* The array is constant, so it is already initialized and
* should be written out .
*/
for ( auto & & [ w , r ] : zip ( a , wrapper . side ) )
w = underlying_value ( r ) ;
process_buffer ( accessor , a ) ;
}
else
{
/* The array is non-constant, so it is initially undefined and
* should be read in .
*/
process_buffer ( accessor , a ) ;
for ( auto & & [ w , r ] : zip ( wrapper . side , a ) )
{
auto s = build_sidenum_from_untrusted ( r ) ;
w = s . value_or ( sidenum_t : : WLEFT ) ;
}
}
}
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2022-01-15 20:39:10 +00:00
DEFINE_SERIAL_UDT_TO_MESSAGE ( trigger , t , ( serial : : pad < 1 > ( ) , t . flags , t . value , serial : : pad < 5 > ( ) , t . num_links , serial : : pad < 1 , 0 > ( ) , t . seg , serialize_wide_trigger_side_numbers { t . side } ) ) ;
2014-01-12 23:00:43 +00:00
ASSERT_SERIAL_UDT_MESSAGE_SIZE ( trigger , 54 ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2022-01-15 20:39:10 +00:00
DEFINE_SERIAL_UDT_TO_MESSAGE ( trigger , t , ( t . type , t . flags , t . num_links , serial : : pad < 1 > ( ) , t . value , serial : : pad < 4 > ( ) , t . seg , serialize_wide_trigger_side_numbers { t . side } ) ) ;
2014-01-12 23:00:43 +00:00
ASSERT_SERIAL_UDT_MESSAGE_SIZE ( trigger , 52 ) ;
2013-03-03 01:03:33 +00:00
# endif
2009-10-05 02:51:37 +00:00
2016-01-09 16:38:14 +00:00
void trigger_read ( PHYSFS_File * fp , trigger & t )
2009-10-05 02:51:37 +00:00
{
2014-01-12 23:00:43 +00:00
PHYSFSX_serialize_read ( fp , t ) ;
}
2010-06-14 08:13:16 +00:00
2016-01-09 16:38:14 +00:00
void trigger_write ( PHYSFS_File * fp , const trigger & t )
2014-01-12 23:00:43 +00:00
{
PHYSFSX_serialize_write ( fp , t ) ;
2009-10-05 02:51:37 +00:00
}
2016-01-09 16:38:14 +00:00
void v29_trigger_write ( PHYSFS_File * fp , const trigger & rt )
2006-03-20 17:12:09 +00:00
{
2014-02-09 18:41:42 +00:00
const trigger * t = & rt ;
PHYSFSX_writeU8 ( fp , 0 ) ; // unused 'type'
# if defined(DXX_BUILD_DESCENT_I)
PHYSFS_writeSLE16 ( fp , t - > flags ) ;
# elif defined(DXX_BUILD_DESCENT_II)
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
const auto one_shot_flag = ( t - > flags & trigger_behavior_flags : : one_shot ) ? TRIGGER_ONE_SHOT : TRIGGER_FLAG { 0 } ;
2014-02-09 18:41:42 +00:00
switch ( t - > type )
2013-03-03 01:03:33 +00:00
{
2020-07-05 23:34:32 +00:00
case trigger_action : : open_door :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_CONTROL_DOORS | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : normal_exit :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_EXIT | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : matcen :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_MATCEN | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : illusion_off :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_ILLUSION_OFF | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : secret_exit :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_SECRET_EXIT | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : illusion_on :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_ILLUSION_ON | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : unlock_door :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_UNLOCK_DOORS | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : open_wall :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_OPEN_WALL | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : close_wall :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_CLOSE_WALL | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2020-07-05 23:34:32 +00:00
case trigger_action : : illusory_wall :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_ILLUSORY_WALL | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
default :
Int3 ( ) ;
PHYSFS_writeSLE16 ( fp , 0 ) ;
break ;
}
# endif
PHYSFSX_writeFix ( fp , t - > value ) ;
2016-02-06 22:12:55 +00:00
PHYSFSX_writeFix ( fp , 0 ) ;
2014-02-09 18:41:42 +00:00
PHYSFSX_writeU8 ( fp , - 1 ) ; //t->link_num
PHYSFS_writeSLE16 ( fp , t - > num_links ) ;
2006-03-20 17:12:09 +00:00
2014-02-09 18:41:42 +00:00
for ( unsigned i = 0 ; i < MAX_WALLS_PER_LINK ; i + + )
PHYSFS_writeSLE16 ( fp , t - > seg [ i ] ) ;
2022-06-05 17:44:52 +00:00
for ( const auto i : xrange ( MAX_WALLS_PER_LINK ) )
PHYSFS_writeSLE16 ( fp , underlying_value ( t - > side [ i ] ) ) ;
2014-02-09 18:41:42 +00:00
}
2016-08-25 04:05:32 +00:00
}
2014-02-09 18:41:42 +00:00
2016-08-25 04:05:32 +00:00
namespace dsx {
2016-01-09 16:38:14 +00:00
void v30_trigger_write ( PHYSFS_File * fp , const trigger & rt )
2014-02-09 18:41:42 +00:00
{
const trigger * t = & rt ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2020-07-05 23:34:32 +00:00
uint8_t action ;
2014-02-09 18:41:42 +00:00
if ( t - > flags & TRIGGER_CONTROL_DOORS )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : open_door ) ; // door
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_MATCEN )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : matcen ) ; // matcen
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_EXIT )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : normal_exit ) ; // exit
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_SECRET_EXIT )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : secret_exit ) ; // secret exit
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_ILLUSION_OFF )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : illusion_off ) ; // illusion off
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_ILLUSION_ON )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : illusion_on ) ; // illusion on
else
action = 0 ;
PHYSFSX_writeU8 ( fp , action ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2020-07-05 23:34:32 +00:00
PHYSFSX_writeU8 ( fp , static_cast < uint8_t > ( t - > type ) ) ;
2014-02-09 18:41:42 +00:00
# endif
2006-03-20 17:12:09 +00:00
2014-02-09 18:41:42 +00:00
# if defined(DXX_BUILD_DESCENT_I)
PHYSFS_writeSLE16 ( fp , t - > flags ) ;
# elif defined(DXX_BUILD_DESCENT_II)
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
const auto one_shot_flag = ( t - > flags & trigger_behavior_flags : : one_shot ) ? TRIGGER_ONE_SHOT : TRIGGER_FLAG { 0 } ;
2014-02-09 18:41:42 +00:00
switch ( t - > type )
{
2020-07-05 23:34:32 +00:00
case trigger_action : : open_door :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_CONTROL_DOORS | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2006-03-20 17:12:09 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : normal_exit :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_EXIT | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : matcen :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_MATCEN | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : illusion_off :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_ILLUSION_OFF | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : secret_exit :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_SECRET_EXIT | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : illusion_on :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_ILLUSION_ON | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : unlock_door :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_UNLOCK_DOORS | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : open_wall :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_OPEN_WALL | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : close_wall :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_CLOSE_WALL | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
2010-06-14 08:13:16 +00:00
2020-07-05 23:34:32 +00:00
case trigger_action : : illusory_wall :
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFS_writeSLE16 ( fp , TRIGGER_ILLUSORY_WALL | one_shot_flag ) ;
2014-02-09 18:41:42 +00:00
break ;
default :
Int3 ( ) ;
PHYSFS_writeSLE16 ( fp , 0 ) ;
break ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2014-02-09 18:41:42 +00:00
PHYSFSX_writeU8 ( fp , t - > num_links ) ;
PHYSFSX_writeU8 ( fp , 0 ) ; // t->pad
2006-03-20 17:12:09 +00:00
PHYSFSX_writeFix ( fp , t - > value ) ;
2016-02-06 22:12:55 +00:00
PHYSFSX_writeFix ( fp , 0 ) ;
2006-03-20 17:12:09 +00:00
2014-02-09 18:41:42 +00:00
for ( unsigned i = 0 ; i < MAX_WALLS_PER_LINK ; i + + )
PHYSFS_writeSLE16 ( fp , t - > seg [ i ] ) ;
2022-06-05 17:44:52 +00:00
for ( const auto i : xrange ( MAX_WALLS_PER_LINK ) )
PHYSFS_writeSLE16 ( fp , underlying_value ( t - > side [ i ] ) ) ;
2014-02-09 18:41:42 +00:00
}
2016-08-25 04:05:32 +00:00
}
2014-02-09 18:41:42 +00:00
2016-08-25 04:05:32 +00:00
namespace dsx {
2016-01-09 16:38:14 +00:00
void v31_trigger_write ( PHYSFS_File * fp , const trigger & rt )
2014-02-09 18:41:42 +00:00
{
const trigger * t = & rt ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2020-07-05 23:34:32 +00:00
uint8_t action ;
2014-02-09 18:41:42 +00:00
if ( t - > flags & TRIGGER_CONTROL_DOORS )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : open_door ) ; // door
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_MATCEN )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : matcen ) ; // matcen
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_EXIT )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : normal_exit ) ; // exit
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_SECRET_EXIT )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : secret_exit ) ; // secret exit
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_ILLUSION_OFF )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : illusion_off ) ; // illusion off
2014-02-09 18:41:42 +00:00
else if ( t - > flags & TRIGGER_ILLUSION_ON )
2020-07-05 23:34:32 +00:00
action = static_cast < uint8_t > ( trigger_action : : illusion_on ) ; // illusion on
else
action = 0 ;
PHYSFSX_writeU8 ( fp , action ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2020-07-05 23:34:32 +00:00
PHYSFSX_writeU8 ( fp , static_cast < uint8_t > ( t - > type ) ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2014-02-09 18:41:42 +00:00
# if defined(DXX_BUILD_DESCENT_I)
PHYSFSX_writeU8 ( fp , ( t - > flags & TRIGGER_ONE_SHOT ) ? 2 : 0 ) ; // flags
# elif defined(DXX_BUILD_DESCENT_II)
Tighten type for trigger behavior flags
Use an enum class to prevent implicit conversion between trigger
behavior flags and other integers. Fix up various resulting breaks,
which look like bugs:
- Descent 2 editor mode could modify trigger::flags, but used
TRIGGER_FLAG_* values, which specify the actions for a Descent 1
trigger when it executes, not the behavior properties for a trigger.
- Adding a trigger set its flags to 0, then cleared all flags except
TRIGGER_ON. Since the flags were just set to 0, the mask operation is
useless. Remove it.
- trigger_turn_all_ON cleared all flags except TRIGGER_ON. This seems
to be completely wrong. Change it to remove
trigger_behavior_flags::disabled. Descent 1 has no (working) support
for disabling triggers, so make trigger_turn_all_ON exclusive to
Descent 2.
- wall_restore_all would enable TRIGGER_ON in both games. Descent 1
never reads TRIGGER_ON. Descent 2 uses this field for trigger
behavior flags, and TRIGGER_ON is not a behavior flag.
- For Descent 1 builds, remove the modification of the field.
- For Descent 2 builds, change it to clear
trigger_behavior_flags::disabled.
2020-07-05 23:34:32 +00:00
PHYSFSX_writeU8 ( fp , static_cast < uint8_t > ( t - > flags ) ) ;
2014-02-09 18:41:42 +00:00
# endif
PHYSFSX_writeU8 ( fp , t - > num_links ) ;
PHYSFSX_writeU8 ( fp , 0 ) ; // t->pad
PHYSFSX_writeFix ( fp , t - > value ) ;
2016-02-06 22:12:55 +00:00
PHYSFSX_writeFix ( fp , 0 ) ;
2014-02-09 18:41:42 +00:00
for ( unsigned i = 0 ; i < MAX_WALLS_PER_LINK ; i + + )
2006-03-20 17:12:09 +00:00
PHYSFS_writeSLE16 ( fp , t - > seg [ i ] ) ;
2022-06-05 17:44:52 +00:00
for ( const auto i : xrange ( MAX_WALLS_PER_LINK ) )
PHYSFS_writeSLE16 ( fp , underlying_value ( t - > side [ i ] ) ) ;
2006-03-20 17:12:09 +00:00
}
2016-08-25 04:05:32 +00:00
}