as a design exercise, i've decided to try porting the procedural c++ code for my new collision maps API to oo syntax.
the procedural code is an array of structs, routines that operate on a single struct, and routines that operate on the array:
// ################################## COLLISION MAPS ################################################
// CM stands for collision map
#define CM_SIZE 300
#define CM_CACHE_SIZE 20
struct CMrec
{
int active,age,mx,mz,cx,cz,data[CM_SIZE][CM_SIZE];
};
CMrec CM[CM_CACHE_SIZE];
void clear_CM(int cache_index)
{
ZeroMemory(&CM[cache_index],sizeof(CMrec));
}
void clear_CM_cache()
{
int a;
for (a=0; a<CM_CACHE_SIZE; a++)
{
clear_CM(a);
}
}
void add_to_CM(int i,int x,int z,int rad,int value)
{
int x1,z1,x2,z2,x3,z3;
x1=x-rad;
x2=x+rad;
z1=z-rad;
z2=z+rad;
for (x3=x1; x3<=x2; x3++)
{
for (z3=z1; z3<=z2; z3++)
{
if (x3 < 0)
{
continue;
}
if (z3 < 0)
{
continue;
}
if (x3 >= CM_SIZE)
{
continue;
}
if (z3 >= CM_SIZE)
{
continue;
}
CM[i].data[x3][z3]=value;
}
}
}
void add_tree_plantmap_to_CM(int i,int mx,int mz,int px,int pz)
{
int a,x,z,cx,cz,x2,z2,rad,value;
// a loop counter
// x,z location of the plant in the map sq
// cx,xz is the index of the collsion map the plant is in
// x2,z2 is the location of the plant in the collision map
// rad is the radius of the plant
// for each plant in map, if in CM, add to CM
// value is the value written to the CM
for (a=0; a<maxplants; a++)
{
// calc plant x z
x=px*plantmapsize+plant[a].x;
z=pz*plantmapsize+plant[a].z;
if (waterinway(mx,mz,x,z))
{
continue;
}
if (storepit_in_way(mx,mz,x,z))
{
continue;
}
// calc CM index cx,cz
// if its not in this CM, skip the plant
cx=x/CM_SIZE;
if (cx != CM[i].cx)
{
continue;
}
cz=z/CM_SIZE;
if (cz != CM[i].cz)
{
continue;
}
// ok, plant is in CM index cx,cz
// add it to the CM
// calc x,z coords in the CM (x2,z2)
x2=x-cx*CM_SIZE;
z2=z-cz*CM_SIZE;
// set radius
rad=3;
// set value. 1 = tree
value=1;
// add it!
add_to_CM(i,x2,z2,rad,value);
}
}
void add_savanna_tree_plantmap_to_CM(int i,int mx,int mz,int px,int pz)
{
int a,x,z,cx,cz,x2,z2,rad,value,mod;
// a loop counter
// x,z location of the plant in the map sq
// cx,xz is the index of the collsion map the plant is in
// x2,z2 is the location of the plant in the collision map
// rad is the radius of the plant
// for each plant in map, if in CM, add to CM
// value is the value written to the CM
// mod is the modulo value for haw many trees to add
if (mz < mapsize/3)
{
mod=SAVANNA_TREE_MOD;
}
else
{
mod=NON_TROPICAL_SAVANNA_TREE_MOD;
}
for (a=0; a<maxplants; a++)
{
if (a%mod != 0)
{
continue;
}
// calc plant x z
x=px*plantmapsize+plant[a].x;
z=pz*plantmapsize+plant[a].z;
if (waterinway(mx,mz,x,z))
{
continue;
}
if (storepit_in_way(mx,mz,x,z))
{
continue;
}
// calc CM index cx,cz
// if its not in this CM, skip the plant
cx=x/CM_SIZE;
if (cx != CM[i].cx)
{
continue;
}
cz=z/CM_SIZE;
if (cz != CM[i].cz)
{
continue;
}
// ok, plant is in CM index cx,cz
// add it to the CM
// calc x,z coords in the CM (x2,z2)
x2=x-cx*CM_SIZE;
z2=z-cz*CM_SIZE;
// set radius
rad=3;
// set value. 1 = tree
value=1;
// add it!
add_to_CM(i,x2,z2,rad,value);
}
}
void add_rock_plantmap_to_CM(int i,int mx,int mz,int px,int pz)
{
int a,x,z,cx,cz,x2,z2,rad,value,dx,dz;
location L;
// a loop counter
// x,z location of the plant in the map sq
// cx,xz is the index of the collsion map the plant is in
// x2,z2 is the location of the plant in the collision map
// rad is the radius of the plant
// for each plant in map, if in CM, add to CM
// value is the value written to the CM
for (a=0; a<maxplants; a++)
{
// skip every other rock
if (a%2 == 1)
{
continue;
}
// calc rock x z
x=px*plantmapsize+plant3[a].x;
z=pz*plantmapsize+plant3[a].z;
// stuff it in a location...
L.mx=mx;
L.mz=mz;
L.x=(float)x;
L.z=(float)z;
// check for other terrain in way of the rock
if (terrain_in_way_of_rock(&L))
{
continue;
}
if (waterinway(mx,mz,x,z))
{
continue;
}
// calc CM index cx,cz
// if its not in this CM, skip the rock
cx=x/CM_SIZE;
if (cx != CM[i].cx)
{
continue;
}
cz=z/CM_SIZE;
if (cz != CM[i].cz)
{
continue;
}
// ok, rock is in CM index cx,cz
// add it to the CM
// calc x,z coords in the CM (x2,z2)
x2=x-cx*CM_SIZE;
z2=z-cz*CM_SIZE;
// calc radius
// calc dx and dz dimesions of bbox
dx=(int)(plant3[a].v2.x-plant3[a].v1.x);
dz=(int)(plant3[a].v2.z-plant3[a].v1.z);
// divide by 2 to get x and z radii of bbox
dx/=2;
dz/=2;
// rad = avg of x and z radii of bbox
dx+=dz;
dx/=2;
rad=dx;
// set value. 3 = rock
value=3;
// add it!
add_to_CM(i,x2,z2,rad,value);
}
}
void add_fruittree_plantmap_to_CM(int i,int mx,int mz,int px,int pz)
{
int a,x,z,cx,cz,x2,z2,rad,value;
// a loop counter
// x,z location of the plant in the map sq
// cx,xz is the index of the collsion map the plant is in
// x2,z2 is the location of the plant in the collision map
// rad is the radius of the plant
// for each plant in map, if in CM, add to CM
// value is the value written to the CM
for (a=0; a<maxplants; a++)
{
// calc plant x z
x=px*plantmapsize+plant2[a].x;
z=pz*plantmapsize+plant2[a].z;
if (waterinway(mx,mz,x,z))
{
continue;
}
if (storepit_in_way(mx,mz,x,z))
{
continue;
}
// calc CM index cx,cz
// if its not in this CM, skip the plant
cx=x/CM_SIZE;
if (cx != CM[i].cx)
{
continue;
}
cz=z/CM_SIZE;
if (cz != CM[i].cz)
{
continue;
}
// ok, plant is in CM index cx,cz
// add it to the CM
// calc x,z coords in the CM (x2,z2)
x2=x-cx*CM_SIZE;
z2=z-cz*CM_SIZE;
// set radius
rad=2;
// set value. 4 = fruit tree
value=4;
// add it!
add_to_CM(i,x2,z2,rad,value);
}
}
void add_trees_to_CM(int i,int mx,int mz,int cx,int cz)
{
int px1,pz1,px2,pz2,px3,pz3;
// px1 etc are begin and end of loops for plant maps
// px3 pz3 loop counters
px1=cx*CM_SIZE/plantmapsize;
px2=(cx+1)*CM_SIZE/plantmapsize;
pz1=cz*CM_SIZE/plantmapsize;
pz2=(cz+1)*CM_SIZE/plantmapsize;
for (px3=px1; px3<=px2; px3++)
{
for (pz3=pz1; pz3<=pz2; pz3++)
{
// add plant map mx mz px3 pz3
add_tree_plantmap_to_CM(i,mx,mz,px3,pz3);
}
}
}
void add_savanna_trees_to_CM(int i,int mx,int mz,int cx,int cz)
{
int px1,pz1,px2,pz2,px3,pz3;
// px1 etc are begin and end of loops for plant maps
// px3 pz3 loop counters
px1=cx*CM_SIZE/plantmapsize;
px2=(cx+1)*CM_SIZE/plantmapsize;
pz1=cz*CM_SIZE/plantmapsize;
pz2=(cz+1)*CM_SIZE/plantmapsize;
for (px3=px1; px3<=px2; px3++)
{
for (pz3=pz1; pz3<=pz2; pz3++)
{
add_savanna_tree_plantmap_to_CM(i,mx,mz,px3,pz3);
}
}
}
void add_rocks_to_CM(int i,int mx,int mz,int cx,int cz)
{
int px1,pz1,px2,pz2,px3,pz3;
// px1 etc are begin and end of loops for plant maps
// px3 pz3 loop counters
px1=cx*CM_SIZE/plantmapsize;
px2=(cx+1)*CM_SIZE/plantmapsize;
pz1=cz*CM_SIZE/plantmapsize;
pz2=(cz+1)*CM_SIZE/plantmapsize;
for (px3=px1; px3<=px2; px3++)
{
for (pz3=pz1; pz3<=pz2; pz3++)
{
// add plant map mx mz px3 pz3
add_rock_plantmap_to_CM(i,mx,mz,px3,pz3);
}
}
}
void add_fruittrees_to_CM(int i,int mx,int mz,int cx,int cz)
{
int px1,pz1,px2,pz2,px3,pz3;
// px1 etc are begin and end of loops for plant maps
// px3 pz3 loop counters
px1=cx*CM_SIZE/plantmapsize;
px2=(cx+1)*CM_SIZE/plantmapsize;
pz1=cz*CM_SIZE/plantmapsize;
pz2=(cz+1)*CM_SIZE/plantmapsize;
for (px3=px1; px3<=px2; px3++)
{
for (pz3=pz1; pz3<=pz2; pz3++)
{
// add plant map mx mz px3 pz3
add_fruittree_plantmap_to_CM(i,mx,mz,px3,pz3);
}
}
}
void add_caves_to_CM(int i,int mx,int mz,int cx,int cz)
{
int num,a,index,cx2,cz2,x,z;
num=numcaves[mx][mz];
if (num < 1)
{
return;
}
for (a=0; a<num; a++)
{
index=caveindex[mx][mz][a];
// calc CM index of the cave
cx2=crh2[index].x/CM_SIZE;
cz2=crh2[index].z/CM_SIZE;
// if cave not in this CM, skip the cave
if (cx2 != cx)
{
continue;
}
if (cz2 != cz)
{
continue;
}
// cave is in this CM.
// calc caves CM xz coords
x=crh2[index].x-cx*CM_SIZE;
z=crh2[index].z-cz*CM_SIZE;
// rad=24 value=2 (cave)
add_to_CM(i,x,z,24,2);
}
}
void add_cavern_to_CM(int i,int cx,int cz)
{
int x,z,cx2,cz2;
// calc CM of cavern (cx2 cz2)
cx2=cavern_x/CM_SIZE;
cz2=cavern_z/CM_SIZE;
// if cavern CM is not this CM, return
if (cx != cx2)
{
return;
}
if (cz != cz2)
{
return;
}
// calc x,z of cavern
x=cavern_x-cx*CM_SIZE;
z=cavern_z-cz*CM_SIZE;
// 5 = cavern rad=40
add_to_CM(i,x,z,40,5);
}
void add_rockshelters_to_CM(int i,int mx,int mz,int cx,int cz)
{
int a,cx2,cz2,x,z;
for (a=60000; a<65000; a++)
{
// skip if different map sq
if (crh2[a].mx != mx)
{
continue;
}
// skip if different map sq
if (crh2[a].mz != mz)
{
continue;
}
// calc CM index (cx2,cz2) of rockshelter
cx2=crh2[a].x/CM_SIZE;
cz2=crh2[a].z/CM_SIZE;
// skip if not in this CM
if (cx2 != cx)
{
continue;
}
if (cz2 != cz)
{
continue;
}
// ok its in this CM
// calc ccords
x=crh2[a].x-cx*CM_SIZE;
z=crh2[a].z-cz*CM_SIZE;
// rad = 30 6 = rockshelter
add_to_CM(i,x,z,30,6);
// clear the interior
add_to_CM(i,x,z-10,20,0);
}
}
void add_volcano_to_CM(int i,int cx,int cz)
{
int x,z,cx2,cz2;
// calc CM of volcano (cx2 cz2)
cx2=volcano_x/CM_SIZE;
cz2=volcano_z/CM_SIZE;
// if cavern CM is not this CM, return
if (cx != cx2)
{
return;
}
if (cz != cz2)
{
return;
}
// calc x,z of volcano
x=volcano_x-cx*CM_SIZE;
z=volcano_z-cz*CM_SIZE;
// 6 = volcano rad=50
add_to_CM(i,x,z,50,6);
}
void add_huts_to_CM(int i,int mx,int mz,int cx,int cz)
{
int num,a,b,cx2,cz2,x,z;
num=numhuts3[mx][mz];
if (num < 1)
{
return;
}
for (a=0; a<num; a++)
{
b=hutindex3[mx][mz][a];
cx2=crh2[b].x/CM_SIZE;
cz2=crh2[b].z/CM_SIZE;
if (cx != cx2)
{
continue;
}
if (cz != cz2)
{
continue;
}
x=crh2[b].x-cx*CM_SIZE;
z=crh2[b].z-cz*CM_SIZE;
// 7 = hut
add_to_CM(i,x,z,10,7);
}
}
void add_permshelters_to_CM(int i,int mx,int mz,int cx,int cz)
{
int a,x,z,cx2,cz2;
for (a=0; a<maxcavemen; a++)
{
if (!cm[a].active)
{
continue;
}
if (!cm[a].alive)
{
continue;
}
if (!cm[a].has_perm_shelter)
{
continue;
}
if (cm[a].shel_mx != mx)
{
continue;
}
if (cm[a].shel_mz != mz)
{
continue;
}
cx2=cm[a].shel_x/CM_SIZE;
cz2=cm[a].shel_z/CM_SIZE;
if (cx != cx2)
{
continue;
}
if (cz != cz2)
{
continue;
}
x=cm[a].shel_x-cx*CM_SIZE;
z=cm[a].shel_z-cz*CM_SIZE;
// 8 = perm shel
add_to_CM(i,x,z,10,8);
}
}
void add_tempshelters_to_CM(int i,int mx,int mz,int cx,int cz)
{
int a,cx2,cz2,x,z;
for (a=0; a<max_world_objects; a++)
{
if (!worldobj[a].active)
{
continue;
}
if (!isshelter(a))
{
continue;
}
if (worldobj[a].mx != mx)
{
continue;
}
if (worldobj[a].mz != mz)
{
continue;
}
cx2=(int)worldobj[a].x/CM_SIZE;
cz2=(int)worldobj[a].z/CM_SIZE;
if (cx != cx2)
{
continue;
}
if (cz != cz2)
{
continue;
}
x=(int)worldobj[a].x-cx*CM_SIZE;
z=(int)worldobj[a].z-cz*CM_SIZE;
// 9 = temp shelter
add_to_CM(i,x,z,5,9);
}
}
void gen_CM(int i,int mx,int mz,int cx,int cz)
{
// clear the collision map
clear_CM(i);
// helps if you make it active, etc! also - cx,cz must be set to add plantmaps (trees, rocks, fruit trees)!
CM[i].active=1;
CM[i].mx=mx;
CM[i].mz=mz;
CM[i].cx=cx;
CM[i].cz=cz;
// add trees as required...
switch (map[mx][mz].coverage)
{
case WOODS:
case JUNGLE:
add_trees_to_CM(i,mx,mz,cx,cz);
break;
case SAVANNA:
add_savanna_trees_to_CM(i,mx,mz,cx,cz);
break;
}
add_caves_to_CM(i,mx,mz,cx,cz);
if (map[mx][mz].rocks)
{
add_rocks_to_CM(i,mx,mz,cx,cz);
}
if (map[mx][mz].fruittree)
{
add_fruittrees_to_CM(i,mx,mz,cx,cz);
}
if (map[mx][mz].cavern)
{
add_cavern_to_CM(i,cx,cz);
}
add_rockshelters_to_CM(i,mx,mz,cx,cz);
if (map[mx][mz].volcano)
{
add_volcano_to_CM(i,cx,cz);
}
add_huts_to_CM(i,mx,mz,cx,cz);
add_permshelters_to_CM(i,mx,mz,cx,cz);
add_tempshelters_to_CM(i,mx,mz,cx,cz);
}
int get_CM_index(int mx,int mz,int cx,int cz)
{
int best,bestval,a;
// first: see if it exists, if so return its index...
for (a=0; a<CM_CACHE_SIZE; a++)
{
if (!CM[a].active)
{
continue;
}
if (CM[a].mx != mx)
{
continue;
}
if (CM[a].mz != mz)
{
continue;
}
if (CM[a].cx != cx)
{
continue;
}
if (CM[a].cz != cz)
{
continue;
}
return(a);
}
// doesnt exist. need to make one.
// serch for inactive, if found, use it to generate a CM and return its index...
for (a=0; a<CM_CACHE_SIZE; a++)
{
if (!CM[a].active)
{
gen_CM(a,mx,mz,cx,cz);
return(a);
}
}
// didnt find inactive CM. must use LRU one.
// find LRU CM, use it to gen new CM, and return its index...
best=0;
bestval=0;
for (a=0; a<CM_CACHE_SIZE; a++)
{
if (CM[a].age > bestval)
{
best=a;
bestval=CM[a].age;
}
}
gen_CM(best,mx,mz,cx,cz);
return(best);
}
// age all maps except map i
void age_CMs(int i)
{
int a;
for (a=0; a<CM_CACHE_SIZE; a++)
{
if (!CM[a].active)
{
continue;
}
if (a == i)
{
CM[a].age=0;
}
else
{
CM[a].age++;
}
}
}
int CM_terrain_in_way(int mx,int mz,int x,int z,int rad)
{
int x1,z1,x2,z2,a,b,a2,b2,mx2,mz2,cx,cz,a3,b3,i;
// x1 z1 z2 z2 start and end of loops
// a b loop counters
// mx2 mz2 a2 b2 normalized world coords
// mx2 mz2 cx cz a3 b3 collsion map coords
// i is the index of the collsion map
// check for "off the map"
if (mx < 0)
{
return(1);
}
if (mx >= mapsize)
{
return(1);
}
if (mz < 0)
{
return(1);
}
if (mz >= mapsize)
{
return(1);
}
if (map[mx][mz].elevation == OCEAN)
{
return(1);
}
if (map[mx][mz].elevation == IMPASSMTNS)
{
return(1);
}
x1=x-rad;
z1=z-rad;
x2=x+rad;
z2=z+rad;
for (a=x1; a<=x2; a++)
{
for (b=z1; b<=z2; b++)
{
mx2=mx;
mz2=mz;
a2=a;
b2=b;
// normalize mx2 mz2 a2 b2
while (a2<0)
{
a2+=map_sq_size;
mx2--;
}
while (a2>=map_sq_size)
{
a2-=map_sq_size;
mx2++;
}
while (b2<0)
{
b2+=map_sq_size;
mz2--;
}
while (b2>=map_sq_size)
{
b2-=map_sq_size;
mz2++;
}
// if off edge of world map, return -1
if (mx2 < 0)
{
return(-1);
}
if (mx2 >= mapsize)
{
return(-1);
}
if (mz2 < 0)
{
return(-1);
}
if (mz2 >= mapsize)
{
return(-1);
}
// convert to CM coords: mx2 mz2 cx cz a3 b3
cx=a2/CM_SIZE;
cz=b2/CM_SIZE;
a3=a2-cx*CM_SIZE;
b3=b2-cz*CM_SIZE;
// get index of collsion map mx2 mz2 cx cz
i=get_CM_index(mx2,mz2,cx,cz);
age_CMs(i);
// if cm[i].data[a3][b3] !=0, ret cm[i].data[a3][b3]
if (CM[i].data[a3][b3] != 0)
{
return(CM[i].data[a3][b3]);
}
}
}
return(0);
}
// ############################### END COLLISION MAPS ################################################