adding new feature requires 99 code changes!

Started by
39 comments, last by Norman Barrows 10 years, 7 months ago


Do not post code in blue comic sans on this forum, or anywhere on the Internet, ever again. We have tags, use them.

i've been having trouble with "[ slash code ]" truncating everything after it in the post, thus the strange font.

sorry about that!

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Advertisement
i've hooked up the generic "alive band member" iterator to the main loop in BMupdate_all.

i also put the body of the loop in its own function: BMupdate_each(int a);

then i collapsed all the calls in BMupdate_each to inline code to create a new version called BMupdate_each2

the iterators....



 
 

int BM_alive_num,BM_active_num;
 
 
int first_alive_bandmember()
{
int a;
for (a=0; a<maxcavemen; a++)
    {
    if (cm[a].active == 0)
        {
        continue;
        }
    if (cm[a].alive == 0)
        {
        continue;
        }
    BM_alive_num=a;
    return(a);
    }
return(-1);
}
 
 
 
 
int next_alive_bandmember()
{
int a;
for (a=BM_alive_num+1; a<maxcavemen; a++)
    {
    if (cm[a].active == 0)
        {
        continue;
        }
    if (cm[a].alive == 0)
        {
        continue;
        }
    BM_alive_num=a;
    return(a);
    }
return(-1);
}
 
 
 
 
 
 
 
 
int first_active_bandmember()
{
int a;
for (a=0; a<maxcavemen; a++)
    {
    if (cm[a].active == 0)
        {
        continue;
        }
    BM_active_num=a;
    return(a);
    }
return(-1);
}
 
 
 
 
 
 
 
 
int next_active_bandmember()
{
int a;
for (a=BM_active_num+1; a<maxcavemen; a++)
    {
    if (cm[a].active == 0)
       {
       continue;
       }
   BM_active_num=a;
   return(a);
   }
return(-1);
}
 
 
 



here's the new BMupdate_all:



 
 
//    must call move_rafts first!
void BMupdate_all()
{
int a;
a=first_alive_bandmember();
while (a!=-1)
    {
    BMupdate_each(a);
    a=next_alive_bandmember();
    }
}
 
 


and now, for a wall of spaghetti code - the new BMupdate_each2 with all the code pulled into one function.


this thing is probably similar to that 32,000 line (or whatever it was) update function mentioned previously....

it seems to be bigger, uglier, and probably more work to maintain. one function, 905 line of code.




 
 
 

void BMupdate_each2(int a)
{
int b,c,e,mx,mz,d,num,f,chance,rng;
float h,x,y,z;
char s[100];
//    do update stuff here - do global frame
//   decrease fatigue
if ((cm[a].moved==0) && (!cm[a].paddling) && (action[cm[a].current_action].energy))
    {
    cm[a].fatigue-=7;                               // reduce fatigue.
    if (cm[a].fatigue<0) cm[a].fatigue=0;
    }
//    model attack
if (cm[a].attacking) 
    {
    cm[a].attack_counter++;
    if (on_drug(a,GAHMUHROOT)) c=atktime*3/4; else c=atktime;
    if (cm[a].attack_counter >= c) 
        { 
        cm[a].attacking=0; 
        }
    else if (cm[a].attack_counter==5) resolve_attack(a);
    }
//   model surprise
if (cm[a].suprised)
    {    
    cm[a].suprise_counter++;
    if (cm[a].suprise_counter>60-xpbonus(cm[a].xp[HUNTING])) cm[a].suprised=0;
    }
//  model full fatigue
if (cm[a].fatigue >= 100000)
    {
    if (cm[a].current_action != MOVE) msg("You're so fatigued you have to stop and rest!");
    // dont resume the following actions w/ friendly cavemen, as they may have wandered off while band member was resting
    if ( (cm[a].current_action != TEACHCAVEMAN) && (cm[a].current_action != TELLJOKE) && (cm[a].current_action != TELLSTORY) )  pushaction2(a);   
    b=gamespeed;
    setaction(a,REST);
    gamespeed=b;
    cm[a].action_x=0;     // no bedding
    }
//   run bamdmember
if (a!=cm0) 
    {
    if (  badguys_nearby(a) && (cm[a].current_action != DONOTHING)  )        // halt action if badguys near
        {
        if (cm[a].current_action == MOVE) adjust_bandmember_location(a);
        setaction(a,DONOTHING);
        }
    if (cm[a].current_action==DONOTHING)
        {
        cm[a].is_blocking=0;
        if (cm[a].collision_recovery)
            {
            move_bandmember_collision_recovery(a);
            }
        else
            {
            set_bandmember_tgt(a);
            steer_bandmember(a);
            move_bandmember(a);
            do_bandmember_atk(a);
            }
        }
    else
        {
        b=cm0;
        cm0=a;
        doactionmodeB(a);
        cm0=b;
        }
    }
//     model raft movement
if (cm[a].location == ONRAFT)
    {
    if (cm[a].current_action != MOVERAFT)
        {
b=cm[a].raftnum;
        cm[a].x+=worldobj[b].dx;
        cm[a].z+=worldobj[b].dz;
        normalize_location( &cm[a].mx, &cm[a].mz, &cm[a].x, &cm[a].z );
        cm[a].y=heightmap(cm[a].mx,cm[a].mz,cm[a].x,cm[a].z);
        }
    }
//  model paddling fatigue
if (cm[a].paddling)
    {
    cm[a].fatigue+=1;
    if (cm[a].fatigue>100000) cm[a].fatigue=100000;
    }
//  model falling
if (cm[a].falling) 
    {
    cm[a].vy+=-g2;
    cm[a].x+=cm[a].vx;
    cm[a].y+=cm[a].vy;
    cm[a].z+=cm[a].vz;
    h=heightmap( cm[a].mx, cm[a].mz, cm[a].x,cm[a].z);
    if (cm[a].y <= h ) bandmember_hit_ground(a,h);
    }
//   model sneak detection
if (   (a % 15 == frame) && (cm[a].sneak_state!=0)  )
    {
    if (cm[a].sneak_state==3)
        {
        if (! bandmember_targeted(a)) cm[a].sneak_state=1;
        }
    else       // states 1 & 2
        {
        switch (detection_state(a))
            {
            case 0: cm[a].sneak_state=1;    //   sneaking - undetected
                    break;
            case 1: cm[a].sneak_state=2;     // sneaking - detected - non-hostile
                    break;
            case 2: cm[a].sneak_state=3;     // sneaking - detected - hostile
                    break;
            }
        }
    }
if (frame != 0)
    {
    return;
    }
//  do global second
//  model fatgue due to damage
if  (   
    (! on_drug(a,MUHAHBOOLEAF)) &&
    (! on_drug(a,YAHBEEBARK))   &&
    (! on_drug(a,BAHYUHSEED))   &&
    (! on_drug(a,GAHMUHROOT)) 
    )
    {
    cm[a].fatigue+=10*cm[a].dmg/cm[a].hp;
    if (cm[a].fatigue>=100000) cm[a].fatigue=100000;
    }
//  model fatigue due to encumberance
if (    (!on_drug(a,MUHAHBOOLEAF)) &&   (! on_drug(a,BAHYUHSEED))  )
    {
    cm[a].fatigue+=10*encumberance(a)/maxencumberance(a);
    if (cm[a].fatigue>=100000) cm[a].fatigue=100000;
    }
//  run quests
for (b=0; b<maxquests; b++)
    {
    if (! cm[a].quest[b].active) continue;
    run_quest(a,b);
    }
//  clear rock shelter encounter flags
mx=cm[a].mx;
mz=cm[a].mz;
if ( map[mx][mz].cliffs) 
    {
    for (e=60000; e<65000; e++)
        {
        if (crh2[e].mx != mx) continue;
        if (crh2[e].mz != mz) continue;
        if (crh2[e].encounter_checked)
            {
            if (first_bandmember_near_cave_or_rockshelter(mx,mz,e,300) == -1)
                {
                remove_CRH_cavemen(2,mx,mz,e);     // 2 = rockshelter housetype        removes friendly cavemen only!
                crh2[e].encounter_checked=0;
                if ((crh2[e].owner_type==HOSTILECAVE) && (hostile_CRH_encounter_underway) )
                    {
                    if ((! hostile_fled_CRH_encounter) && (! hostile_in_mapsq(a))) crh2[e].owner_type=EMPTYCAVE;
                    hostile_CRH_encounter_underway=0;
                    hostile_fled_CRH_encounter=0;
                    }
                }
            }
        }
    }
//   check rock shelter encounters
mx=cm[a].mx;
mz=cm[a].mz;
if ( map[mx][mz].cliffs)
    {
    for (e=60000; e<65000; e++)
        {
        if (crh2[e].mx != mx) continue;
        if (crh2[e].mz != mz) continue;
        if (crh2[e].encounter_checked) continue;
        if ( BBdist( (int)cm[a].x, (int)cm[a].z, crh2[e].x,crh2[e].z) > 75) continue;        // trigger at 75, reset at 300
        crh2[e].encounter_checked=1;
        switch ( crh2[e].owner_type )
            {
            case ANIMALCAVE: do_cave_animal_encounter(a); break;
            case FRIENDLYCAVE:  
                                if (crh2[e].npc_ownerID == -1)        // no npc assigned to rockshelter yet, so assign one
                                    {
                                    num=dice(10);
                                    for (b=0; b<num; b++)
                                        {
                                        x=crh2[e].x-20.0f+(float)b*10.0f;
                                        z=crh2[e].z+40.0f;
                                        y=heightmap(mx,mz,x,z);
                                        d=add_caveman(mx,mz,x,y,z,0,0);
                                        if (d != -1)
                                            {
                                            animal[a].butchered=new_npc();
                                            if (b==0) crh2[e].npc_ownerID=animal[d].butchered;
                                            npc[animal[d].butchered].house_type=2;    // house type: 0=unassigned 1=cave 2=rockshelter 3=hut
                                            npc[animal[d].butchered].house_mx=mx;
                                            npc[animal[d].butchered].house_mz=mz;
                                            npc[animal[d].butchered].house_index=e;
                                            animal[d].sacrificed=1;   // 1= they're a CRH caveman
                                            }
                                        }
                                    }
                                else
                                    {
                                    c=0;
                                    for (b=0; b<maxnpcs; b++)
                                        {
                                        if (! npc[b].active) continue;
                                        if (npc[b].house_type != 2) continue;       // if not rockshelter
                                        if (npc[b].house_mx != mx) continue;
                                        if (npc[b].house_mz != mz) continue;
                                        if (npc[b].house_index != e) continue;
                                        x=crh2[e].x-20.0f+(float)c*10.0f;
                                        z=crh2[e].z+40.0f;
                                        y=heightmap(mx,mz,x,z);
                                        d=add_caveman(mx,mz,x,y,z,0,0);
                                        if (d != -1)
                                            {
                                            animal[d].butchered=b;
                                            animal[d].sacrificed=1;   // 1= they're a CRH caveman
                                            }
                                        c++;
                                        }
                                    }
                                msg("You encounter cavemen from the nearby rockshelter!");
                                if (cm[a].current_action == MOVE) adjust_bandmember_location(a);
                                setaction(a,DONOTHING);
                                gamespeed=0;
                                break;
            case HOSTILECAVE:   add_hostile_cavemen(a,0); 
                                msg("You encounter cavemen from the nearby rockshelter!");
                                if (cm[a].current_action == MOVE) adjust_bandmember_location(a);
                                setaction(a,DONOTHING);
                                gamespeed=0;
                                hostile_CRH_encounter_underway=1;
                                hostile_fled_CRH_encounter=0;
                                break;
            case PLAYERCAVE: if (dice(10000)<=1000)  do_cave_animal_encounter(a); break;
            }
        }
    }
//    clear cave encounter flags
mx=cm[a].mx;
mz=cm[a].mz;
if ((map[mx][mz].elevation == 2) || (map[mx][mz].elevation == 3)) 
    {
for (f=0; f<numcaves[mx][mz]; f++)
    {
    e=caveindex[mx][mz][f];
        if (crh2[e].encounter_checked)
            {
            if (first_bandmember_near_cave_or_rockshelter(mx,mz,e,300) == -1)
                {
                remove_CRH_cavemen(1,mx,mz,e);     // 1 = cave housetype        removes friendly cavemen only!
                crh2[e].encounter_checked=0;
                if ((crh2[e].owner_type==HOSTILECAVE) && (hostile_CRH_encounter_underway) )
                    {
                    if ((! hostile_fled_CRH_encounter) && (! hostile_in_mapsq(a))) crh2[e].owner_type=EMPTYCAVE;
                    hostile_CRH_encounter_underway=0;
                    hostile_fled_CRH_encounter=0;
                    }
                }
            }
    }
    for (e=0; e<60000; e++)
        {
        if (crh2[e].mx != mx) continue;
        if (crh2[e].mz != mz) continue;
        if (crh2[e].encounter_checked)
            {
            if (first_bandmember_near_cave_or_rockshelter(mx,mz,e,300) == -1)
                {
                remove_CRH_cavemen(1,mx,mz,e);     // 1 = cave housetype        removes friendly cavemen only!
                crh2[e].encounter_checked=0;
                if ((crh2[e].owner_type==HOSTILECAVE) && (hostile_CRH_encounter_underway) )
                    {
                    if ((! hostile_fled_CRH_encounter) && (! hostile_in_mapsq(a))) crh2[e].owner_type=EMPTYCAVE;
                    hostile_CRH_encounter_underway=0;
                    hostile_fled_CRH_encounter=0;
                    }
                }
            }
        }
    }
//  check cave encounters
mx=cm[a].mx;
mz=cm[a].mz;
if ((map[mx][mz].elevation == 2) || (map[mx][mz].elevation == 3)) 
    {
for (f=0; f<numcaves[mx][mz]; f++)
    {
    e=caveindex[mx][mz][f];
        if (crh2[e].encounter_checked) return;
        if ( BBdist( (int)cm[a].x, (int)cm[a].z, crh2[e].x,crh2[e].z) > 75) continue;        // trigger at 75, reset at 300
        crh2[e].encounter_checked=1;
        switch ( crh2[e].owner_type )
            {
            case ANIMALCAVE: do_cave_animal_encounter(a); break;
            case FRIENDLYCAVE: 
                                if (crh2[e].npc_ownerID == -1)  // no npc assigned to cave yet, so assign one
                                    {
                                    num=dice(10);
                                    for (b=0; b<num; b++)
                                        {
                                        x=crh2[e].x-20.0f+(float)b*10.0f;
                                        z=crh2[e].z+40.0f;
                                        y=heightmap(mx,mz,x,z);
                                        d=add_caveman(mx,mz,x,y,z,0,0);
                                        if (d != -1)
                                            {
                                            animal[d].butchered=new_npc();
                                            if (b==0) crh2[e].npc_ownerID=animal[d].butchered;
                                            npc[animal[d].butchered].house_type=1;    // house type: 0=unassigned 1=cave 2=rockshelter 3=hut
                                            npc[animal[d].butchered].house_mx=mx;
                                            npc[animal[d].butchered].house_mz=mz;
                                            npc[animal[d].butchered].house_index=e;
                                            animal[d].sacrificed=1;   // 1= they're a CRH caveman
                                            }
                                        }
                                    }
                                else
                                    {
                                    c=0;
                                    for (b=0; b<maxnpcs; b++)
                                        {
                                        if (! npc[b].active) continue;
                                        if (npc[b].house_type != 1) continue;    // if not cave
                                        if (npc[b].house_mx != mx) continue;
                                        if (npc[b].house_mz != mz) continue;
                                        if (npc[b].house_index != e) continue;
                                        x=crh2[e].x-20.0f+(float)c*10.0f;
                                        z=crh2[e].z+40.0f;
                                        y=heightmap(mx,mz,x,z);
                                        d=add_caveman(mx,mz,x,y,z,0,0);
                                        if (d != -1)
                                            {
                                            animal[d].butchered=b;
                                            animal[d].sacrificed=1;   // 1= they're a CRH caveman
                                            }
                                        c++;
                                        }
                                    }
                                msg("You encounter cavemen from the nearby cave!");
                                if (cm[a].current_action == MOVE) adjust_bandmember_location(a);
                                setaction(a,DONOTHING);
                                gamespeed=0;
                                break;
            case HOSTILECAVE:   add_hostile_cavemen(a,0); 
                                msg("You encounter cavemen from the nearby cave!");
                                if (cm[a].current_action == MOVE) adjust_bandmember_location(a);
                                setaction(a,DONOTHING);
                                gamespeed=0;
                                hostile_CRH_encounter_underway=1;
                                hostile_fled_CRH_encounter=0;
                                break;
            case PLAYERCAVE: if (dice(10000)<=1000)  do_cave_animal_encounter(a); break;
            }
    }
    }
//    clear hut encounter flags
mx=cm[a].mx;
mz=cm[a].mz;
for (e=65000; e<num_crhs; e++)
    {
    if (! crh2[e].active) continue;
    if (crh2[e].mx != mx) continue;
    if (crh2[e].mz != mz) continue;
    if (crh2[e].encounter_checked)
        {
        if (! bandmember_near_hut(e))            // if no bandmember <= 300 from hut
            {
            remove_CRH_cavemen(3,mx,mz,0);       // 3 = hut housetype        removes friendly cavemen only!
            crh2[e].encounter_checked=0;
            }
        }
    }
//   check hut encounters
mx=cm[a].mx;
mz=cm[a].mz;
for (e=65000; e<num_crhs; e++)
    {
    if (! crh2[e].active) continue;
    if (crh2[e].mx != mx) continue;
    if (crh2[e].mz != mz) continue;
    if (crh2[e].encounter_checked) continue;
    if ( BBdist( (int)cm[a].x, (int)cm[a].z, crh2[e].x,crh2[e].z) > 75) continue;        // trigger at 75, reset at 300
    crh2[e].encounter_checked=1;
    switch ( crh2[e].owner_type )
        {
        case FRIENDLYCAVE: 
                            if (crh2[e].npc_ownerID == -1)        // no npc assigned to hut yet, so assign one
                                {
                                num=dice(10);
                                for (b=0; b<num; b++)
                                    {
                                    x=crh2[e].x-20.0f+(float)b*10.0f;
                                    z=crh2[e].z+30.0f;
                                    y=heightmap(mx,mz,x,z);
                                    d=add_caveman(mx,mz,x,y,z,0,0);
                                    if (d != -1)
                                        {
                                        animal[d].butchered=new_npc();
                                        if (b==0) crh2[e].npc_ownerID=animal[d].butchered;
                                        npc[animal[d].butchered].house_type=3;    // house type: 0=unassigned 1=cave 2=rockshelter 3=hut
                                        npc[animal[d].butchered].house_mx=mx;
                                        npc[animal[d].butchered].house_mz=mz;
                                        animal[d].sacrificed=1;   // 1= they're a CRH caveman
                                        }
                                    }
                                }
                            else
                                {
                                c=0;
                                for (b=0; b<maxnpcs; b++)
                                    {
                                    if (! npc[b].active) continue;
                                    if (npc[b].house_type != 3) continue;        // if not hut
                                    if (npc[b].house_mx != mx) continue;
                                    if (npc[b].house_mz != mz) continue;
                                    x=crh2[e].x-20.0f+(float)c*10.0f;
                                    z=crh2[e].z+30.0f;
                                    y=heightmap(mx,mz,x,z);
                                    d=add_caveman(mx,mz,x,y,z,0,0);
                                    if (d != -1)
                                        {
                                        animal[d].butchered=b;
                                        animal[d].sacrificed=1;   // 1= they're a CRH caveman
                                        }
                                    c++;
                                    }
                                }
                            msg("You encounter cavemen from the nearby hut!");
                            if (cm[a].current_action == MOVE) adjust_bandmember_location(a);
                            setaction(a,DONOTHING);
                            gamespeed=0;
                            break;
        case HOSTILECAVE:   add_hostile_cavemen(a,0); 
                            msg("You encounter cavemen from the nearby hut!");
                            if (cm[a].current_action == MOVE) adjust_bandmember_location(a);
                            setaction(a,DONOTHING);
                            gamespeed=0;
                            break;
        case PLAYERCAVE: if (dice(10000)<=1000)  do_animal_encounter(a); break;
        }
    }
//   check hut takeover
for (b=65000; b<num_crhs; b++)
    {
    if (! crh2[b].active) continue;
    if (! crh2[b].encounter_checked) continue;
    if (crh2[b].mx != cm[a].mx) continue;
    if (crh2[b].mz != cm[a].mz) continue;
    if (BBdist( (int)cm[a].x, (int)cm[a].z,  crh2[b].x, crh2[b].z ) > 50) continue;
    if (cavemen_near_hut(b)) continue;
    msg("The nearby hut has been abandoned !");
    if (cm[a].has_perm_shelter) Znewmenu("Abandon your hut and take this one over ?");
    else Znewmenu("Takeover abandoned hut ?");
    Zaddmenu("Yes");
    Zaddmenu("No");
    if (menu(2)==1)
        {
        // create perm shelter where hut is
        cm[a].has_perm_shelter=1;
        cm[a].shel_mx=cm[a].mx;
        cm[a].shel_mz=cm[a].mz;
        cm[a].shel_x=crh2[b].x;
        cm[a].shel_z=crh2[b].z;
        cm[a].perm_shel_quality=100;
        }
    crh2[b].active=0;
    pcrh2[b].active=0;
    // sort_and_index_huts("Updating huts");
index_huts2();
    cm[a].mood+=10;
    ulim(&cm[a].mood,100);
    }
//   check climbing animals
if (cm[a].location == UPATREE)
    {
    check_animal_climbing_up(a);
    }
if (second != 0)
    {
    return;
    }
//    do global minute
//    check animal encounters
b=animal_encounter_chance();
if (dice(10000) <= b)
    {
    do_animal_encounter(a);
    }
//  check caveman encounters
if (dice(10000) > 10)
    {
    return;
    }
b=caveman_encounter_chance(a);
if (dice(10000) > b)
    {
    return;
    }
do_caveman_encounter(a);
//   model intox
for (b=0; b<maxdrugs; b++)
    {
    if (! cm[a].drug[b].active) continue;
    cm[a].drug[b].age++;
    if (cm[a].drug[b].age>400)
        {
        switch(cm[a].drug[b].type)
            {
            case MUHAHBOOLEAF:          cm[a].dex--;
                                        cm[a].sleep-=50;
                                        llim(&cm[a].sleep,0);
                                        cm[a].fatigue+=50000;
                                        ulim(&cm[a].fatigue,100000);
                                        break;
            case BOOYEEBEEBERRY:        cm[a].intelligence-=2;
                                        break;
            case GAHYEEMOOGUHFLOWER:    cm[a].sleep-=10;
                                        llim(&cm[a].sleep,0);
                                        break;
            case YAHBEEBARK:            cm[a].mood-=40;
                                        llim(&cm[a].mood,0);
                                        break;
            case BAHYUHSEED:            cm[a].str-=3;
                                        cm[a].sleep-=50;
                                        llim(&cm[a].sleep,0);
                                        cm[a].fatigue+=50000;
                                        ulim(&cm[a].fatigue,100000);
                                        break;
            case GAHMUHROOT:            cm[a].speed-=2;
                                        cm[a].sleep-=50;
                                        llim(&cm[a].sleep,0);
                                        cm[a].fatigue+=50000;
                                        ulim(&cm[a].fatigue,100000);
                                        break;
            }
        cm[a].drug[b].active=0;
        }
    }
//  extinguish torches
for (b=0; b<maxobjrecs; b++)
    if (  (cm[a].stuff[b].active) && (cm[a].stuff[b].type==LITTORCH) )
        { 
        cm[a].stuff[b].qual--;
        if (cm[a].stuff[b].qual < 1) cm[a].stuff[b].active=0;
        }
if (minute%7 == 0)
    {
//   reduce hygiene due to movement
    if (cm[a].moved)
        {
        cm[a].hygiene--;
        if (cm[a].running) cm[a].hygiene--;
        if (cm[a].hygiene<0) cm[a].hygiene=0;
        }
    }
if (minute%10 == 0)
    {
//   reduce water
    cm[a].water--; 
    if (cm[a].water<0) cm[a].water=0; 
//  reduce sleep
    cm[a].sleep--; 
    if (cm[a].sleep<=0)
        {
        cm[a].sleep=0;
        if (cm[a].current_action != SLEEP)
            {
            setaction(a,SLEEP);   // sleep
            cm[a].actiondata[0]=0;
            cm[a].actiondata[1]=cm[a].sleep;    // save old sleep value for mood check when they wake up
            cm[a].actiondata[2]=100;
            if ((cm[a].dmg>0) || (cm[a].has_disease))
                {
                if (num_carried(a,MEDHERB,ANYQUALITY) > 0)
                    {
                    remove_best(a,MEDHERB);
                    cm[a].actiondata[3]=1;          // using med herbs
                    }
                else cm[a].actiondata[3]=0;         // not using med herbs
                }
            else cm[a].actiondata[3]=0;           // not using med herbs
            msg("You pass out from lack of sleep!");
            }
        }
    }
if (minute%15 == 0)
    {
//    reduce food
    cm[a].food--; 
    if (cm[a].food<0) cm[a].food=0;
//  affect mood
    if (! on_drug(a,MUHAHBOOLEAF)) 
        {
        if (cm[a].water<1) 
            {
            cm[a].mood--;
            if (cm[a].mood<0) cm[a].mood=0;
            }
        if (cm[a].food<1) 
            {
            cm[a].mood--;
            if (cm[a].mood<0) cm[a].mood=0;
            }
        if (    !on_drug(a,YAHBEEBARK) && !on_drug(a,BAHYUHSEED))
            {
            if (cm[a].dmg>cm[a].hp/2) 
                {
                cm[a].mood--;
                if (cm[a].mood<0) cm[a].mood=0;
                }
            }
        if (cm[a].has_disease) 
            {
            cm[a].mood--;
            if (cm[a].mood<0) cm[a].mood=0;
            }
        if (cm[a].hygiene<1) 
            {
            cm[a].mood--;
            if (cm[a].mood<0) cm[a].mood=0;
            }
        if (encumberance(a)>3*maxencumberance(a)/4) 
            {
            cm[a].mood--;
            if (cm[a].mood<0) cm[a].mood=0;
            }
        if (  (is_raining) &&  (!has_shelter(a))  && !on_drug(a,GAHMUHROOT) && ! on_drug(a,MUHAHBOOLEAF) )      // rain
            {
            cm[a].mood-=2;
            if (cm[a].mood<0) cm[a].mood=0;
            }
        b=cm0;
        cm0=a;
        if (  (windchill(a) < 60.0f) && (!has_shelter(a)) && (! near_fire())   && !on_drug(a,GAHMUHROOT) && !on_drug(cm0,MUHAHBOOLEAF)  )        // cold
            {
            cm[a].mood-=2;
            if (cm[a].mood<0) cm[a].mood=0;
            }
        cm0=b;
        if (temp_at(a) > 80.0f)        // heat
            {
            cm[a].mood--;
            if (cm[a].mood<0) cm[a].mood=0;
            }
        if (cm[a].social<1)            // make social affect mood
            if (dice(10000) <= 23)
                {
                cm[a].mood--;
                if (cm[a].mood<0) cm[a].mood=0;
                }
        }
    }
if (minute != 0)
    {
    return;
    }
//    do global hour
//  reduce hygiene
if (cm[a].hygiene>=1) cm[a].hygiene--;
//   model dehydration
if (cm[a].water<1) 
    {
    if (dice(100)<=12) 
        {
        cm[a].dmg++;
        cm[a].mood-=2;
        llim(&cm[a].mood,0);
        msg("You take damage from dehydration!");
        if (cm[a].dmg>=cm[a].hp)
            {
            msg("You died of dehydration!");
            kill_bandmember(a);
            }
        }
    }
//   model food spoilage
for (b=0; b<maxobjrecs; b++)
    {
    if (!cm[a].stuff[b].active) continue;
    if (object[cm[a].stuff[b].type].spoilchance==0) continue;
    if (dice(10000) >= object[cm[a].stuff[b].type].spoilchance) continue;
    cm[a].stuff[b].qual-=object[cm[a].stuff[b].type].spoilrate;
    if (cm[a].stuff[b].qual<1)
        {
        cm[a].stuff[b].active=0;
        strcpy_s(s,100,"Some of your ");
        strcat_s(s,100,object[cm[a].stuff[b].type].name);
        strcat_s(s,100," spoiled!");
        msg(s);
        }
    }
//  model exposure
if (exposed(a))  
    {
    if (dice(10000) <= 1000) 
        {
        cm[a].dmg++;
        cm[a].mood-=2;
        llim(&cm[a].mood,0);
        msg("You take damage from exposure to cold!");
        if (cm[a].dmg >= cm[a].hp)
            {
            msg("You died from exposure to cold!");
            kill_bandmember(a);
            }
        }
    }
//  model heatstroke
if  (
    (temp_at(a) > 100) &&
    ((cm[a].location==OUTSIDE) && (map[cm[a].mx][cm[a].mz].coverage!=WOODS))   &&
    ((cm[a].location==OUTSIDE) && (map[cm[a].mx][cm[a].mz].coverage!=JUNGLE))  &&
    (! has_shelter(a)) &&
    (dice(10000) <= 1000)
    )
    {
    cm[a].dmg++;
    cm[a].mood-=2;
    llim(&cm[a].mood,0);
    msg("You take damage from heatstroke!");
    if (cm[a].dmg >= cm[a].hp)
        {
        msg("You died from heatstroke!");
        kill_bandmember(a);
        }
    }
//   model drown in flood
if (watertable>6.0f)                                                                // model drowning in floods
    if(watertable>heightmap(cm[a].mx,cm[a].mz,cm[a].x,cm[a].z)+7.0f)   
        { 
        msg("You have been swept away by flood waters and drown!"); 
        kill_bandmember(a); 
        }
//   model wear n tear of clothing etc
for (b=0; b<maxobjrecs; b++)
    {
    if (!cm[a].stuff[b].active) continue;
    switch(cm[a].stuff[b].type)
        {
        case BOOTS:
        case HAT:
        case MITTENS:
        case CLOAK:
                    if ( is_raining && ! has_shelter(a) ) chance = 1000;
                    else chance = 462;
                    if (dice(10000) > chance) break;
                    cm[a].stuff[b].qual--;
                    if (cm[a].stuff[b].qual>0) break;
                    Ss("Your ");
                    Sa(object[cm[a].stuff[b].type].name);
                    Sa(" wore out!");
                    msg(S);
                    cm[a].stuff[b].active=0;
                    break;
        }
    }
//   model perm shelter raids
if (cm[a].has_perm_shelter)
    {
    if (dice(10000) <= 100)
        {
        chance = 200 - xpbonus(cm[a].xp[CAMOFLAGE]);
        rng=rng2closest_hostile_CRH(cm[a].shel_mx,cm[a].shel_mz);
        if (rng<1) rng=1;
        chance+=200/rng;
        if (dice(10000) <= chance) raid_perm_shelter(a);
        }
    }
//    moodboost nature lovers
if  (   
    (dice(10000) <= 2500)  &&   
    (has_interest(a,I_NATURE))   &&
    (   (map[cm[a].mx][cm[a].mz].coverage == WOODS) ||  (map[cm[a].mx][cm[a].mz].coverage == JUNGLE) || (map[cm[a].mx][cm[a].mz].rocks)  )
    )
    {
    cm[a].mood++; 
    ulim(&cm[a].mood,100);
    }
if (hour%2 == 0)
    {
//  model damage due to illness
    if (   (cm[a].has_disease)  &&   (dice(1000) < 100-xpbonus(cm[a].xp[HEALING]))   )
        {
        cm[a].dmg++;
        cm[a].mood-=2;
        llim(&cm[a].mood,0);
        msg("You take damage from being sick!");
        if (cm[a].dmg>=cm[a].hp)
            {
            msg("You died from an illness!");
            kill_bandmember(a);
            }
        }
    }
if (((hour>7)&&(hour<19)))
    {
//  check quest encounters
    if (  (at_friendly_CRH(a)) &&  (num_friendlies() > 0) &&  (dice(10000) <= 1000)  )   do_quest_encounter(a);
    }
if (hour != 0)
    {
    return;
    }
//    do global day
//  model starvation
if (   (cm[a].food<1)  &&  (dice(100)<=42)  )
    {
    cm[a].dmg++;
    msg("You take damage from starvation!");
    cm[a].mood-=5;
    llim(&cm[a].mood,0);
    if (cm[a].dmg>=cm[a].hp)
        {
        msg("You died of starvation!");
        kill_bandmember(a);
        }
    }
//  model getting sick
if (cm[a].hygiene<1) b=100; else b=20;    // low hygiene increases chance
b-=cm[a].con;                              // constitution decreases chance
if (exposed(a) || exposed2(a)) b+=300;   // exposure increases chance
if (dice(1000)<b)
    {
    cm[a].has_disease=1;
    msg("You've caught an illness!");
    cm[a].mood-=10;
    llim(&cm[a].mood,0);
    }
//  model background radiation - IE ageing
if (dice(10000) <= 3) 
    {
    msg("You suffer aging from background radiation!");
    cm[a].hp--;
    cm[a].mood-=10;
    llim(&cm[a].mood,0);
    if ( (cm[a].hp<1) || (cm[a].dmg>=cm[a].hp) )
        {
        msg("Background radiation (old age) killed you!");
        kill_bandmember(a);
        }
    }
//   model permanent shelter weathering
if ( cm[a].has_perm_shelter)
    {
    if (dice(10000) <= 6000)
        {
        cm[a].perm_shel_quality--;
        if (cm[a].perm_shel_quality < 1) 
            {
            cm[a].has_perm_shelter=0;
            msg("Your shelter has weathered away!");
            }
        }
    }
//  zero god relations
for (b=0; b<8; b++)
    {
    if (cm[a].god[b] > 0) cm[a].god[b]--;
    if (cm[a].god[b] < 0) cm[a].god[b]++;
    }
//   reduce social
cm[a].social-=5; 
llim(&cm[a].social,0);         // make social go down by 5 per day
//   model traps
for (b=0; b<maxtraps; b++)
    {
    if (!cm[a].trap[b].active) continue;
    cm[a].trap[b].age++;
    if (cm[a].trap[b].age>30)
        {
        cm[a].trap[b].active=0;
        continue;
        }
    switch(cm[a].trap[b].status)
        {
        case 0: c=dice(10000);
                if (c<=500) cm[a].trap[b].status=1; // caught animal
                else if (c<=1000) cm[a].trap[b].status=2;   // trap sprung, no animal caught
                break;
        case 1: cm[a].trap[b].daystrapped++;
                if (cm[a].trap[b].daystrapped > 5) cm[a].trap[b].status=2;   // trap sprung, no animal caught (rotted away)
                break;
        }
    }
//  model skill reduction
for (b=0; b<maxskilltypes; b++)
    {
    if (cm[a].xp[b] <1 ) continue;
    c=cm[a].xp[b];
    c/=100;
    if (c<1) continue;
    if (dice(10000) > 274) continue;  // works out to -1%, 10x / year on avg.
    cm[a].xp[b]-=c;
    }
}
 
 
 




compare that to BMupdate_each:




 
 

void BMupdate_each(int a)
{
//    do update stuff here - do global frame
BMdecrease_fatigue(a);
BMmodel_attack(a);
BMmodel_surprise(a);
BMmodel_full_fatigue(a);
run_bandmember(a);
BMmodel_raft_movement(a);
BMmodel_paddling_fatigue(a);
BMmodel_falling(a);
BMmodel_sneak_detection(a);
if (frame != 0)
    {
    return;
    }
//  do global second
BMmodel_fatigue_dueto_damage(a);
BMmodel_fatigue_dueto_encumbrance(a);
BMrun_quests(a);
BMclear_rockshelter_enccouter_flags(a);
BMcheck_rockshelter_encounters(a);
BMclear_cave_encounter_flags(a);
BMcheck_cave_encounters(a);
BMclear_hut_encouter_flags(a);
BMcheck_hut_encounters(a);
BMcheck_hut_takeover(a);
BMcheck_climbing_animals(a);
if (second != 0)
    {
    return;
    }
//    do global minute
BMcheck_animal_encounters(a);
BMcheck_caveman_encounters(a);
BMmodel_intox(a);
BMextinguish_torches(a);
if (minute%7 == 0)
    {
    BMreduce_hygiene_dueto_movement(a);
    }
if (minute%10 == 0)
    {
    BMreduce_water(a);
    BMreduce_sleep(a);
    }
if (minute%15 == 0)
    {
    BMreduce_food(a);
    BMaffect_mood(a);
    }
if (minute != 0)
    {
    return;
    }
//    do global hour
BMreduce_hygiene(a);
BMmodel_dehydration(a);
BMmodel_food_spoilage(a);
BMmodel_exposure(a);
BMmodel_heatstroke(a);
BMmodel_drown_in_flood(a);
BMmodel_wearNtear(a);
BMmodel_perm_shelter_raids(a);
BMmoodboost_nature_lover(a);
if (hour%2 == 0)
    {
    BMmodel_damage_dueto_illness(a);
    }
if (((hour>7)&&(hour<19)))
    {
    BMcheck_quest_encounters(a);
    }
if (hour != 0)
    {
    return;
    }
//    do global day
BMmodel_starvation(a);
BMmodel_getting_sick(a);
BMmodel_background_radiation(a);
BMmodel_perm_shel_weathering(a);
BMzero_god_relations(a);
BMreduce_social(a);
BMmodel_traps(a);
BMmodel_skill_reduction(a);
}
 
 
 




BMupdate_each seems much clearer to me.


Although i'm technically not optimizing here, while i have everything setup already i might as well put timers on the two update_each functions just for fun.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

BMupdate_each seems much clearer to me.


Although i'm technically not optimizing here, while i have everything setup already i might as well put timers on the two update_each functions just for fun.

Once ago I was writing some tile roguelike rpgs (eye1, eye2, eye3 - three big versions of this, not finished but improving ) and I can say my code was very like like yours, also a very big nice structures and a very big complicated stats and skills mechanics - also I discoveed the think you wrote that i

run many such mechanics in separate way like yours -

I consider the style of yr coding as a very fine (same way I write as I say) so I read it with nice, Its quite kool - Got not to much mood to get deeper into that you write (there is to much post on this forum and its harder to stop on something separate) but maybe i should becouse we are doing same things!

I'm... staggered... you go on and on about 'cache efficiency' and then post a struct like that.. that abomination... which is just going to utterly utterly screw the cache over as it's just so damned large...

And I'm willing to bet for most of your functions that data is 'cold' but being pulled in anyway.

Hell, just looking at the opening section of your 'update_each2' function, which I assume is functionally the same as the prefered 'update_each' function, makes me want to vomit.

You touch 'moved' which is over 200bytes into your structure (and 16 bytes away from the 'active' flag) and then check 'paddling' a further 172 bytes away, then go you BACK to 'current_action' which is 188 bytes behind the last touched data before using that to look up in ANOTHER array (which I assume is global so that'll probably cache miss too). At which point you go a further 20+ bytes back (without knowing the value of 'maxskilltypes' its hard to size 'xp' properly) to update that property.

Then you go on to touch 'attacking' which is 48+ bytes away again. To your credit 'attach_counter' is at least next to that one.The attack handling is probably the saner bit... when we get onto raft modeling and once again you at touching one section of the structure before wandering off to an unrelated bit to touch the 'x' and 'z' data before running the normalise function on data right at the start of the structure AND towards the end.

Paddling and falling suffers the same madness and about then I just gave up.

Frankly with this abomination NEVER EVER mention the words 'cache effiency' again because you are just playing a game of cache miss city with that setup; you data layout and access patterns are not REMOTELY sane and to even dream otherwise is just foolish.


I'm... staggered... you go on and on about 'cache efficiency' and then post a struct like that.. that abomination... which is just going to utterly utterly screw the cache over as it's just so damned large...

R.O.T.F.L.!!!!!!! no sh*t! <g>

that data structure is totally UN-optimized ! <g>

too big, poorly laid out. screams for a C-E system.

like you say, its way too big for the cache, data accesses jump all the heck all over.

that will most likely be addressed during the "quest for 900x accelerate time" optimizations.

right now, this "99 code changes" issue is more of a refactoring or re-design to simplify the code. but while refactoring the code, i do need to keep speed in mind as well as maintainability. thus the interest in cache friendly code (as opposed to cache friendly data).

despite its cache unfriendliness, its still plenty fast enough right now to run update at 450 Hz (fps) - fast enough for any normal shooter. but not fast enough for a vehicle sim that supports accelerated times on the order of 1024x - unless its one of those "go get a cup of coffee while you travel in accelerated time to your target" type vehicle sims.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

i ran timing tests on BMupdate_each (function calls) vs BMupdate_each2 (905 lines of code)

to get meaningful numbers i had to accumulate the elapsed time for BMupdate_all over 1 second.

times were about a wash, with the nod going to BMupdate_each (function calls) with perhaps 5% fewer ticks on average.

this actually makes sense. its doubtful that a 905 line function compiles to a pile of machine code small enough to be instruction cache friendly.

the function version most likely inlines the short stuff and does calls for the larger update routines.

if this were an academic exercise, i'd turn warning level 5 on, and do a build, and check the god-awful long output list of inlined functions to find out.

so i think i'm gong to go with the function version, more maintainable, and perhaps a tad faster too.

now i have to figure out what to do about all the loops in the checks

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

After collapsing all the update loops together, i'm still left with approximately 50 check loops.

I checked for possible C++ iterator constructs, but all were template based with RTT check code overhead, and therefore a slight performance hit. since the code only runs at ~450Hz currently, and the ideal target is an undoable ~13.5KHz, similar constructs without the RTToverhead would be preferable.

to that end, i took a cue from ApochPiQ, and created a generic foreach_aliveBM() iterator routine which takes a function as a parameter.

that turns code like this....

 
 
// reduce fatigue due to movement
int a
for (a=0; a<maxcavemen; a++)
     {
     if (! cm[a].active) continue;
     if (! cm[a].alive) continue;
     if (cm[a].moved)
          {
          cm[a].fatigue--;
          if (cm[a].speed==SPRINT) cm[a].fatigue-=2; else cm[a].fatigue--;
          }
    }
 

into something like this......

 
 
 
 
// reduce fatigue due to movement
void update_fatigue(int a)
{
if (cm[a].moved) 
    {
    cm[a].fatigue--;
    if (cm[a].speed==SPRINT) cm[a].fatigue-=2; else cm[a].fatigue--;
    }
}
 
 
 
foreach_aliveBM(update_fatigue);
 
 

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

here's the foreach generic iterator code....


 
typedef void functiontype2(int);
 
 

void foreach_aliveBM(functiontype2 *f)
{
int a;
for (a=0; a<num_bandmembers-1; a++)   if (cm[a].alive) f(a);
}
 
 
void foreach_activeBM(functiontype2 *f)
{
int a;
for (a=0; a<num_bandmembers-1; a++)  f(a);
}
 
 

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

post got clipped cliped again!

continuing form last post.....

and here's the new version of BMupdate_all that uses the foreach routine....

(still have to call move_rafts first... <g> )


 
 
//    must call move_rafts first!
void BMupdate_all()
{
foreach_aliveBM(BMupdate_each);
}
 
 

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

I'm just curious what the point of all this posting is. Are you asking for help with your (godawful spaghetti) code, or what? The running commentary here just seems sort of bizarre, and probably more suited for a journal or blog of some sort than the Game Programming forum.

This topic is closed to new replies.

Advertisement