From 1253b8c1ece3af78a35586ecd02f056a7b3cdd29 Mon Sep 17 00:00:00 2001
From: johns <>
Date: Mon, 16 Apr 2001 00:16:36 +0000
Subject: [PATCH] Upgrades now supports changing the unit-type of already build
 units.

---
 doc/ChangeLog.html            |   3 +-
 src/include/player.h          |  24 +-
 src/include/upgrade.h         |  45 ++--
 src/include/upgrade_structs.h | 116 +++++----
 src/unit/upgrade.cpp          | 469 +++++++++++++++++-----------------
 5 files changed, 343 insertions(+), 314 deletions(-)

diff --git a/doc/ChangeLog.html b/doc/ChangeLog.html
index 73378d700..53b0b8d38 100644
--- a/doc/ChangeLog.html
+++ b/doc/ChangeLog.html
@@ -600,7 +600,7 @@
     <LI>Spell death and decay handled now like original.
     <LI>Spell whirlwind now moves correct and did the correct damage on the
 	correct position.
-    <LI>Spell raise dead removes the corpse and works on djacent fields.
+    <LI>Spell raise dead removes the corpse and works on adjacent fields.
     <LI>Added decay of units, eye of k. and skeletons dies after some seconds.
     <LI>Spell blizzard handled more like the original.
     <LI>Spell runes works now correct.
@@ -608,6 +608,7 @@
 	(from Latimerius)
     <LI>Fixed bug: Spells hits unit without hitpoints, dumps core.
 	(from Latimerius)
+    <LI>Upgrades now supports changing the unit-type of already build units.
     <LI>+++
     </UL>
     </UL>
diff --git a/src/include/player.h b/src/include/player.h
index 4271e8724..78c190652 100644
--- a/src/include/player.h
+++ b/src/include/player.h
@@ -10,7 +10,7 @@
 //
 /**@name player.h	-	The player headerfile. */
 //
-//	(c) Copyright 1998-2000 by Lutz Sammer
+//	(c) Copyright 1998-2001 by Lutz Sammer
 //
 //	$Id$
 
@@ -19,6 +19,26 @@
 
 //@{
 
+/*----------------------------------------------------------------------------
+--	Documentation
+----------------------------------------------------------------------------*/
+
+/**
+**	@struct _player_ player.h
+**
+**	\#include "player.h"
+**
+**	typedef struct _player_ Player;
+**
+**	This structure contains all informations about a player in game.
+**
+**	The player structure members:
+**
+**	Player::Player
+**
+**	FIXME: not written documentation
+*/
+
 /*----------------------------------------------------------------------------
 --	Includes
 ----------------------------------------------------------------------------*/
@@ -98,7 +118,7 @@ struct _player_ {
 
 //  Upgrades/Allows:
     Allow		Allow;		/// Allowed for player
-    UpgradeTimers	UTimers;	/// Timer for the upgrades
+    UpgradeTimers	UpgradeTimers;	/// Timer for the upgrades
 };
 
 /*
diff --git a/src/include/upgrade.h b/src/include/upgrade.h
index 55826c575..a638ae121 100644
--- a/src/include/upgrade.h
+++ b/src/include/upgrade.h
@@ -9,11 +9,10 @@
 //	   FreeCraft - A free fantasy real time strategy game engine
 //
 /**@name upgrade.h	-	The upgrades headerfile. */
-/*
-**	(c) Copyright 1999,2000 by Vladi Belperchinov-Shabanski
-**
-**	$Id$
-*/
+//
+//	(c) Copyright 1999-2001 by Vladi Belperchinov-Shabanski
+//
+//	$Id$
 
 #ifndef __UPGRADE_H__
 #define __UPGRADE_H__
@@ -43,13 +42,18 @@ typedef struct _player_ Player;		// recursive includes :(
 --	Functions
 ----------------------------------------------------------------------------*/
 
-extern void InitUpgrades(void);		/// init upgrade/allow structures
-extern Upgrade* UpgradeByIdent(const char*); /// upgrade of identifier
-extern void SaveUpgrades(FILE*);	/// save the upgrades
-extern void ParsePudALOW(const char*,int); /// parse pud alow table
-extern void ParsePudUGRD(const char*,int); /// parse pud ugrd table
-extern void UpgradesCclRegister(void);	/// Register CCL features for upgrades
-
+    /// init upgrade/allow structures
+extern void InitUpgrades(void);
+     /// upgrade of identifier
+extern Upgrade* UpgradeByIdent(const char*);
+    /// save the upgrades
+extern void SaveUpgrades(FILE*);
+    /// parse pud alow (upgrade/spell/units allow) table
+extern void ParsePudALOW(const char*,int);
+    /// parse pud ugrd (upgrade cost) table
+extern void ParsePudUGRD(const char*,int);
+    /// Register CCL features for upgrades
+extern void UpgradesCclRegister(void);
 
 // CHAOS PUR
 
@@ -147,24 +151,23 @@ extern int ActionIdByIdent( const char* sid );
 --	Upgrades
 ----------------------------------------------------------------------------*/
 
-// amount==-1 to cancel upgrade, could happen when building destroyed during upgrade
-// using this we could have one upgrade research in two buildings, so we can have
-// this upgrade faster.
-void UpgradeIncTime( Player* player, int id, int amount );
-void UpgradeIncTime2( Player* player, char* sid, int amount ); // by ident string
+    /// Upgrade will be acquired, called by UpgradeIncTime() when timer reached
+extern void UpgradeAcquire( Player* player,const Upgrade* upgrade );
+
+    /// Increment the upgrade timer.
+extern void UpgradeIncTime( Player* player, int id, int amount );
+extern void UpgradeIncTime2( Player* player, char* sid, int amount ); // by ident string
 
 // this function will mark upgrade done and do all required modifications to
 // unit types and will modify allow/forbid maps
 
-    // called by UpgradeIncTime() when timer reached
-void UpgradeAcquire( Player* player,Upgrade* upgrade );
 
 // for now it will be empty?
 // perhaps acquired upgrade can be lost if ( for example ) a building is lost
 // ( lumber mill? stronghold? )
 // this function will apply all modifiers in reverse way
-void UpgradeLost( Player* player, int id );
-void UpgradeLost2( Player* player, char* sid ); // by ident string
+extern void UpgradeLost( Player* player, int id );
+extern void UpgradeLost2( Player* player, char* sid ); // by ident string
 
 /*----------------------------------------------------------------------------
 --	Allow(s)
diff --git a/src/include/upgrade_structs.h b/src/include/upgrade_structs.h
index 9b7c9dae2..f409cf381 100644
--- a/src/include/upgrade_structs.h
+++ b/src/include/upgrade_structs.h
@@ -39,8 +39,6 @@
 #define MAXUNITTYPES	MAXUACOUNT
     /// max upgrades count
 #define MAXUPGRADES	MAXUACOUNT
-    /// max actions count
-#define MAXACTIONS	MAXUACOUNT // include spells
 
 /*----------------------------------------------------------------------------
 --	Declarations
@@ -120,6 +118,51 @@ typedef struct _upgrade_ {
     IconConfig	Icon;			/// icon to display to the user
 } Upgrade;
 
+/*----------------------------------------------------------------------------
+--	upgrades and modifiers
+----------------------------------------------------------------------------*/
+
+/**
+**	Modifiers of the unit stats.
+**	All the following are modifiers not values!
+**	@see UnitStats
+*/
+typedef struct _modifiers_ {
+    int	AttackRange;			/// attack range modifier
+    int	SightRange;			/// sight range modifier
+    int	BasicDamage;			/// basic damage modifier
+    int	PiercingDamage;			/// piercing damage modifier
+    int	Armor;				/// armor modifier
+    int	Speed;				/// speed modifier (FIXME: not working)
+    int	HitPoints;			/// hit points modifier
+
+    int	Costs[MaxCosts];		/// costs modifier
+} Modifiers;
+
+/**
+**	This is the modifier of an upgrade.
+**	This do the real action of an upgrade, an upgrade can have multiple
+**	modifiers.
+*/
+typedef struct _upgrade_modifier_ {
+
+  int		UpgradeId;		/// used to filter required modifier
+
+  Modifiers	Modifier;		/// modifier of unit stats
+
+  // allow/forbid bitmaps -- used as chars for example:
+  // `?' -- leave as is, `F' -- forbid, `A' -- allow
+  // FIXME: see below allow more semantics?
+  // FIXME: pointers or ids would be faster and less memory use
+  char	ChangeUnits[MAXUNITTYPES];	/// allow/forbid units
+  char	ChangeUpgrades[MAXUPGRADES];	/// allow/forbid upgrades
+  char	ApplyTo[MAXUNITTYPES];		/// which unit types are affected
+
+  // FIXME: UnitType*
+  void*		ConvertTo;		/// convert to this unit-type.
+
+} UpgradeModifier;
+
 /**
 **	Allow what a player can do. Every player has an own Allow struct.
 **
@@ -134,10 +177,23 @@ typedef struct _upgrade_ {
 */
 typedef struct _allow_ {
     char	Units[MAXUNITTYPES];	/// Units allowed/disallowed
-	// FIXME: Actions isn't used yet.
-    //char	Actions[MAXACTIONS];	/// Actions allowed/disallowed
     char	Upgrades[MAXUPGRADES];	/// Upgrades allowed/disallowed
 } Allow;
+
+/**
+**	Upgrade timer used in the player structure.
+**	Every player has an own UpgradeTimers struct.
+*/
+typedef struct _upgrade_timers_ {
+
+    /**
+    **	all 0 at the beginning, all upgrade actions do increment values in
+    **	this struct.
+    */
+    int	Upgrades[MAXUPGRADES];		/// Counter for each upgrade
+
+} UpgradeTimers;
+
 /*----------------------------------------------------------------------------
 --	Variables
 ----------------------------------------------------------------------------*/
@@ -145,58 +201,6 @@ typedef struct _allow_ {
 extern const char UpgradeType[];	/// upgrade type
 extern Upgrade Upgrades[MAXUACOUNT];	/// The main user useable upgrades
 
-
-
-
-//Cleaning this
-//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-
-/*----------------------------------------------------------------------------
---	upgrades and modifiers
-----------------------------------------------------------------------------*/
-
-typedef struct _modifiers_ {
-  // all the following are modifiers not values!
-  int	AttackRange;			/// attack range modifier
-  int	SightRange;			/// sight range modifier
-  int	BasicDamage;			/// basic damage modifier
-  int	PiercingDamage;			/// piercing damage modifier
-  int	Armor;				/// armor modifier
-  int	Speed;				/// speed modifier (FIXME: not working)
-  int	HitPoints;			/// hit points modifier
-
-  int	Costs[MaxCosts];		/// costs modifier
-} Modifiers;
-
-typedef struct _upgrade_modifier_ {
-
-  int	uid; // used to filter required by upgrade modifiers
-
-  Modifiers mods;
-
-  // allow/forbid bitmaps -- used as chars for example:
-  // `?' -- leave as is, `F' -- forbid, `A' -- allow
-  // FIXME: pointers or ids would be faster and less memory use
-  char af_units[MAXUNITTYPES];   // allow/forbid units
-  //char af_actions[MAXACTIONS]; // allow/forbid actions
-  char af_upgrades[MAXUPGRADES]; // allow/forbid upgrades
-  char apply_to[MAXUNITTYPES]; // which unit types are affected
-
-} UpgradeModifier;
-
-typedef struct _upgrade_timers_ {
-
-  // all 0 at the beginning, all upgrade actions do increment values in
-  // this struct, every player has own UpgradeTimers struct
-  int upgrades[MAXUPGRADES];
-
-} UpgradeTimers;
-
-
 //@}
 
 #endif // !__UPGRADE_STRUCTS_H__
diff --git a/src/unit/upgrade.cpp b/src/unit/upgrade.cpp
index a1b6af418..67f7d9d00 100644
--- a/src/unit/upgrade.cpp
+++ b/src/unit/upgrade.cpp
@@ -35,9 +35,9 @@
 #include "etlib/hash.h"
 
 local int AddUpgradeModifierBase(int,int,int,int,int,int,int,int,int*,
-	const char*,const char*,const char*,const char*);
+	const char*,const char*,const char*,UnitType*);
 local int AddUpgradeModifier(int,int,int,int,int,int,int,int,int*,
-	const char*,const char*,const char*,const char*);
+	const char*,const char*,const char*);
 
 /*----------------------------------------------------------------------------
 --	Variables
@@ -83,6 +83,8 @@ local struct _wc_upgrades_ {
     int		CostsModifier[MaxCosts];/// costs modifier
 
     const char*	Units;			/// units affected
+
+    const char*	ConvertTo;		/// convert to this unit
 } WcUpgrades[] = {
 //			Name			Icon
 //  Time  Gold Wood  Oil         At Si BD PD Ar Sp HP  Time Gold Wood  Oil
@@ -387,10 +389,6 @@ local void SetupAllow(void)
 		    ,sizeof(Players[z].Allow.Upgrades));
 	    memset(Players[z].Allow.Units,'A'
 		    ,sizeof(Players[z].Allow.Units));
-#if 0
-	    memset(Players[z].Allow.Actions,'A'
-		    ,sizeof(Players[z].Allow.Actions));
-#endif
 	}
 
 	// Give some upgrades as default.
@@ -836,69 +834,74 @@ global void SaveUpgrades(FILE* file)
     //
     for( i=0; i<UpgradeModifiersCount; ++i ) {
 	fprintf(file,"(define-modifier '%s",
-		Upgrades[UpgradeModifiers[i]->uid].Ident);
+		Upgrades[UpgradeModifiers[i]->UpgradeId].Ident);
 
-	if( UpgradeModifiers[i]->mods.AttackRange ) {
+	if( UpgradeModifiers[i]->Modifier.AttackRange ) {
 	    fprintf(file,"\n  '(attack-range %d)"
-		    ,UpgradeModifiers[i]->mods.AttackRange );
+		    ,UpgradeModifiers[i]->Modifier.AttackRange );
 	}
-	if( UpgradeModifiers[i]->mods.SightRange ) {
+	if( UpgradeModifiers[i]->Modifier.SightRange ) {
 	    fprintf(file,"\n  '(sight-range %d)"
-		    ,UpgradeModifiers[i]->mods.SightRange );
+		    ,UpgradeModifiers[i]->Modifier.SightRange );
 	}
-	if( UpgradeModifiers[i]->mods.SightRange ) {
+	if( UpgradeModifiers[i]->Modifier.SightRange ) {
 	    fprintf(file,"\n  '(attack-range %d)"
-		    ,UpgradeModifiers[i]->mods.SightRange );
+		    ,UpgradeModifiers[i]->Modifier.SightRange );
 	}
-	if( UpgradeModifiers[i]->mods.BasicDamage ) {
+	if( UpgradeModifiers[i]->Modifier.BasicDamage ) {
 	    fprintf(file,"\n  '(basic-damage %d)"
-		    ,UpgradeModifiers[i]->mods.BasicDamage );
+		    ,UpgradeModifiers[i]->Modifier.BasicDamage );
 	}
-	if( UpgradeModifiers[i]->mods.PiercingDamage ) {
+	if( UpgradeModifiers[i]->Modifier.PiercingDamage ) {
 	    fprintf(file,"\n  '(piercing-damage %d)"
-		    ,UpgradeModifiers[i]->mods.PiercingDamage );
+		    ,UpgradeModifiers[i]->Modifier.PiercingDamage );
 	}
-	if( UpgradeModifiers[i]->mods.Armor ) {
+	if( UpgradeModifiers[i]->Modifier.Armor ) {
 	    fprintf(file,"\n  '(armor %d)"
-		    ,UpgradeModifiers[i]->mods.Armor );
+		    ,UpgradeModifiers[i]->Modifier.Armor );
 	}
-	if( UpgradeModifiers[i]->mods.Speed ) {
+	if( UpgradeModifiers[i]->Modifier.Speed ) {
 	    fprintf(file,"\n  '(speed %d)"
-		    ,UpgradeModifiers[i]->mods.Speed );
+		    ,UpgradeModifiers[i]->Modifier.Speed );
 	}
-	if( UpgradeModifiers[i]->mods.HitPoints ) {
+	if( UpgradeModifiers[i]->Modifier.HitPoints ) {
 	    fprintf(file,"\n  '(hit-points %d)"
-		    ,UpgradeModifiers[i]->mods.HitPoints );
+		    ,UpgradeModifiers[i]->Modifier.HitPoints );
 	}
 
 	for( j=0; j<MaxCosts; ++j ) {
-	    if( UpgradeModifiers[i]->mods.Costs[j] ) {
+	    if( UpgradeModifiers[i]->Modifier.Costs[j] ) {
 		fprintf(file,"\n  '(%s-cost %d)"
-			,DEFAULT_NAMES[j],UpgradeModifiers[i]->mods.Costs[j]);
+			,DEFAULT_NAMES[j],UpgradeModifiers[i]->Modifier.Costs[j]);
 	    }
 	}
 
 	for( j=0; j<MAXUNITTYPES; ++j ) {	// allow/forbid units
-	    if( UpgradeModifiers[i]->af_units[j]!='?' ) {
+	    if( UpgradeModifiers[i]->ChangeUnits[j]!='?' ) {
 		fprintf(file,"\n  '(allow %s %d)",
 			UnitTypes[j].Ident,
-			UpgradeModifiers[i]->af_units[j]);
+			UpgradeModifiers[i]->ChangeUnits[j]);
 	    }
 	}
 
 	for( j=0; j<MAXUPGRADES; ++j ) {	// allow/forbid upgrades
-	    if( UpgradeModifiers[i]->af_upgrades[j]!='?' ) {
+	    if( UpgradeModifiers[i]->ChangeUpgrades[j]!='?' ) {
 		fprintf(file,"\n  '(allow %s %c)",Upgrades[j].Ident,
-			UpgradeModifiers[i]->af_upgrades[j]);
+			UpgradeModifiers[i]->ChangeUpgrades[j]);
 	    }
 	}
 
 	for( j=0; j<MAXUNITTYPES; ++j ) {	// apply to units
-	    if( UpgradeModifiers[i]->apply_to[j]!='?' ) {
+	    if( UpgradeModifiers[i]->ApplyTo[j]!='?' ) {
 		fprintf(file,"\n  '(apply-to %s)",UnitTypes[j].Ident);
 	    }
 	}
 
+	if( UpgradeModifiers[i]->ConvertTo ) {
+	    fprintf(file,"\n  '(convert-to %s)",
+		    ((UnitType*)UpgradeModifiers[i]->ConvertTo)->Ident);
+	}
+
 	fprintf(file,")\n\n");
     }
 
@@ -973,6 +976,7 @@ local SCM CclDefineModifier(SCM list)
     char units[MAXUNITTYPES];
     char upgrades[MAXUPGRADES];
     char apply_to[MAXUNITTYPES];
+    UnitType* convert_to;
 
     attack_range=0;
     sight_range=0;
@@ -985,6 +989,7 @@ local SCM CclDefineModifier(SCM list)
     memset(units,'?',sizeof(units));
     memset(upgrades,'?',sizeof(upgrades));
     memset(apply_to,'?',sizeof(apply_to));
+    convert_to=NULL;
 
     value=gh_car(list);
     list=gh_cdr(list);
@@ -1050,6 +1055,11 @@ local SCM CclDefineModifier(SCM list)
 	    str=gh_scm2newstr(gh_car(value),NULL);
 	    apply_to[UnitTypeIdByIdent(str)]='X';
 	    free(str);
+	} else if( gh_eq_p(temp,gh_symbol2scm("convert-to")) ) {
+	    value=gh_cdr(value);
+	    str=gh_scm2newstr(gh_car(value),NULL);
+	    convert_to=UnitTypeByIdent(str);
+	    free(str);
 	} else {
 	    errl("wrong tag",temp);
 	    return SCM_UNSPECIFIED;
@@ -1058,7 +1068,7 @@ local SCM CclDefineModifier(SCM list)
 
     AddUpgradeModifierBase(uid,attack_range,sight_range,
 	    basic_damage,piercing_damage,armor,speed,hit_points,costs,
-	    units,NULL,upgrades,apply_to);
+	    units,upgrades,apply_to,convert_to);
 
     return SCM_UNSPECIFIED;
 }
@@ -1262,10 +1272,10 @@ void UpgradesDone(void) // free upgrade/allow structures
 #endif
 
 // returns upgrade modifier id or -1 for error ( actually this id is useless, just error checking )
-local int AddUpgradeModifierBase(int aUid,int aattack_range,int asight_range,
-    int abasic_damage,int apiercing_damage,int aarmor,int aspeed,
-    int ahit_points,int* acosts,const char* aaf_units,const char* aaf_actions,
-    const char* aaf_upgrades,const char* aapply_to)
+local int AddUpgradeModifierBase(int uid,int attack_range,int sight_range,
+    int basic_damage,int piercing_damage,int armor,int speed,
+    int hit_points,int* costs,const char* af_units,
+    const char* af_upgrades,const char* apply_to,UnitType* convert_to)
 {
     int i;
     UpgradeModifier *um;
@@ -1275,27 +1285,26 @@ local int AddUpgradeModifierBase(int aUid,int aattack_range,int asight_range,
 	return -1;
     }
 
-    um->uid = aUid;
+    um->UpgradeId = uid;
 
     // get/save stats modifiers
-    um->mods.AttackRange	= aattack_range;
-    um->mods.SightRange		= asight_range;
-    um->mods.BasicDamage	= abasic_damage;
-    um->mods.PiercingDamage	= apiercing_damage;
-    um->mods.Armor		= aarmor;
-    um->mods.Speed		= aspeed;
-    um->mods.HitPoints		= ahit_points;
+    um->Modifier.AttackRange	= attack_range;
+    um->Modifier.SightRange	= sight_range;
+    um->Modifier.BasicDamage	= basic_damage;
+    um->Modifier.PiercingDamage	= piercing_damage;
+    um->Modifier.Armor		= armor;
+    um->Modifier.Speed		= speed;
+    um->Modifier.HitPoints	= hit_points;
 
     for( i=0; i<MaxCosts; ++i ) {
-	um->mods.Costs[i]	= acosts[i];
+	um->Modifier.Costs[i]	= costs[i];
     }
 
-    memcpy(um->af_units,aaf_units,sizeof(um->af_units));
-#if 0
-    memcpy(um->af_actions,aaf_actions,sizeof(um->af_actions));
-#endif
-    memcpy(um->af_upgrades,aaf_upgrades,sizeof(um->af_upgrades));
-    memcpy(um->apply_to,aapply_to,sizeof(um->apply_to));
+    memcpy(um->ChangeUnits,af_units,sizeof(um->ChangeUnits));
+    memcpy(um->ChangeUpgrades,af_upgrades,sizeof(um->ChangeUpgrades));
+    memcpy(um->ApplyTo,apply_to,sizeof(um->ApplyTo));
+
+    um->ConvertTo=convert_to;
 
     UpgradeModifiers[UpgradeModifiersCount] = um;
 
@@ -1304,23 +1313,22 @@ local int AddUpgradeModifierBase(int aUid,int aattack_range,int asight_range,
 
 
 // returns upgrade modifier id or -1 for error ( actually this id is useless, just error checking )
-local int AddUpgradeModifier( int aUid,
-    int aattack_range,
-    int asight_range,
-    int abasic_damage,
-    int apiercing_damage,
-    int aarmor,
-    int aspeed,
-    int ahit_points,
+local int AddUpgradeModifier( int uid,
+    int attack_range,
+    int sight_range,
+    int basic_damage,
+    int piercing_damage,
+    int armor,
+    int speed,
+    int hit_points,
 
-    int* acosts,
+    int* costs,
 
     // following are comma separated list of required string id's
 
-    const char* aaf_units,    // "A:unit-mage,F:unit-grunt" -- allow mages, forbid grunts
-    const char* aaf_actions,  // "A:PeonAttack"
-    const char* aaf_upgrades, // "F:upgrade-Shield1,R:upgrade-ShieldTotal" -- :)
-    const char* aapply_to	    // "unit-Peon,unit-Peasant"
+    const char* af_units,    // "A:unit-mage,F:unit-grunt" -- allow mages, forbid grunts
+    const char* af_upgrades, // "F:upgrade-Shield1,R:upgrade-ShieldTotal" -- :)
+    const char* apply_to	    // "unit-Peon,unit-Peasant"
 
     )
 {
@@ -1334,36 +1342,33 @@ local int AddUpgradeModifier( int aUid,
 	return -1;
     }
 
-    um->uid = aUid;
+    um->UpgradeId = uid;
 
     // get/save stats modifiers
-    um->mods.AttackRange	= aattack_range;
-    um->mods.SightRange		= asight_range;
-    um->mods.BasicDamage	= abasic_damage;
-    um->mods.PiercingDamage	= apiercing_damage;
-    um->mods.Armor		= aarmor;
-    um->mods.Speed		= aspeed;
-    um->mods.HitPoints		= ahit_points;
+    um->Modifier.AttackRange	= attack_range;
+    um->Modifier.SightRange	= sight_range;
+    um->Modifier.BasicDamage	= basic_damage;
+    um->Modifier.PiercingDamage	= piercing_damage;
+    um->Modifier.Armor		= armor;
+    um->Modifier.Speed		= speed;
+    um->Modifier.HitPoints	= hit_points;
 
     for( i=0; i<MaxCosts; ++i ) {
-	um->mods.Costs[i]	= acosts[i];
+	um->Modifier.Costs[i]	= costs[i];
     }
 
     // FIXME: all the thing below is sensitive to the format of the string!
     // FIXME: it will be good if things are checked for errors better!
     // FIXME: perhaps the function `strtok()' should be replaced with local one?
 
-    memset( um->af_units,    '?', sizeof(um->af_units)    );
-#if 0
-    memset( um->af_actions,  '?', sizeof(um->af_actions)  );
-#endif
-    memset( um->af_upgrades, '?', sizeof(um->af_upgrades) );
-    memset( um->apply_to,    '?', sizeof(um->apply_to)    );
+    memset( um->ChangeUnits,    '?', sizeof(um->ChangeUnits)   );
+    memset( um->ChangeUpgrades, '?', sizeof(um->ChangeUpgrades));
+    memset( um->ApplyTo,     '?', sizeof(um->ApplyTo)    );
 
     //
     // get allow/forbid's for units
     //
-    s1 = strdup( aaf_units );
+    s1 = strdup( af_units );
     DebugCheck(!s1);
     for( s2 = strtok( s1, "," ); s2; s2=strtok( NULL, "," ) ) {
 	int id;
@@ -1373,33 +1378,14 @@ local int AddUpgradeModifier( int aUid,
 	if ( id == -1 ) {
 	    continue;		// should we cancel all and return error?!
 	}
-	um->af_units[id] = s2[0];
+	um->ChangeUnits[id] = s2[0];
     }
     free(s1);
 
-    //
-    // get allow/forbid's for actions
-    //
-#if 0
-    s1 = strdup( aaf_actions );
-    DebugCheck(!s1);
-    for( s2 = strtok( s1, "," ); s2; s2=strtok( NULL, "," ) ) {
-	int id;
-	DebugCheck(!( s2[0] == 'A' || s2[0] == 'F' ));
-	DebugCheck(!( s2[1] == ':' ));
-	id = ActionIdByIdent( s2+2 );
-	if ( id == -1 ) {
-	    continue;		// should we cancel all and return error?!
-	}
-	um->af_actions[id] = s2[0];
-    }
-    free(s1);
-#endif
-
     //
     // get allow/forbid's for upgrades
     //
-    s1 = strdup( aaf_upgrades );
+    s1 = strdup( af_upgrades );
     DebugCheck(!s1);
     for( s2 = strtok( s1, "," ); s2; s2=strtok( NULL, "," ) ) {
 	int id;
@@ -1409,14 +1395,14 @@ local int AddUpgradeModifier( int aUid,
 	if ( id == -1 ) {
 	    continue;		// should we cancel all and return error?!
 	}
-	um->af_upgrades[id] = s2[0];
+	um->ChangeUpgrades[id] = s2[0];
     }
     free(s1);
 
     //
     // get units that are affected by this upgrade
     //
-    s1 = strdup( aapply_to );
+    s1 = strdup( apply_to );
     DebugCheck(!s1);
     for( s2 = strtok( s1, "," ); s2; s2=strtok( NULL, "," ) ) {
 	int id;
@@ -1426,7 +1412,7 @@ local int AddUpgradeModifier( int aUid,
 	if ( id == -1 ) {
 	    break;		// cade: should we cancel all and return error?!
 	}
-	um->apply_to[id] = 'X'; // something other than '?'
+	um->ApplyTo[id] = 'X'; // something other than '?'
     }
     free(s1);
 
@@ -1438,35 +1424,35 @@ local int AddUpgradeModifier( int aUid,
 
 // this function is used for define `simple' upgrades
 // with only one modifier
-global void AddSimpleUpgrade( const char* aIdent,
-    const char* aIcon,
+global void AddSimpleUpgrade( const char* ident,
+    const char* icon,
     // upgrade costs
-    int* aCosts,
+    int* costs,
     // upgrade modifiers
-    int aattack_range,
-    int asight_range,
-    int abasic_damage,
-    int apiercing_damage,
-    int aarmor,
-    int aspeed,
-    int ahit_points,
+    int attack_range,
+    int sight_range,
+    int basic_damage,
+    int piercing_damage,
+    int armor,
+    int speed,
+    int hit_points,
 
     int* mcosts,
 
-    const char* aapply_to		// "unit-Peon,unit-Peasant"
+    const char* apply_to		// "unit-Peon,unit-Peasant"
     )
 {
     Upgrade* up;
 
-    up = AddUpgrade(aIdent,aIcon,aCosts);
+    up = AddUpgrade(ident,icon,costs);
     if ( !up )  {
 	return;
     }
-    AddUpgradeModifier(up-Upgrades,aattack_range,asight_range,abasic_damage,
-	    apiercing_damage,aarmor,aspeed,ahit_points,
+    AddUpgradeModifier(up-Upgrades,attack_range,sight_range,basic_damage,
+	    piercing_damage,armor,speed,hit_points,
 	    mcosts,
-	    "","","", // no allow/forbid maps
-	    aapply_to);
+	    "","", // no allow/forbid maps
+	    apply_to);
 }
 
 /*----------------------------------------------------------------------------
@@ -1511,99 +1497,142 @@ global int UpgradeIdByIdent(const char* sid)
     return -1;
 }
 
-#if 0
-// FIXME: Docu
-global int ActionIdByIdent( const char* sid )
-{
-  // FIXME: there's no actions table yet
-  DebugLevel0Fn(" fix this %s\n",sid);
-  return -1;
-}
-#endif
-
 /*----------------------------------------------------------------------------
 --	Upgrades
 ----------------------------------------------------------------------------*/
 
-// amount==-1 to cancel upgrade, could happen when building destroyed during upgrade
-// using this we could have one upgrade research in two buildings, so we can have
-// this upgrade faster.
-global void UpgradeIncTime( Player* player, int id, int amount )
+/**
+**	Increment the counter of an upgrade.
+**
+**	Amount==-1 to cancel upgrade, could happen when building destroyed
+**	during upgrade. Using this we could have one upgrade research in two
+**	buildings, so we can have this upgrade faster.
+**
+**	@param player	Player pointer of the incremented upgrade.
+**	@param id	Upgrade id number.
+**	@param amount	Value to add to timer. -1 to cancel upgrade
+*/
+global void UpgradeIncTime(Player * player, int id, int amount)
 {
-    player->UTimers.upgrades[id] += amount;
-    if ( player->UTimers.upgrades[id] >= Upgrades[id].Costs[TimeCost] )
-    {
-	player->UTimers.upgrades[id] = Upgrades[id].Costs[TimeCost];
-	UpgradeAcquire( player, &Upgrades[id] );
+    player->UpgradeTimers.Upgrades[id] += amount;
+    if (player->UpgradeTimers.Upgrades[id] >= Upgrades[id].Costs[TimeCost]) {
+	player->UpgradeTimers.Upgrades[id] = Upgrades[id].Costs[TimeCost];
+	UpgradeAcquire(player, &Upgrades[id]);
     }
 }
 
-// this function will mark upgrade done and do all required modifications to
-// unit types and will modify allow/forbid maps
-global void ApplyUpgradeModifier( Player* player, UpgradeModifier* um )
+/**
+**	Apply the modifiers of an upgrade.
+**
+**	This function will mark upgrade done and do all required modifications
+**	to unit types and will modify allow/forbid maps
+**
+**	@param player	Player that get all the upgrades.
+**	@param um	Upgrade modifier that do the effects
+*/
+local void ApplyUpgradeModifier(Player * player, const UpgradeModifier * um)
 {
     int z;
     int j;
-    int pn = player-Players; // player number
+    int pn;
 
-    for ( z = 0; z < MAXUACOUNT; z++ )
-    {
+    pn = player->Player;		// player number
+    for (z = 0; z < MAXUACOUNT; z++) {
 	// allow/forbid unit types for player
-	if ( um->af_units[z] == 'A' ) player->Allow.Units[z] = 'A';
-	if ( um->af_units[z] == 'F' ) player->Allow.Units[z] = 'F';
-
-#if 0
-	// allow/forbid actions for player
-	if ( um->af_actions[z] == 'A' ) player->Allow.Actions[z] = 'A';
-	if ( um->af_actions[z] == 'F' ) player->Allow.Actions[z] = 'F';
-#endif
-
-	// allow/forbid upgrades for player
-	if ( player->Allow.Upgrades[z] != 'R' )
-	{ // only if upgrade is not acquired
-	    if ( um->af_upgrades[z] == 'A' ) player->Allow.Upgrades[z] = 'A';
-	    if ( um->af_upgrades[z] == 'F' ) player->Allow.Upgrades[z] = 'F';
-	    // we can even have upgrade acquired w/o costs
-	    if ( um->af_upgrades[z] == 'R' ) player->Allow.Upgrades[z] = 'R';
+	if (um->ChangeUnits[z] == 'A') {
+	    player->Allow.Units[z] = 'A';
+	}
+	if (um->ChangeUnits[z] == 'F') {
+	    player->Allow.Units[z] = 'F';
 	}
 
-	DebugCheck(!( um->apply_to[z] == '?' || um->apply_to[z] == 'X' ));
-	if ( um->apply_to[z] == 'X' )
-	{ // this modifier should be applied to unittype id == z
+	// allow/forbid upgrades for player.  only if upgrade is not acquired
+	if (player->Allow.Upgrades[z] != 'R') {
+	    if (um->ChangeUpgrades[z] == 'A') {
+		player->Allow.Upgrades[z] = 'A';
+	    }
+	    if (um->ChangeUpgrades[z] == 'F') {
+		player->Allow.Upgrades[z] = 'F';
+	    }
+	    // we can even have upgrade acquired w/o costs
+	    if (um->ChangeUpgrades[z] == 'R') {
+		player->Allow.Upgrades[z] = 'R';
+	    }
+	}
 
-	    DebugLevel3Fn(" applied to %d\n",z);
+	DebugCheck(!(um->ApplyTo[z] == '?' || um->ApplyTo[z] == 'X'));
+
+	// this modifier should be applied to unittype id == z
+	if (um->ApplyTo[z] == 'X') {
+
+	    DebugLevel3Fn(" applied to %d\n", z);
 	    // upgrade stats
-	    UnitTypes[z].Stats[pn].AttackRange	+= um->mods.AttackRange;
-	    UnitTypes[z].Stats[pn].SightRange	+= um->mods.SightRange;
-	    UnitTypes[z].Stats[pn].BasicDamage	+= um->mods.BasicDamage;
-	    UnitTypes[z].Stats[pn].PiercingDamage += um->mods.PiercingDamage;
-	    UnitTypes[z].Stats[pn].Armor	+= um->mods.Armor;
-	    UnitTypes[z].Stats[pn].Speed	+= um->mods.Speed;
-	    UnitTypes[z].Stats[pn].HitPoints	+= um->mods.HitPoints;
-
+	    UnitTypes[z].Stats[pn].AttackRange += um->Modifier.AttackRange;
+	    UnitTypes[z].Stats[pn].SightRange += um->Modifier.SightRange;
+	    UnitTypes[z].Stats[pn].BasicDamage += um->Modifier.BasicDamage;
+	    UnitTypes[z].Stats[pn].PiercingDamage
+		    += um->Modifier.PiercingDamage;
+	    UnitTypes[z].Stats[pn].Armor += um->Modifier.Armor;
+	    UnitTypes[z].Stats[pn].Speed += um->Modifier.Speed;
+	    UnitTypes[z].Stats[pn].HitPoints += um->Modifier.HitPoints;
 
 	    // upgrade costs :)
-	    for( j=0; j<MaxCosts; ++j ) {
-		UnitTypes[z].Stats[pn].Costs[j]	+= um->mods.Costs[j];
+	    for (j = 0; j < MaxCosts; ++j) {
+		UnitTypes[z].Stats[pn].Costs[j] += um->Modifier.Costs[j];
 	    }
 
 	    UnitTypes[z].Stats[pn].Level++;
+
+	    if( um->ConvertTo ) {
+		UnitType* dst;
+		UnitType* src;
+		Unit* unit;
+		int i;
+
+		src=&UnitTypes[z];
+		dst=(UnitType*)um->ConvertTo;
+		dst->Stats[pn].Level++;
+		for( i=0; i<player->TotalNumUnits; ++i ) {
+		    unit=player->Units[i];
+		    if( unit->Type==src ) {
+			unit->HP+=dst->Stats[pn].HitPoints
+				-unit->Stats->HitPoints;
+			// don't have such unit now
+			player->UnitTypesCount[src->Type]--;
+			unit->Type=dst;
+			unit->Stats=&dst->Stats[pn];
+			// and we have new one...
+			player->UnitTypesCount[dst->Type]++;
+			UpdateForNewUnit(unit,1);
+			if( dst->CanCastSpell ) {
+			    unit->Mana=MAGIC_FOR_NEW_UNITS;
+			}
+			CheckUnitToBeDrawn(unit);
+		    }
+		}
+	    }
 	}
     }
 }
 
- // called by UpgradeIncTime() when timer reached
-global void UpgradeAcquire( Player* player, Upgrade* upgrade )
+/**
+**	Handle that an upgrade was acquired.
+**	Called by UpgradeIncTime() when timer reached
+**
+**	@param player	Player researching the upgrade.
+**	@param upgrade	Upgrade ready researched.
+*/
+global void UpgradeAcquire( Player* player, const Upgrade* upgrade )
 {
     int z;
     int id;
 
     id=upgrade-Upgrades;
-    player->UTimers.upgrades[id] = upgrade->Costs[TimeCost];
+    player->UpgradeTimers.Upgrades[id] = upgrade->Costs[TimeCost];
     AllowUpgradeId( player, id, 'R' );		// research done
 
     for ( z = 0; z < UpgradeModifiersCount; z++ ) {
-	if ( UpgradeModifiers[z]->uid == id ) {
+	if ( UpgradeModifiers[z]->UpgradeId == id ) {
 	    ApplyUpgradeModifier( player, UpgradeModifiers[z] );
 	}
     }
@@ -1613,6 +1642,7 @@ global void UpgradeAcquire( Player* player, Upgrade* upgrade )
     //
     if( player==ThisPlayer ) {
 	UpdateButtonPanel();
+	MustRedraw|=RedrawInfoPanel;
     }
 }
 
@@ -1624,7 +1654,7 @@ global void UpgradeLost( Player* player, int id )
 {
   return; //FIXME: remove this if implemented below
 
-  player->UTimers.upgrades[id] = 0;
+  player->UpgradeTimers.Upgrades[id] = 0;
   AllowUpgradeId( player, id, 'A' ); // research is lost i.e. available
   // FIXME: here we should reverse apply upgrade...
 }
@@ -1644,17 +1674,6 @@ global void AllowUnitId( Player* player, int id, char af ) // id -- unit type id
   player->Allow.Units[id] = af;
 }
 
-#if 0
-/**
-**	FIXME: docu
-*/
-global void AllowActionId( Player* player,  int id, char af )
-{
-  DebugCheck(!( af == 'A' || af == 'F' ));
-  player->Allow.Actions[id] = af;
-}
-#endif
-
 /**
 **	FIXME: docu
 */
@@ -1673,17 +1692,6 @@ global char UnitIdAllowed(const Player* player,  int id )
   return player->Allow.Units[id];
 }
 
-#if 0
-/**
-**	FIXME: docu
-*/
-global char ActionIdAllowed(const Player* player,  int id )
-{
-  if ( id < 0 || id >= MAXUACOUNT ) return 'F';
-  return player->Allow.Actions[id];
-}
-#endif
-
 /**
 **	FIXME: docu
 */
@@ -1696,34 +1704,38 @@ global char UpgradeIdAllowed(const Player* player,  int id )
 }
 
 // ***************by sid's
-/**
-**	FIXME: docu
-*/
-global void UpgradeIncTime2( Player* player, char* sid, int amount ) // by ident string
-  { UpgradeIncTime( player, UpgradeIdByIdent(sid), amount ); }
-/**
-**	FIXME: docu
-*/
-global void UpgradeLost2( Player* player, char* sid ) // by ident string
-  { UpgradeLost( player, UpgradeIdByIdent(sid) ); }
 
 /**
 **	FIXME: docu
 */
-global void AllowUnitByIdent( Player* player,  const char* sid, char af )
-     { AllowUnitId( player,  UnitTypeIdByIdent(sid), af ); };
-#if 0
+global void UpgradeIncTime2(Player * player, char *sid, int amount)	// by ident string
+{
+    UpgradeIncTime(player, UpgradeIdByIdent(sid), amount);
+}
+
 /**
 **	FIXME: docu
 */
-global void AllowActionByIdent( Player* player,  const char* sid, char af )
-     { AllowActionId( player,  ActionIdByIdent(sid), af ); };
-#endif
+global void UpgradeLost2(Player * player, char *sid)	// by ident string
+{
+    UpgradeLost(player, UpgradeIdByIdent(sid));
+}
+
 /**
 **	FIXME: docu
 */
-global void AllowUpgradeByIdent( Player* player,  const char* sid, char af )
-     { AllowUpgradeId( player,  UpgradeIdByIdent(sid), af ); };
+global void AllowUnitByIdent(Player * player, const char *sid, char af)
+{
+    AllowUnitId(player, UnitTypeIdByIdent(sid), af);
+}
+
+/**
+**	FIXME: docu
+*/
+global void AllowUpgradeByIdent(Player * player, const char *sid, char af)
+{
+    AllowUpgradeId(player, UpgradeIdByIdent(sid), af);
+}
 
 /**
 **	FIXME: docu
@@ -1742,27 +1754,16 @@ global void AllowByIdent(Player* player,  const char* sid, char af )
 /**
 **	FIXME: docu
 */
-global char UnitIdentAllowed(const Player* player,const char* sid )
+global char UnitIdentAllowed(const Player * player, const char *sid)
 {
-    return UnitIdAllowed( player,  UnitTypeIdByIdent(sid) );
+    return UnitIdAllowed(player, UnitTypeIdByIdent(sid));
 }
 
-#if 0
-/**
-**	FIXME: docu
-*/
-global char ActionIdentAllowed(const Player* player,const char* sid )
-{
-    return ActionIdAllowed( player,  ActionIdByIdent(sid) );
-}
-#endif
-
 /**
 **	FIXME: docu
 */
-global char UpgradeIdentAllowed(const Player* player,const char* sid )
+global char UpgradeIdentAllowed(const Player * player, const char *sid)
 {
-    return UpgradeIdAllowed( player,  UpgradeIdByIdent(sid) );
+    return UpgradeIdAllowed(player, UpgradeIdByIdent(sid));
 }
-
 //@}