#!/usr/bin/perl -w

# (c) Copyright by Tels 1999-2000. All Rights Reserved.
# 1999-12-04 v0.0.1 - from scratch
# 1999-12-26 v0.0.2 - added attic
# 2000-01-24 v0.0.3 - added some objects as demo
# 2000-02-13 v0.0.4 - object sizes
# 2000-02-15 v0.0.5 - test creature
# 2000-02-26 v0.0.6 - loot
# 2000-03-03 v0.0.7 - breakable window
# 2000-03-13 v0.0.8 - torch, unlitTorch, links

use Cowgen::Bunch;          # for a bunch of brushes
use Cowgen::Dromed;         # for some Thief constants and specifics
use Cowgen::Texture;        # to get texture mappings
use Cowgen::VWorld::Room;   # virtual world based on cells
use Cowgen::VWorld::RoomGen;# virtual world based on cells
use Cowgen::VWorld::House;  # virtual houses
use Cowgen::Objsize;        # for size of objects
use Cowgen::Architecture::Basics;
use Cowgen::Thief;

print "Sample for JM\n\n";

# create a vbr object from template mission
$vbr = Cowgen::Vbr->create("houses.mis");
$txt = Cowgen::Texture->create($vbr->getTXT()); 
$gf = Cowgen::Gamfile->create( $vbr->gamesysName() );

# get commandline parameter
$outfile = shift || "vroom1.mis"; 
print "Need .mis as outfile!\n" if ($outfile !~ /\.mis$/);
$outfile = "data/$outfile" if ($outfile !~ /^data\//);

# first define some basic templates

# remember: a list in perl is comma seperated, but a last comma is no problem
# "2,3,4," is equal to "2,3,4". so to make it easier for you and to avoid
# syntax errors when adding stuff, always add a last comma to any list

# a { } creates an anonymous hash out of the key => value pairs
# a [ ] creates an anonymous list out of the values

$room = { texture => $txt->texture("odstone"), wallthick => 0.5,
          ceilingtexture => $txt->texture("wdplnk2"),
          bandheight => 3, bandtexture => $txt->texture("stone2s2"),
          bandthick => 0.25, 
          floortexture => $txt->texture("wetbricks"), 
          gridsize => 0.25, gen => \&basicRoom,
        };

# kitchen room (basic room since we dont want a carpet)
$kroom = { texture => $txt->texture("brick1"), wallthick => 0.5,
          ceilingtexture => $txt->texture("wdplnk2"),
          floortexture => $txt->texture("mosaic"), 
          gridsize => 0.25, gen => \&basicRoom,
        };

# attic room (0..-0.5 is relativ, 0..x is absolute size of wedges
$aroom = { texture => $txt->texture("wdplnk2"), wallthick => 0.5,
          ceilingtexture => $txt->texture("wdplnk2"),
          beams => 4, beamwidth => 1.5, beamthick => 1.5, 
          beamtexture => $txt->texture("wdplnk2"), lowerbeam => true(),
          wedgex => 4, wedgey => -0.4,
          floortexture => $txt->texture("wood"), 
          gridsize => 0.25, gen => \&atticRoom,
        };

# blockthick and blocktexture are ignored for fake things,
# so we can set them here
# door/window type (lit/open/unlit etc) is defined later on
$mydoor = { floortexture => $txt->texture("rooftile"), 
        texture => $txt->texture("wdplanko"), 
        innertexture => $txt->texture("wdplanko"), framethick => 0.25,
        blocktexture => $txt->texture("wood"), blockthick => 0.5,
        height => 8.5, width => 4.5, name => "doorframe##num##",
        };

# a door that can be placed at an east or west wall (not relying on openDoor() 
# to set some defaults). We could make mydoor the same, and use only this, but
# this is an example, so I make some things longer to show you what you can do

# in X we place it at wall, with at least one offset of 1 feet (sx)

$myfdoor = { floortexture => $txt->texture("rooftile"), 
        texture => $txt->texture("wdplanko"), 
        innertexture => $txt->texture("wdplanko"), framethick => 0.25,
        blocktexture => $txt->texture("wood"), height => 8, width => 4, 
        ax => atWall(), ay => atCell(), az => atThing(), sx => 1, 
        };

# actually, flooding an open window will prevent you from seeing the sky texture
# this seems to be a dromed bug, flood always uses default texture and does not
# honour the face textures !?

# place the window not at center, but a bit higher

$mywindow = { texture => $txt->texture("stucco"), framethick => 0.25,
              blocktexture => $txt->texture("win325s"), 
              blockthick => 0.5, height => 4.5, width => 4.5, 
              z => 0.15,
              sidetexture => { t => sky(), s => 24 },
            };

# check inherit if you want a thing to be placed in each of a cells' subcells,
# then add it to the mothercell
# omit inherit, if you want the thing to actual appear in the mothercell, and
# not to be inherited by subcells. Last case is shown with lantern added to "upper",
# first case with lamp added to kitchen, hall and stairs

# remember: rotaion of objects in DromEd is not consistent, e.g rz == 0 means not
# everytime that object faces south!
# to fix this, simple set rz to the desired angle-offset-fix, e.g for the lantern
# this is 180 degress, since 0 degress makes the lantern facing north

# Most of the objects need gamefile set for the adjustments done in Thief.pm

$mylantern = { name => 'ElecWallLight##num##', 
            base => $gf->obj('ElecWallLight'), 
            prop => { light => 160, collisiontype => o_bounce(), }, 
            gen => \&makeObject, rz => 180, gamfile => $gf,
            adjust => \&Cowgen::Thief::makePhysical,
            };

$myoutlight = { name => 'OldElecWallLight##num##', 
            base => $gf->obj('OldElecWallLight'), 
            prop => { collisiontype => o_bounce(), }, 
            gen => \&makeObject, rz => 180, gamfile => $gf,
            light => { maxbright => 160, minbright => 0, inactive => TRUE, 
             type => O_SMOOTHLY_BRIGHTEN,  },
            adjust => \&Cowgen::Thief::makeAnimLight,
            };

$mylamp = { name => 'lamp##num##', base => $gf->obj('HangingLamp'), 
            prop => { light => 80, }, gen => \&makeObject, 
            inherit => true(), gamfile => $gf,
            adjust => \&Cowgen::Thief::makePhysical,
            };

$myspot = { name => 'spot##num##', base => $gf->obj('HangingSpot'), 
            prop => { light => 120, }, gen => \&makeObject, gamfile => $gf,
            adjust => \&Cowgen::Thief::makePhysical,
            };

$mytable = { name => 'table##num##', base => $gf->obj('Table'), 
            prop => { }, gen => \&makeObject, gamfile => $gf,
            inherit => true(), az => atThing(), ax => atThing(), ay => atThing(),
            adjust => \&Cowgen::Thief::makePhysical,
            };

$mychair = { name => 'chair1##num##', base => $gf->obj('Wooden Chair'), 
            prop => { }, gen => \&makeObject, gamfile => $gf,
            inherit => true(), az => atThing(), ax => atThing(), ay => atThing(), 
            relativeto => 'table', rz => 15,
            adjust => \&Cowgen::Thief::makePhysical,
            };

$mychair2 = { name => 'chair##num##', base => $gf->obj('Wooden Chair'), 
            prop => { }, gen => \&makeObject, gamfile => $gf,
            inherit => true(), az => atThing(), ax => atThing(), ay => atThing(), 
            relativeto => 'chair1', rz => 30,
            adjust => \&Cowgen::Thief::makePhysical,
            };

# torch not ready yet!
$mytorch = { name => 'atorch', 
            prop => { }, gen => \&Cowgen::Thief::torch, gamfile => $gf,
            light => { type => O_COHERENT, maxbright => 125, minbright => 80,
              },
            inherit => true(), az => atThing(), ax => atThing(), ay => atThing(), 
            };

$mylightdoor = { name => 'lightdoor', base => $gf->obj('door13'),
            gen => \&Cowgen::Thief::animLightDoor, gamfile => $gf,
            light => { maxbright => 35, minbright => 0, ldx => 0.5, ldy => 0, ldz => 1, },
            inherit => true(), az => atThing(), ax => atThing(), ay => atThing(), 
            relativeto => 'doorframe', openedangle => 0, closedangle => 270, 
            clockwise => TRUE,
            dx => 0, dy => 0, dz => 0,
            };

# for testing circular reference check in Room.pm. See below:
$mychair3 = copyHash($mychair2);
$mychair3->{name} = 'chair3##num##';
$mychair3->{relativto} = 'chair4';
$mychair4 = copyHash($mychair2);
$mychair4->{name} = 'chair4##num##';
$mychair4->{relativto} = 'chair3';

# just a silly example, three stools to show conditional thing creation:
# conditional: "name of property of room to test, testcondition (0 = eq, 1 = ne),
# value to compare to"

# mystool_0 will be generated if difficulty is != 0 (e.g. 1 and 2)
$mystool_0 = { name => 'stool_0_##num##', base => $gf->obj('stool'), 
            prop => { }, gen => \&makeObject, gamfile => $gf,
            inherit => true(), az => atThing(), ax => atThing(), ay => atThing(), 
            adjust => \&Cowgen::Thief::makePhysical, 
            conditional => "difficulty,1,0",
            };

# mystool_1 will be generated if difficulty is == 0 (e.g. not 1 or 2)
$mystool_1 = copyHash($mystool_0);
$mystool_1->{conditional} = "difficulty,0,0";

# mystool_2 will be generated if difficulty is == 2 (e.g. not 1 or 0)
$mystool_2 = copyHash($mystool_0);
$mystool_2->{conditional} = "difficulty,0,2";

$mynovice = { name => 'novice##num##', base => $gf->obj('Ham Novice'), 
            prop => { }, gen => \&makeObject, adjust => \&Cowgen::Thief::makeCreature,
            inherit => false(), az => atThing(), ax => atThing(), ay => atThing(),
            gamfile => $gf,
            };

$mygem = { name => "gem##num##", base => $gf->obj('GemStone'), 
            prop => { loot => "200,0,0,0", },
            gen => \&makeObject, adjust => \&Cowgen::Thief::makeLoot, gamfile => $gf,
            inherit => false(), az => atThing(), ax => atThing(), ay => atThing(),
            sx => 1, relativeto => 'table', dx => 0, dy => 0, dz => 0,
            };
$mysword = { name => "sword", base => $gf->obj('ConstantineSword'), 
            prop => { }, gen => \&makeObject, gamfile => $gf,
            inherit => false(), az => atThing(), ax => atThing(), ay => atThing(),
            relativeto => 'table', dx => 0, dy => 0, dz => 1, rz => 120, rx => 90,
            };

$mybreakwin = { name => 'breakablewindow##num##', texture => 'fam\church\glass1',
            gen => \&Cowgen::Thief::breakableWindow, gamfile => $gf,
            width => 8, height => 8, length => 0.5,
            inherit => true(), az => atThing(), ax => atThing(), ay => atThing(), 
            relativeto => 'breakablewindowhole', rz => 90, 
            };

$mywinhole = { name => 'breakablewindowhole##num##', texture => $txt->texture('brick'),
            gen => \&frame, framethick => 0.25,
            width => 8.5, height => 8.5, ax => atThing(), sx => 0.5, ay => atCell(),
            };

$mystart = { name => "startingPoint", 
            gen => \&Cowgen::Thief::startingPoint,
            width => 0, height => 0, length => 0, gamfile => $gf,
            };

$mylever = { name => 'lever##num##', base => 'up/down switch',
            prop => { }, gen => \&makeObject, gamfile => $gf, rz => 90,
            inherit => false(), az => atThing(), ax => atThing(), ay => atThing(),
            sz => 0, sy => 0, sx => 0,
            };

# remember, from and to will match as regualr expressions on multiple objects!
# this below will actually link ANY lever in office to ANY oldelecwalllight in
# office. If you have more than one office, this will also link across the
# office. Maybe not what you want :o)

# either set gamfile, or add the flavour as number, not a string.

$mylightlink = { name => 'link##num##', gamfile => $gf,
            from => 'office->lever', to => 'office->oldelecwall', 
            flavour => 'controldevice',
            };

# a link that works only once

$myoslink = { name => 'oslink##num##', 
            from => 'kitchen->lever', to => 'kitchen->light', 
            flavour => $gf->flavour('controldevice'), flags => CD_ONE_SHOT,
            };

# start a house floor description.
# create a cell divider (using our room, door, window stuff)

# first we define the cells for the rooms, so that we later on
# simple canput anything together. bottom up method here

# if you leave off div, it will be div => none() as default, 
# which is perfectly for single rooms

# all three cells (upper, middle and lower) are divided, but the lower ones
# are not divided like the upper. That is to make entry and hallway not into
# such large wasted spaces.

$kitchen = cell ( { name => "kitchen", size => 16, room => $kroom } );
$dining  = cell ( { name => "hall", size => 16 } );
$stairs  = cell ( { name => "stairs", size => 16, room => $room } );

$dinette = cell ( { name => "dinette", size => 18, room => $kroom } );
$hallway = cell ( { name => "hallway", size => 12 } );
$office  = cell ( { name => "office", size => 18, room => $room } );

$living  = cell ( { name => "living", size => 18, room => $kroom } );
$entry   = cell ( { name => "entry", size => 12 } );
$library = cell ( { name => "library", size => 18, room => $room } );

# now add some things to the various rooms

# openDoor can place a door only at the center of a wall. you can use thing() 
# to place the door at any place (even in the middle of the room :)

$kitchen->{things} = [ openDoor(aEast(),$mydoor), openWindow(aNorth(),$mywindow),
#  thing (-0.5,0,0.1,aSouth(),$mytorch),
   objThing(0.5,0.1,+0.1,aNorth(),$myoutlight),
   thing ( 0.4, -0.5, -0.1, aEast(), $mylever),
   objLink ( $myoslink ),
  ];
$dinette->{things} = [ 
  openDoor(aEast(),$mydoor), objThing(0,0,0.5,aNorth(),$mylamp), 
  objThing(0,0,0,aNorth(),$mylightdoor), 
  ];
$living->{things} = [ openDoor(aEast(),$mydoor), openWindow(aWest(),$mywindow), 
# order of things relative to each other does not matter!
                       objThing(0.5,0,+0.1,aNorth(),$mylantern),
                       objThing( 4, -1, 0, aNorth(),$mychair), 
                       objThing(-0.5,-0.2,-0.5,aWest(),$mytable), 
                       objThing(-0.5,-1.2, +1.5,aWest(),$mygem), 
                       objThing( 0, 0, -0.4, aSouth(),$mysword), 
                       objThing( 0.5, 3, 0, aNorth(),$mychair2), 
# to see what happens if you create an error in relativeto, uncomment next two lines:
#                       objThing( 5, 0, 0, aNorth(),$mychair3), 
#                       objThing( 5, 0, 0, aNorth(),$mychair4), 
                       ];

$entry->{things} = [ 
  openDoor(aSouth(),$mydoor), thing ( 0.4, 0.5, -0.5, aEast(), $myfdoor),
  objThing( 0.4, 0,-0.2,aNorth(),$mystart),
  ];
$office->{things} = [ 
   objThing(-0.5,0.1,+0.1,aSouth(),$myoutlight),
   thing ( 0.4, -0.5, -0.1, aEast(), $mylever),
  ];

# to show you that it actually does not matter where to add links
$hallway->{things} = [ openDoor(aSouth(),$mydoor), openDoor(aNorth(),$mydoor),
   thing ( -0.4, 0.5, -0.5, aEast(), $myfdoor),
   objThing ( 0,0,0.5, aSouth(), $myspot),
#   objThing ( 0.2,-0.1,-0.5, aSouth(), $mynovice),
   objThing ( 0, 0, 0, aWest(), $mybreakwin),
   thing ( 0.2, 0.5, -0.1, aEast(), $mywinhole),
   objLink ( $mylightlink ),
   ];
$stairs->{things} = [ openDoor(aWest(),$mydoor) ];

$library->{things} = [ openWindow(aEast(),$mywindow), 
                       objThing(-0.5,0,+0.1,aSouth(),$mylantern), 
                       objThing(-0.4,0,-0.5,aSouth(),$mystool_0), 
                       objThing(-0.3,0,-0.5,aSouth(),$mystool_1), 
                       objThing(-0.2,0,-0.5,aSouth(),$mystool_2), 
  ];

# now define the 3 parts, they are 12,20 and 12 in size. That are relative sizes!
# show that you can add a thing (outlight) to a cell that has child cells and it
# what happens if it doesnt have inherited set:

$upper = cell ( { div => inY(), size => 12, 
  things => [ objThing(0,0,0.5,aNorth(),$mylamp), 
   objThing(-0.5,0,0.1,aSouth(),$myoutlight),],
  cells => [ $kitchen, $dining, $stairs
   ] } );

$middle = cell ( { div => inY(), size => 20,
  cells => [ $dinette, $hallway, $office
   ] } );

$lower = cell ( { div => inY(), size => 12,
  cells => [ $living, $entry, $library
   ] } );

# now we divide out "world" in three parts, from left to right
# (you could start diving from top to down, and then left to right, but
# I choose so. It really doesnt matter)

$firstfloor = cell ( { name => "firstfloor##num##", div => inX(), size => 14,
  cells => [ $upper, $middle, $lower
   ] } );

# now we add the attic

$attic = cell ( { name => "attic##num##", div => inX(), size => 16, room => $aroom } );

$house = cell ( { name => "house##num##", div => inZ(), room => $room,
  cells => [ $firstfloor, $attic ] } );

$house->{debug} = 1;

# one of three stools will be created, depending on which value (1,2,3) you
# set difficulty to. This is to make more than one version of a mission, f..i. 
# one for people with low resource, the other for high-end-game-freaks
$house->{room}->{difficulty} = "0";

# at 0,64,0 place the house, 48 width (in Y), 64 long (in X), 30 heigh

$house->{gamfile} = $gf;
$bunch = worldAsBunch (0, 64, 0, 64, 48, 30, $house);
$bunch->debug();

# optimize and generate rooms and flows, then write out
#$bunch->optimize();
$bunch->autoRoom(0,3); $bunch->autoFlow(); optimizeSky($bunch);
$vbr->missionEAX ( eax => eax_stoneRoom() );
$vbr->renderParams ( ambient => 20 ); # always use this!
$vbr->missionDescription ( number => 20, path => "vroom", ); # for save/load to work
$vbr->scriptModules ( "convict" );
$vbr->skyMode ( O_SKY_STARS ); # or O_SKY_TEXTURE
$vbr->saveMission($gf,$bunch,$outfile);
print "Done, enjoy $outfile!\n";

# EOF
1;

