traps are randomly selected, can now easily be controlled on a branch by branch basis (and for Pan and the Abyss), similar to how monster level and rarity is controlled (via function pointers in the Branch data structure). The same can be done for fog machines (though this feature isn't being used as of yet).
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2846 c06c8d41-db1a-0410-9941-cceddc491573
TFZ4TER7O2Z4FOGF2RCPEPYIHBTUA4LG3ECXLR7XGLCC6GO6OOTAC
AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC
MQY6MBFZ6OYPW2GD65SB6W7XHT6NWQLW7XQNS3VAHBNMX6YLTO4QC
ZCRK2DJ5VKECRQXZTWT4NUDL2VT5ZHUK7NT6NQPLRJ56TDX5PJSAC
Y5GWVQ5SM7DJEAPFOBPMMJH4D3NXBB2MPONSJUMG3KIQMBVGEE6AC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC
TZ55IZNANEJO2WDTKYWVLY2W2VV6BR7WKIN7XLNISAMMFT6LG2WQC
2YSMM7QMFZOPD5NXAD2OAMDJEY5LOZO4NCYBC7UCQVANKINJRNBAC
L6O4LGZRKBURVWEY7XRVCSQLJ5RULNBEWMQJ6I2UYVWWB66FM3MQC
ILOED4VB4I6VPAUTR75ZWX6MXDYXB5DO2EDK2UH67O3HNKWV23RQC
4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC
QKGDOYIYKE6B36ION5O2DRW65DWWPZMYNWJVH7LJJ7FPGGM2MYAQC
WBAFNYODKTL3YSG3UOJITBJSTFYGJLIWKRNK6NMGIIP5TPC2BDGQC
JNB3PBPBJHDUHH47ZICB25QENPTMLYK7CXC5BXRVWZ3J3ZZPKCUAC
ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC
KKROXTUPBNEXXEUUDJNADATK3BCQPSQWFZ6L4VTKBPTYXJLYUHDQC
WWR4IDWLXP4XLBWDZBA5GFG7CRKUJQNRK7FFUFOISK6OJTMYQPFQC
int traps_zero_number(int level_number = -1);
int traps_pan_number(int level_number = -1);
trap_type traps_pan_type(int level_number = -1);
int traps_abyss_number(int level_number = -1);
trap_type traps_abyss_type(int level_number = -1);
int traps_lab_number(int level_number = -1);
trap_type traps_lab_type(int level_number = -1);
}
bool is_valid_shaft_level(const level_id &place)
{
if (place.level_type != LEVEL_DUNGEON)
return (false);
// Don't generate shafts in branches where teleport control
// is prevented. Prevents player from going down levels without
// reaching stairs, and also keeps player from getting stuck
// on lower levels with the innability to use teleport control to
// get back up.
if (testbits(get_branch_flags(place.branch), LFLAG_NO_TELE_CONTROL))
{
return (false);
}
const Branch &branch = branches[place.branch];
// When generating levels, don't place a shaft on the level
// immediately above the bottom of a branch if that branch is
// significantly more dangerous than normal.
int min_delta = 1;
if (env.turns_on_level == -1 && branch.dangerous_bottom_level)
min_delta = 2;
return ((branch.depth - place.depth) >= min_delta);
}
static int num_traps_default(int level_number, const level_id &place)
{
return random2avg(9, 2);
}
int num_traps_for_place(int level_number, const level_id &place)
{
if (level_number == -1)
{
switch(place.level_type)
{
case LEVEL_DUNGEON:
level_number = absdungeon_depth(place.branch, place.depth);
break;
case LEVEL_ABYSS:
level_number = 51;
break;
case LEVEL_PANDEMONIUM:
level_number = 52;
break;
default:
level_number = you.your_level;
}
}
switch(place.level_type)
{
case LEVEL_DUNGEON:
if (branches[place.branch].num_traps_function != NULL)
return branches[place.branch].num_traps_function(level_number);
else
return num_traps_default(level_number, place);
case LEVEL_ABYSS:
return traps_abyss_number(level_number);
case LEVEL_PANDEMONIUM:
return traps_pan_number(level_number);
case LEVEL_LABYRINTH:
case LEVEL_PORTAL_VAULT:
ASSERT(false);
break;
default:
return 0;
}
return 0;
}
static trap_type random_trap_default(int level_number, const level_id &place)
{
trap_type type = TRAP_DART;
if ((random2(1 + level_number) > 1) && one_chance_in(4))
type = TRAP_NEEDLE;
if (random2(1 + level_number) > 3)
type = TRAP_SPEAR;
if (random2(1 + level_number) > 5)
type = TRAP_AXE;
// Note we're boosting arrow trap numbers by moving it
// down the list, and making spear and axe traps rarer.
if (type == TRAP_DART?
random2(1 + level_number) > 2
: one_chance_in(7))
type = TRAP_ARROW;
if ((type == TRAP_DART || type == TRAP_ARROW) && one_chance_in(15))
type = TRAP_NET;
if (random2(1 + level_number) > 7)
type = TRAP_BOLT;
if (random2(1 + level_number) > 11)
type = TRAP_BLADE;
if ((random2(1 + level_number) > 14 && one_chance_in(3))
|| (place.branch == BRANCH_HALL_OF_ZOT &&
place.level_type == LEVEL_DUNGEON && coinflip()))
{
type = TRAP_ZOT;
}
if (one_chance_in(50) && is_valid_shaft_level(place))
type = TRAP_SHAFT;
if (one_chance_in(20))
type = TRAP_TELEPORT;
if (one_chance_in(40))
type = TRAP_ALARM;
return (type);
trap_type random_trap_for_place(int level_number, const level_id &place)
{
if (level_number == -1)
{
switch(place.level_type)
{
case LEVEL_DUNGEON:
level_number = absdungeon_depth(place.branch, place.depth);
break;
case LEVEL_ABYSS:
level_number = 51;
break;
case LEVEL_PANDEMONIUM:
level_number = 52;
break;
default:
level_number = you.your_level;
}
}
switch(place.level_type)
{
case LEVEL_DUNGEON:
if (branches[place.branch].rand_trap_function != NULL)
return branches[place.branch].rand_trap_function(level_number);
else
return random_trap_default(level_number, place);
case LEVEL_ABYSS:
return traps_abyss_type(level_number);
case LEVEL_PANDEMONIUM:
return traps_pan_type(level_number);
case LEVEL_LABYRINTH:
case LEVEL_PORTAL_VAULT:
ASSERT(false);
break;
default:
return random_trap_default(level_number, place);
}
return NUM_TRAPS;
}
int traps_zero_number(int level_number)
{
return 0;
}
int traps_pan_number(int level_number)
{
return num_traps_default(level_number, level_id(LEVEL_PANDEMONIUM));
}
trap_type traps_pan_type(int level_number)
{
return random_trap_default(level_number, level_id(LEVEL_PANDEMONIUM));
}
int traps_abyss_number(int level_number)
{
return num_traps_default(level_number, level_id(LEVEL_ABYSS));
}
trap_type traps_abyss_type(int level_number)
{
return random_trap_default(level_number, level_id(LEVEL_ABYSS));
}
int traps_lab_number(int level_number)
{
return num_traps_default(level_number, level_id(LEVEL_LABYRINTH));
}
trap_type traps_lab_type(int level_number)
{
return random_trap_default(level_number, level_id(LEVEL_LABYRINTH));
}
bool is_valid_shaft_level()
{
if (you.level_type != LEVEL_DUNGEON)
return (false);
// Don't generate shafts in branches where teleport control
// is prevented. Prevents player from going down levels without
// reaching stairs, and also keeps player from getting stuck
// on lower levels with the innability to use teleport control to
// get back up.
if (testbits(get_branch_flags(), LFLAG_NO_TELE_CONTROL))
{
return (false);
}
int depth = subdungeon_depth(you.where_are_you, you.your_level);
// When generating levels, don't place a shaft on the level
// immediately above the bottom of a branch if that branch is
// significantly more dangerous than normal.
int min_delta = 1;
if (env.turns_on_level == -1 && your_branch().dangerous_bottom_level)
min_delta = 2;
return ((your_branch().depth - depth) >= min_delta);
}
}
// Also checks you.where_are_you!
static trap_type random_trap_for_level(int level_number)
{
trap_type type = TRAP_DART;
if ((random2(1 + level_number) > 1) && one_chance_in(4))
type = TRAP_NEEDLE;
if (random2(1 + level_number) > 3)
type = TRAP_SPEAR;
if (random2(1 + level_number) > 5)
type = TRAP_AXE;
// Note we're boosting arrow trap numbers by moving it
// down the list, and making spear and axe traps rarer.
if (type == TRAP_DART?
random2(1 + level_number) > 2
: one_chance_in(7))
type = TRAP_ARROW;
if ((type == TRAP_DART || type == TRAP_ARROW) && one_chance_in(15))
type = TRAP_NET;
if (random2(1 + level_number) > 7)
type = TRAP_BOLT;
if (random2(1 + level_number) > 11)
type = TRAP_BLADE;
if ((random2(1 + level_number) > 14 && one_chance_in(3))
|| (player_in_branch( BRANCH_HALL_OF_ZOT ) && coinflip()))
{
type = TRAP_ZOT;
}
if (one_chance_in(50) && is_valid_shaft_level())
type = TRAP_SHAFT;
if (one_chance_in(20))
type = TRAP_TELEPORT;
if (one_chance_in(40))
type = TRAP_ALARM;
return (type);
static void place_fog_machines(int level_number)
{
int i;
int num_fogs = num_fogs_for_place(level_number);
ASSERT(num_fogs >= 0);
for (i = 0; i < num_fogs; i++)
{
fog_machine_data data = random_fog_for_place(level_number);
if (!valid_fog_machine_data(data))
{
mpr("Invalid fog machine data, bailing.", MSGCH_DIAGNOSTICS);
return;
}
int tries = 200;
int x, y;
dungeon_feature_type feat;
do
{
x = random2(GXM);
y = random2(GYM);
feat = grd[x][y];
}
while (feat <= DNGN_MAXWALL && --tries > 0);
if (tries <= 0)
break;
place_fog_machine(data, x, y);
} // end "for i"
} // end place_traps()
bool valid_fog_machine_data(fog_machine_data data);
int num_fogs_for_place(int level_number = -1,
const level_id &place = level_id::current());
fog_machine_data random_fog_for_place(int level_number = -1,
const level_id &place = level_id::current());
int fogs_pan_number(int level_number = -1);
fog_machine_data fogs_pan_type(int level_number = -1);
int fogs_abyss_number(int level_number = -1);
fog_machine_data fogs_abyss_type(int level_number = -1);
int fogs_lab_number(int level_number = -1);
fog_machine_data fogs_lab_type(int level_number = -1);
if (data.cl_type <= CLOUD_NONE || (data.cl_type >= CLOUD_RANDOM
&& data.cl_type != CLOUD_DEBUGGING))
return false;
if (data.size < 1 || data.power < 1)
return false;
return true;
}
int num_fogs_for_place(int level_number, const level_id &place)
{
if (level_number == -1)
{
switch(place.level_type)
{
case LEVEL_DUNGEON:
level_number = absdungeon_depth(place.branch, place.depth);
break;
case LEVEL_ABYSS:
level_number = 51;
break;
case LEVEL_PANDEMONIUM:
level_number = 52;
break;
default:
level_number = you.your_level;
}
}
switch(place.level_type)
{
case LEVEL_DUNGEON:
{
Branch &branch = branches[place.branch];
ASSERT((branch.num_fogs_function == NULL
&& branch.rand_fog_function == NULL)
|| (branch.num_fogs_function != NULL
&& branch.rand_fog_function != NULL));
if (branch.num_fogs_function == NULL)
return 0;
return branch.num_fogs_function(level_number);
}
case LEVEL_ABYSS:
return fogs_abyss_number(level_number);
case LEVEL_PANDEMONIUM:
return fogs_pan_number(level_number);
case LEVEL_LABYRINTH:
return fogs_lab_number(level_number);
default:
return 0;
}
return 0;
}
fog_machine_data random_fog_for_place(int level_number, const level_id &place)
{
fog_machine_data data = {NUM_FOG_MACHINE_TYPES, CLOUD_NONE, -1, -1};
if (level_number == -1)
{
switch(place.level_type)
{
case LEVEL_DUNGEON:
level_number = absdungeon_depth(place.branch, place.depth);
break;
case LEVEL_ABYSS:
level_number = 51;
break;
case LEVEL_PANDEMONIUM:
level_number = 52;
break;
default:
level_number = you.your_level;
}
}
switch(place.level_type)
{
case LEVEL_DUNGEON:
{
Branch &branch = branches[place.branch];
ASSERT(branch.num_fogs_function != NULL
&& branch.rand_fog_function != NULL);
fog_machine_data data;
branch.rand_fog_function(level_number, data);
return data;
}
case LEVEL_ABYSS:
return fogs_abyss_type(level_number);
case LEVEL_PANDEMONIUM:
return fogs_pan_type(level_number);
case LEVEL_LABYRINTH:
return fogs_lab_type(level_number);
default:
ASSERT(false);
return data;
}
ASSERT(false);
return data;
}
int fogs_pan_number(int level_number)
{
return 0;
}
fog_machine_data fogs_pan_type(int level_number)
{
fog_machine_data data = {NUM_FOG_MACHINE_TYPES, CLOUD_NONE, -1, -1};
return data;
}
int fogs_abyss_number(int level_number)
{
return 0;
}
fog_machine_data fogs_abyss_type(int level_number)
{
fog_machine_data data = {NUM_FOG_MACHINE_TYPES, CLOUD_NONE, -1, -1};
return data;
}
int fogs_lab_number(int level_number)
{
return 0;
}
fog_machine_data fogs_lab_type(int level_number)
{
fog_machine_data data = {NUM_FOG_MACHINE_TYPES, CLOUD_NONE, -1, -1};
return data;
}
int (*mons_rarity_function)(int);
int (*mons_level_function)(int);
int (*mons_rarity_function)(int);
int (*mons_level_function)(int);
int (*num_traps_function)(int);
trap_type (*rand_trap_function)(int);
int (*num_fogs_function)(int);
void (*rand_fog_function)(int,fog_machine_data&);