#!/usr/bin/env perl # rockslevel - Runs a specified Rocks'n'Diamonds levelset # License: BSD-style [for this file only] # Revision: 080115 # Note: The license indicated above applies to this file. It doesn't # apply to the official Rocks'n'Diamonds package. #--------------------------------------------------------------------- # overview #--------------------------------------------------------------------- # 1. "rockslevel" runs Rocks'n'Diamonds using a specified levelset. # After Rocks'n'Diamonds exits, "rockslevel" restores the previous # levelset configuration. #--------------------------------------------------------------------- # 2. "rockslevel" turns the "Ask On Escape" option flag off temporari- # ly. This is necessary because at least one important levelset [Pac- # man] doesn't handle this option correctly, and other levelsets might # have the same problem. #--------------------------------------------------------------------- # 3. Usage examples: # # rockslevel Old_West - Runs Old_West levelset (if present) # rockslevel Pacman - Runs Pacman levelset (if present) # rockslevel snake_bite - Runs Snake Bite levelset (if present) # "rockslevel" takes a directory name as an argument, as opposed to a # levelset name. Specifically, the argument should be the name of the # directory that contains the desired levelset's "levelinfo.conf" # file and the associated ".level" files. The pathname component # should be omitted. #--------------------------------------------------------------------- # 4. This program sets an environment variable named RDLEVELSET equal # to the specified directory name. This is done for the benefit of # lower-level scripts. #--------------------------------------------------------------------- # standard module setup #--------------------------------------------------------------------- require 5.6.1; use strict; use Carp; use warnings; # Trap warnings $SIG {__WARN__} = sub { die @_; }; #--------------------------------------------------------------------- # basic constants #--------------------------------------------------------------------- use constant ZERO => 0; # Zero use constant ONE => 1; # One use constant FALSE => 0; # Boolean FALSE use constant TRUE => 1; # Boolean TRUE #--------------------------------------------------------------------- # program parameters #--------------------------------------------------------------------- # $IE specifies an internal-error message prefix string. # $REVISION specifies a program-revision string. my $IE = 'rockslevel: Internal error'; my $REVISION = '080115'; #--------------------------------------------------------------------- # $TARGET_PROGRAM should specify the name of the target executable to # be run. Presently, either the base name or an absolute pathname may # be used. my $TARGET_PROGRAM = '/glibc64/pkg/diamonds/bin/diamonds'; #--------------------------------------------------------------------- # default "levelsetup.conf" data #--------------------------------------------------------------------- # Note: The "last_level_series" field defined here should specify the # name of a levelset that's guaranteed to be present in the local copy # of Rocks'n'Diamonds. my $DEFAULT_CFGDATA_LEVELSETUP = << 'END'; file_identifier: ROCKSNDIAMONDS_LEVELSETUP_FILE_VERSION_3.2 last_level_series: Walpurgis_Gardens END #--------------------------------------------------------------------- # default "setup.conf" data #--------------------------------------------------------------------- my $DEFAULT_CFGDATA_SETUP = << 'END'; file_identifier: ROCKSNDIAMONDS_SETUP_FILE_VERSION_3.2 player_name: __META_USER__ sound: on repeating_sound_loops: on background_music: off simple_sound_effects: on toons: on scroll_delay: on soft_scrolling: on fade_screens: on automatic_tape_recording: on show_titlescreen: on quick_doors: off team_mode: off handicap: on skip_levels: on time_limit: on fullscreen: on fullscreen_mode: 800x600 ask_on_escape: off ask_on_escape_editor: on quick_player_switch: off input_on_focus: off prefer_aga_graphics: on graphics_set: gfx_classic sounds_set: snd_classic music_set: mus_classic override_level_graphics: off override_level_sounds: off override_level_music: off editor.el_boulderdash: off editor.el_emerald_mine: off editor.el_emerald_mine_club: off editor.el_more: off editor.el_sokoban: off editor.el_supaplex: off editor.el_diamond_caves: off editor.el_dx_boulderdash: off editor.el_chars: on editor.el_custom: on editor.el_headlines: off editor.el_user_defined: off editor.el_dynamic: on editor.el_by_game: off editor.el_by_type: off editor.show_element_token: off shortcut.save_game: XK_F1 # F1 shortcut.load_game: XK_F2 # F2 shortcut.toggle_pause: XK_space # space shortcut.focus_player_1: XK_F5 # F5 shortcut.focus_player_2: XK_F6 # F6 shortcut.focus_player_3: XK_F7 # F7 shortcut.focus_player_4: XK_F8 # F8 shortcut.focus_player_all: XK_F9 # F9 player_1.use_joystick: false player_1.joy.device_name: /dev/js0 player_1.joy.xleft: -32767 player_1.joy.xmiddle: 0 player_1.joy.xright: 32767 player_1.joy.yupper: -32767 player_1.joy.ymiddle: 0 player_1.joy.ylower: 32767 player_1.joy.snap_field: 16 player_1.joy.place_bomb: 32 player_1.key.move_left: XK_Left # cursor left player_1.key.move_right: XK_Right # cursor right player_1.key.move_up: XK_Up # cursor up player_1.key.move_down: XK_Down # cursor down player_1.key.snap_field: XK_Control_L # left control player_1.key.place_bomb: XK_Control_R # right control player_1.key.place_bomb2: XK_KP_Add # keypad + player_2.use_joystick: false player_2.joy.device_name: /dev/js1 player_2.joy.xleft: -32767 player_2.joy.xmiddle: 0 player_2.joy.xright: 32767 player_2.joy.yupper: -32767 player_2.joy.ymiddle: 0 player_2.joy.ylower: 32767 player_2.joy.snap_field: 0 player_2.joy.place_bomb: 0 player_2.key.move_left: [undefined] player_2.key.move_right: [undefined] player_2.key.move_up: [undefined] player_2.key.move_down: [undefined] player_2.key.snap_field: [undefined] player_2.key.place_bomb: [undefined] player_2.key.place_bomb2: [undefined] player_3.use_joystick: false player_3.joy.device_name: /dev/js2 player_3.joy.xleft: -32767 player_3.joy.xmiddle: 0 player_3.joy.xright: 32767 player_3.joy.yupper: -32767 player_3.joy.ymiddle: 0 player_3.joy.ylower: 32767 player_3.joy.snap_field: 0 player_3.joy.place_bomb: 0 player_3.key.move_left: [undefined] player_3.key.move_right: [undefined] player_3.key.move_up: [undefined] player_3.key.move_down: [undefined] player_3.key.snap_field: [undefined] player_3.key.place_bomb: [undefined] player_3.key.place_bomb2: [undefined] player_4.use_joystick: false player_4.joy.device_name: /dev/js3 player_4.joy.xleft: -32767 player_4.joy.xmiddle: 0 player_4.joy.xright: 32767 player_4.joy.yupper: -32767 player_4.joy.ymiddle: 0 player_4.joy.ylower: 32767 player_4.joy.snap_field: 0 player_4.joy.place_bomb: 0 player_4.key.move_left: [undefined] player_4.key.move_right: [undefined] player_4.key.move_up: [undefined] player_4.key.move_down: [undefined] player_4.key.snap_field: [undefined] player_4.key.place_bomb: [undefined] player_4.key.place_bomb2: [undefined] system.sdl_audiodriver: [DEFAULT] system.audio_fragment_size: 512 options.verbose: false END #--------------------------------------------------------------------- # main routine #--------------------------------------------------------------------- sub Main { my $str; # Scratch my $HOME; # Absolute path for "home" directory #--------------------------------------------------------------------- # Initial setup. $HOME = $ENV {HOME}; # Absolute path for "home" directory if (!defined ($HOME)) { # Safety measure $HOME = '/tmp'; $ENV {HOME} = $HOME; } system "resetpcmvol"; # This code is distro-specific # Absolute path for config. directory my $CFGDIR = "$HOME/.rocksndiamonds"; # Absolute paths for config. files my $CFGPATH_LEVELSETUP = "$CFGDIR/levelsetup.conf"; my $CFGPATH_SETUP = "$CFGDIR/setup.conf"; #--------------------------------------------------------------------- # Process the command line. my $LevelSet; $LevelSet = shift (@ARGV); $LevelSet = "" unless defined $LevelSet; $LevelSet =~ s@^.*/@@; if (!length ($LevelSet) || scalar (@ARGV) || ($LevelSet !~ m@^[A-Z0-9_&\-]+\z@i)) { print << "END"; # "END" must be double-quoted here rockslevel rev. $REVISION - Runs a Rocks'n'Diamonds levelset Usage: rockslevel Pacman "rockslevel" takes a directory name as an argument, as opposed to a levelset name. Specifically, the argument should be the name of the directory that contains the desired levelset's "levelinfo.conf" file and the associated ".level" files. The pathname component should be omitted. END exit ONE; } #--------------------------------------------------------------------- # Create "levelsetup.conf" file, if necessary. # Does the file exist? if (!-e $CFGPATH_LEVELSETUP) { # No - We need to create it # Handle broken links unlink $CFGPATH_LEVELSETUP; # Create directory [if necessary] system "mkdir -p $CFGDIR"; if (-d $CFGDIR && open (OFD, ">$CFGPATH_LEVELSETUP")) { print OFD $DEFAULT_CFGDATA_LEVELSETUP; close (OFD) || die "$IE #0001\n"; } else { die "$IE #0002\n"; } } #--------------------------------------------------------------------- # Create "setup.conf" file, if necessary. if (!-e $CFGPATH_SETUP) # Does the file exist? { # No - We need to create it unlink $CFGPATH_SETUP; # Handle broken links # Create directory [if necessary] system "mkdir -p $CFGDIR"; if (-d $CFGDIR && open (OFD, ">$CFGPATH_SETUP")) { my $user = 'Unknown'; $user = 'root' if $HOME eq '/root'; $user = $1 if $HOME =~ m@/home/(\w+)@; $str = $DEFAULT_CFGDATA_SETUP; $str =~ s@__META_USER__@$user@g; print OFD $str; close (OFD) || die "$IE #0003\n"; } else { die "$IE #0004\n"; } } #--------------------------------------------------------------------- # Load "levelsetup.conf" data. open (IFD, "<$CFGPATH_LEVELSETUP") || die "$IE #0005\n"; undef $/; $str = ; $str = "" unless defined $str; close IFD; die "$IE #0006\n" unless length $str; my $LEVELSETUP_PREVIOUS = $str; #--------------------------------------------------------------------- # Load "levelsetup.conf" data. open (IFD, "<$CFGPATH_SETUP") || die "$IE #0007\n"; undef $/; $str = ; $str = "" unless defined $str; close IFD; die "$IE #0008\n" unless length $str; my $SETUP_PREVIOUS = $str; #--------------------------------------------------------------------- # Adjust "levelsetup.conf". $str = $LEVELSETUP_PREVIOUS; $str =~ s@(last_level_series:[\011\040]*)\S+@${1}$LevelSet@; open (OFD, ">$CFGPATH_LEVELSETUP") || die "$IE #0009\n"; print OFD $str; close (OFD) || die "$IE #0010\n"; #--------------------------------------------------------------------- # Adjust "setup.conf". $str = $SETUP_PREVIOUS; $str =~ s@(ask_on_escape:[\011\040]*)\S+@${1}off@; open (OFD, ">$CFGPATH_SETUP") || die "$IE #0011\n"; print OFD $str; close (OFD) || die "$IE #0012\n"; #--------------------------------------------------------------------- # Run next-level Rocks'n'Diamonds wrapper. $ENV {RDLEVELSET} = $LevelSet; system $TARGET_PROGRAM; #--------------------------------------------------------------------- # Restore previous "levelsetup.conf" data. $str = $LEVELSETUP_PREVIOUS; open (OFD, ">$CFGPATH_LEVELSETUP") || die "$IE #0013\n"; print OFD $str; close OFD; #--------------------------------------------------------------------- # Restore previous "setup.conf" data. $str = $SETUP_PREVIOUS; open (OFD, ">$CFGPATH_SETUP") || die "$IE #0014\n"; print OFD $str; close OFD; undef; } #--------------------------------------------------------------------- # main program #--------------------------------------------------------------------- &Main(); # Call the main routine exit ZERO; # Not reached