hexen2/H2MP/hcode/stats.hc
2000-11-10 00:00:00 +00:00

671 lines
15 KiB
C++

/*
* $Header: /H2 Mission Pack/HCode/stats.hc 10 3/17/98 11:02a Mgummelt $
*/
// ExperienceValues for each level indicate the minimum at which
// you can become that level. The 11th entry indicates the amount
// of experience needed for each level past 10
float ExperienceValues[55] =
{
// Paladin
945, // Level 2
2240, // Level 3
5250, // Level 4
10150, // Level 5
21000, // Level 6
39900, // Level 7
72800, // Level 8
120400, // Level 9
154000, // Level 10
210000, // Level 11
210000, // Required amount for each level afterwards
// Crusader
911, // Level 2
2160, // Level 3
5062, // Level 4
9787, // Level 5
20250, // Level 6
38475, // Level 7
70200, // Level 8
116100, // Level 9
148500, // Level 10
202500, // Level 11
202500, // Required amount for each level afterwards
// Necromancer
823, // Level 2
1952, // Level 3
4575, // Level 4
8845, // Level 5
18300, // Level 6
34770, // Level 7
63440, // Level 8
104920, // Level 9
134200, // Level 10
183000, // Level 11
183000, // Required amount for each level afterwards
// Assassin
675, // Level 2
1600, // Level 3
3750, // Level 4
7250, // Level 5
15000, // Level 6
28500, // Level 7
52000, // Level 8
86000, // Level 9
110000, // Level 10
150000, // Level 11
150000, // Required amount for each level afterwards
// Succubus
871, // Level 2
2060, // Level 3
4822, // Level 4
9319, // Level 5
19278, // Level 6
36626, // Level 7
66804, // Level 8
110494, // Level 9
141334, // Level 10
192700, // Level 11
192700 // Required amount for each level afterwards
};
// min health, max health,
// min health per level up to level 10, min health per level up to level 10,
// health per level past level 10
float hitpoint_table[25] =
{
70, 85, // Paladin
8, 13, 4,
65, 75, // Crusader
5, 10, 3,
65, 75, // Necromancer
5, 10, 3,
65, 75, // Assassin
5, 10, 3,
65, 75, // Succubus
5, 10, 3
};
float mana_table[25] =
{
// Startup Per Level Past
// min max min max 10th Level
84, 94, 6, 9, 1, // Paladin
88, 98, 7, 10, 2, // Crusader
96, 106, 10, 12, 4, // Necromancer
92, 102, 9, 11, 3, // Assassin
90, 100, 8, 11, 3 // Succubus
};
float strength_table[10] =
{
15, 18, // Paladin
12, 15, // Crusader
6, 10, // Necromancer
10, 13, // Assassin
11, 14 // Succubus
};
float intelligence_table[10] =
{
6, 10, // Paladin
10, 13, // Crusader
15, 18, // Necromancer
6, 10, // Assassin
9, 13 // Succubus
};
float wisdom_table[10] =
{
6, 10, // Paladin
15, 18, // Crusader
10, 13, // Necromancer
12, 15, // Assassin
11, 14 // Succubus
};
float dexterity_table[10] =
{
10, 13, // Paladin
6, 10, // Crusader
8, 12, // Necromancer
15, 18, // Assassin
9, 13 // Succubus
};
/*
float CLASS_PALADIN = 1;
float CLASS_CRUSADER = 2;
float CLASS_NECROMANCER = 3;
float CLASS_ASSASSIN = 4;
float CLASS_SUCCUBUS = 5;
*/
// Make sure we get a real distribution beteen
// min-max, otherwise, max will only get choosen when
// random() returns 1.0
float stats_compute(float min, float max)
{
float value;
value = (max-min+1)*random() + min;
if (value > max) value = max;
value = ceil(value);
return value;
}
void stats_NewPlayer(entity e)
{
float index;
// Stats already set?
if (e.strength) return;
if (e.playerclass < CLASS_PALADIN || e.playerclass > CLASS_SUCCUBUS)
{
sprint(e,"Invalid player class ");
sprint(e,ftos(e.playerclass));
sprint(e,"\n");
return;
}
// Calc initial health
index = (e.playerclass - 1) * 5;
e.health = stats_compute(hitpoint_table[index],
hitpoint_table[index+1]);
e.max_health = e.health;
// Calc initial mana
index = (e.playerclass - 1) * 5;
e.max_mana = stats_compute(mana_table[index],
mana_table[index+1]);
index = (e.playerclass - 1) * 2;
e.strength = stats_compute(strength_table[index],
strength_table[index+1]);
e.intelligence = stats_compute(intelligence_table[index],
intelligence_table[index+1]);
e.wisdom = stats_compute(wisdom_table[index],
wisdom_table[index+1]);
e.dexterity = stats_compute(dexterity_table[index],
dexterity_table[index+1]);
e.level = 1;
e.experience = 0;
}
// Jump ahead one level
void player_level_cheat()
{
float index;
index = (self.playerclass - 1) * (MAX_LEVELS+1);
if (self.level > MAX_LEVELS)
index += MAX_LEVELS - 1;
else
index += self.level - 1;
self.experience = ExperienceValues[index];
if (self.level > MAX_LEVELS)
self.experience += (self.level - MAX_LEVELS) * ExperienceValues[index+1];
PlayerAdvanceLevel(self.level+1);
}
void player_experience_cheat(void)
{
AwardExperience(self,self,350);
}
/*
================
PlayerAdvanceLevel
This routine is called (from the game C side) when a player is advanced a level
(self.level)
================
*/
void PlayerAdvanceLevel(float NewLevel)
{
string s2;
float OldLevel,Diff;
float index,HealthInc,ManaInc;
sound (self, CHAN_VOICE, "misc/comm.wav", 1, ATTN_NONE);
OldLevel = self.level;
self.level = NewLevel;
Diff = self.level - OldLevel;
sprint(self,"You are now level ");
s2 = ftos(self.level);
sprint(self,s2);
sprint(self,"!\n");
if(!self.newclass)
{
switch (self.playerclass)
{
case CLASS_PALADIN:
centerprint(self, "Paladin gained a level\n");
break;
case CLASS_CRUSADER:
centerprint(self,"Crusader gained a level\n");
// Special ability #1, full mana at level advancement
self.bluemana = self.greenmana = self.max_mana;
break;
case CLASS_NECROMANCER:
centerprint(self,"Necromancer gained a level\n");
break;
case CLASS_ASSASSIN:
centerprint(self,"Assassin gained a level\n");
break;
case CLASS_SUCCUBUS:
centerprint(self,"Demoness gained a level\n");
break;
}
}
if (self.playerclass < CLASS_PALADIN ||
self.playerclass > CLASS_SUCCUBUS)
return;
index = (self.playerclass - 1) * 5;
// Have to do it this way in case they go up more than 1 level at a time
while(Diff > 0)
{
OldLevel += 1;
Diff -= 1;
if (OldLevel <= MAX_LEVELS)
{
HealthInc = stats_compute(hitpoint_table[index+2],hitpoint_table[index+3]);
ManaInc = stats_compute(mana_table[index+2],mana_table[index+3]);
}
else
{
HealthInc = hitpoint_table[index+4];
ManaInc = mana_table[index+4];
}
self.health += HealthInc;
self.max_health += HealthInc;
// An upper limit of 150 on health
if (self.health > 150)
self.health = 150;
if (self.max_health > 150)
self.max_health = 150;
self.greenmana += ManaInc;
self.bluemana += ManaInc;
self.max_mana += ManaInc;
sprint(self, "Stats: MP +");
s2 = ftos(ManaInc);
sprint(self, s2);
sprint(self, " HP +");
s2 = ftos(HealthInc);
sprint(self, s2);
sprint(self, "\n");
}
if (self.level > 2)
self.flags(+)FL_SPECIAL_ABILITY1;
if (self.level >5)
self.flags(+)FL_SPECIAL_ABILITY2;
}
float FindLevel(entity WhichPlayer)
{
float Chart;
float Amount,Position,Level;
if (WhichPlayer.playerclass < CLASS_PALADIN ||
WhichPlayer.playerclass > CLASS_SUCCUBUS)
return WhichPlayer.level;
Chart = (WhichPlayer.playerclass - 1) * (MAX_LEVELS+1);
Level = 0;
Position=0;
while(Position < MAX_LEVELS && Level == 0)
{
if (WhichPlayer.experience < ExperienceValues[Chart+Position])
Level = Position+1;
Position += 1;
}
if (!Level)
{
Amount = WhichPlayer.experience - ExperienceValues[Chart + MAX_LEVELS - 1];
Level = ceil(Amount / ExperienceValues[Chart + MAX_LEVELS]) + MAX_LEVELS;
}
return Level;
}
void AwardExperience(entity ToEnt, entity FromEnt, float Amount)
{
float AfterLevel;
float IsPlayer;
entity SaveSelf;
float index,test40,test80,diff,index2,totalnext,wis_mod;
if (!Amount) return;
if(ToEnt.deadflag>=DEAD_DYING)
return;
IsPlayer = (ToEnt.classname == "player");
if (FromEnt != world && Amount == 0.0)
{
Amount = FromEnt.experience_value;
}
if (ToEnt.level <4)
Amount *= .5;
if (ToEnt.playerclass == CLASS_PALADIN)
Amount *= 1.4;
else if (ToEnt.playerclass == CLASS_CRUSADER)
Amount *= 1.35;
else if (ToEnt.playerclass == CLASS_NECROMANCER)
Amount *= 1.22;
wis_mod = ToEnt.wisdom - 11;
Amount+=Amount*wis_mod/20;//from .75 to 1.35
ToEnt.experience += Amount;
if (IsPlayer)
{
AfterLevel = FindLevel(ToEnt);
// dprintf("Total Experience: %s\n",ToEnt.experience);
if (ToEnt.level != AfterLevel)
{
SaveSelf = self;
self = ToEnt;
PlayerAdvanceLevel(AfterLevel);
self = SaveSelf;
}
}
// Crusader Special Ability #1: award full health at 40% and 80% of levels experience
if (IsPlayer)
{
if (ToEnt.playerclass == CLASS_CRUSADER)
{
index = (ToEnt.playerclass - 1) * (MAX_LEVELS+1);
if ((ToEnt.level - 1) > MAX_LEVELS)
index += MAX_LEVELS;
else
index += ToEnt.level - 1;
if (ToEnt.level == 1)
{
test40 = ExperienceValues[index] * .4;
test80 = ExperienceValues[index] * .8;
}
else if ((ToEnt.level - 1) <= MAX_LEVELS)
{
index2 = index - 1;
diff = ExperienceValues[index] - ExperienceValues[index2];
test40 = ExperienceValues[index2] + (diff * .4);
test80 = ExperienceValues[index2] + (diff * .8);
}
else // Past MAX_LEVELS
{
totalnext = ExperienceValues[index - 1]; // index is 1 past MAXLEVEL at this point
totalnext += ((ToEnt.level - 1) - MAX_LEVELS) * ExperienceValues[index];
test40 = totalnext + (ExperienceValues[index] * .4);
test80 = totalnext + (ExperienceValues[index] * .8);
}
if (((ToEnt.experience - Amount) < test40) && (ToEnt.experience> test40))
ToEnt.health = ToEnt.max_health;
else if (((ToEnt.experience - Amount) < test80) && (ToEnt.experience> test80))
ToEnt.health = ToEnt.max_health;
}
}
}
/*
======================================
void stats_NewClass(entity e)
MG
Used when doing a quick changeclass
======================================
*/
void stats_NewClass(entity e)
{
entity oself;
float index,newlevel;
if (e.playerclass < CLASS_PALADIN || e.playerclass > CLASS_SUCCUBUS)
{
sprint(e,"Invalid player class ");
sprint(e,ftos(e.playerclass));
sprint(e,"\n");
return;
}
// Calc initial health
index = (e.playerclass - 1) * 5;
e.health = stats_compute(hitpoint_table[index],
hitpoint_table[index+1]);
e.max_health = e.health;
// Calc initial mana
index = (e.playerclass - 1) * 5;
e.max_mana = stats_compute(mana_table[index],
mana_table[index+1]);
index = (e.playerclass - 1) * 2;
e.strength = stats_compute(strength_table[index],
strength_table[index+1]);
e.intelligence = stats_compute(intelligence_table[index],
intelligence_table[index+1]);
e.wisdom = stats_compute(wisdom_table[index],
wisdom_table[index+1]);
e.dexterity = stats_compute(dexterity_table[index],
dexterity_table[index+1]);
//Add level diff stuff
newlevel = FindLevel(e);
e.level=1;
if(newlevel>1)
{
oself=self;
self=e;
PlayerAdvanceLevel(newlevel);
self=oself;
}
}
/*
======================================
drop_level
MG
Used in deathmatch where you don't
lose all exp, just enough to drop you
down one level.
======================================
*/
void drop_level (entity loser,float number)
{
float pos,lev_pos,new_exp,mana_dec,health_dec,dec_pos;
if(loser.classname!="player")
return;
if(loser.level-number<1)
{//would drop below level 1, set to level 1
loser.experience=0;
dec_pos = (loser.playerclass - 1) * 5;
loser.max_health= hitpoint_table[dec_pos];
loser.max_mana = mana_table[dec_pos];
if(loser.health>loser.max_health)
loser.health=loser.max_health;
if(loser.bluemana>loser.max_mana)
loser.bluemana=loser.max_mana;
if(loser.greenmana>loser.max_mana)
loser.greenmana=loser.max_mana;
return;
}
pos = (loser.playerclass - 1) * (MAX_LEVELS+1);
if(loser.level-number>1)
{
loser.level-=number;
lev_pos+=loser.level - 2;
if(lev_pos>9)//last number in that char's
{
new_exp=ExperienceValues[pos+10];
loser.experience=new_exp+new_exp*(lev_pos - 9);
}
else
loser.experience = ExperienceValues[pos+lev_pos];
}
else
{
loser.level=1;
loser.experience=0;
}
if (loser.level <= 2)
loser.flags(-)FL_SPECIAL_ABILITY1;
if (loser.level <=5)
loser.flags(-)FL_SPECIAL_ABILITY2;
dec_pos = (loser.playerclass - 1) * 5;
health_dec = hitpoint_table[dec_pos+4];
mana_dec = mana_table[dec_pos+4];
loser.max_health -= health_dec *number;
if(loser.health>loser.max_health)
loser.health=loser.max_health;
loser.max_mana -= mana_dec *number;
if(loser.bluemana>loser.max_mana)
loser.bluemana=loser.max_mana;
if(loser.greenmana>loser.max_mana)
loser.greenmana=loser.max_mana;
}
/*
* $Log: /H2 Mission Pack/HCode/stats.hc $
*
* 10 3/17/98 11:02a Mgummelt
*
* 9 3/16/98 6:21p Jweier
*
* 8 3/13/98 3:02a Mgummelt
*
* 7 3/12/98 11:06p Jmonroe
* change ifs to switch
*
* 6 2/24/98 6:39p Mgummelt
*
* 5 2/13/98 11:16a Jmonroe
* changed succubus to demoness
*
* 4 1/21/98 12:12p Jweier
* made level up more apparent
*
* 27 10/28/97 1:01p Mgummelt
* Massive replacement, rewrote entire code... just kidding. Added
* support for 5th class.
*
* 24 9/10/97 11:40p Mgummelt
*
* 23 9/10/97 7:51p Mgummelt
*
* 22 9/10/97 7:08p Mgummelt
*
* 21 9/03/97 7:49p Mgummelt
*
* 20 8/15/97 3:59p Rlove
*
* 19 8/11/97 4:35p Rlove
*
* 18 8/09/97 10:51a Rlove
*
* 17 7/26/97 8:39a Mgummelt
*
* 16 7/25/97 11:45a Mgummelt
*
* 15 7/25/97 11:12a Mgummelt
*
* 14 7/25/97 11:10a Mgummelt
*
* 13 7/14/97 2:29p Rlove
*
* 12 7/08/97 5:17p Rlove
*
* 11 7/03/97 10:07a Rlove
*
* 10 6/30/97 3:33p Rlove
*
* 9 6/30/97 9:41a Rlove
*
* 8 6/20/97 9:25a Rlove
*
* 7 6/20/97 9:12a Rlove
* New mana system added
*
* 6 6/06/97 2:52p Rlove
* Artifact of Super Health now functions properly
*
* 5 5/15/97 1:15p Rjohnson
* Added the appriate experience tables and hitpoint advancement for level
* gains
*
* 4 5/15/97 11:43a Rjohnson
* Stats updates
*
* 3 5/14/97 4:12p Rjohnson
* Minor fix from C-side conversion
*
* 2 5/14/97 3:36p Rjohnson
* Inital stats implementation
*
* 1 5/13/97 2:23p Rjohnson
* Initial Version
*/