1 /***************************************************************************
2                           combattest.cpp  -  description
3                              -------------------
4     begin                : Sat Nov 12 2005
5     copyright            : (C) 2005 by Gabor Torok
6     email                : cctorok@yahoo.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 #include "combattest.h"
18 #include "../rpg/rpglib.h"
19 #include "../creature.h"
20 #include "../item.h"
21 #include "../session.h"
22 #include <vector>
23 
24 using namespace std;
25 
26 /**
27   *@author Gabor Torok
28   */
29 
30 #define SHOW_MAX_LEVEL MAX_LEVEL
31 #define HTML_PREFIX "<html><head><title>%s</title><style>\
32 BODY { \
33   background: white;\
34   font-size: 9pt; \
35   FONT-FAMILY: Arial, Helvetica, sans-serif; \
36   margin: 15px;\
37   color: black;\
38 }\
39 TD { \
40   font-size: 8pt; \
41   FONT-FAMILY: Monospace, Courier, sans-serif; \
42   padding: 5px;\
43   border: 1px solid gray\
44 }\
45 TH { \
46   font-size: 9pt; \
47   FONT-FAMILY: Arial, Helvetica, sans-serif; \
48   font-weight:bold;\
49 }\
50 </style></head><body bgcolor=white>"
51 #define HTML_POSTFIX "</body></html>"
52 
CombatTest()53 CombatTest::CombatTest() {
54 }
55 
~CombatTest()56 CombatTest::~CombatTest() {
57 }
58 
executeTests(Session * session,char const * path)59 bool CombatTest::executeTests( Session *session, char const* path ) {
60   vector<Creature*> creatures;
61   vector<Item*> items;
62 
63   // -----------------------------------------------------------
64   // The attacker
65   Creature *attacker = createCharacter( session, "RA", "Attacker", 1 );
66   creatures.push_back( attacker );
67   Item *weapon = equipItem( session, attacker, "Dirk", 1 );
68   items.push_back( weapon );
69 
70   // The defender
71   Creature *defender = createCharacter( session, "RA", "Defender", 1 );
72   creatures.push_back( defender );
73   items.push_back( equipItem( session, defender, "Horned helmet", 1 ) );
74   items.push_back( equipItem( session, defender, "Leather Armor", 1 ) );
75 
76   // Test all weapons vs. leather armor
77   bool ret = true;
78   enum { FILE_NAME_SIZE = 80 };
79   char filename[ FILE_NAME_SIZE ];
80   for( int i = 0; i < RpgItem::itemCount; i++ ) {
81     if( !RpgItem::getItem( i )->isWeapon() ) continue;
82     attacker->removeFromBackpack( 0 );
83     weapon = equipItem( session, attacker, RpgItem::getItem( i )->getName(), 1 );
84     items.push_back( weapon );
85     snprintf( filename, FILE_NAME_SIZE, "weapon_%s.html", RpgItem::getItem( i )->getName() );
86     if( !fight( path, filename, session, attacker, weapon, defender ) ) break;
87   }
88 
89   // Test all character classes with long sword vs. leather armor
90   attacker->removeFromBackpack( 0 );
91   weapon = equipItem( session, attacker, "Long sword", 1 );
92   items.push_back( weapon );
93   /* -=K=-: Character does not work like that anymore
94   for( int i = 0; i < static_cast<int>(Character::character_list.size()); i++ ) {
95     Creature *c = createCharacter( session, Character::character_list[i]->getName(), "Defender", 1 );
96     creatures.push_back( c );
97     items.push_back( equipItem( session, c, "Horned helmet", 1 ) );
98     items.push_back( equipItem( session, c, "Leather Armor", 1 ) );
99     snprintf( filename, FILE_NAME_SIZE, "character_%s.html", Character::character_list[i]->getName() );
100     if( !fight( path, filename, session, attacker, weapon, c ) ) break;
101   }*/
102 
103   // Test random skill values
104   for( int i = 0; i < 20; i++ ) {
105     for( int t = 0; t < 8; t++ ) {
106       attacker->setSkill( t, Util::dice( MAX_SKILL ) );
107       defender->setSkill( t, Util::dice( MAX_SKILL ) );
108     }
109     snprintf( filename, FILE_NAME_SIZE, "rand_ability_%d.html", i );
110     if( !fight( path, filename, session, attacker, weapon, defender ) ) break;
111   }
112 
113   // cleanup
114   for( int i = 0; i < static_cast<int>(items.size()); i++ ) {
115     Item *item = items[ i ];
116     delete item;
117   }
118   for( int i = 0; i < static_cast<int>(creatures.size()); i++ ) {
119     Creature *creature = creatures[ i ];
120     delete creature;
121   }
122 
123 
124   return ret;
125 }
126 
127 
128 
129 
130 
fight(char const * path,char const * filename,Session * session,Creature * attacker,Item * weapon,Creature * defender,int count)131 bool CombatTest::fight( char const* path,
132                         char const* filename,
133                         Session *session,
134                         Creature *attacker,
135                         Item *weapon,
136                         Creature *defender,
137                         int count ) {
138 
139   char file[300];
140   snprintf( file, 300, "%s/%s", path, filename );
141   FILE *fp = fopen( file, "w" );
142   if( !fp ) {
143     cerr << "Unable to open file: " << file << endl;
144     return false;
145   }
146   cout << "...creating file: " << file << endl;
147 
148   attacker->setTargetCreature( defender );
149 
150   fprintf( fp, HTML_PREFIX, "Combat Test" );
151 
152   fprintf( fp, "<h1>Combat test with %d iterations</h1>", count );
153   fprintf( fp, "<b>%s</b> with %s vs. ", attacker->getCharacter()->getName(), weapon->getRpgItem()->getName() );
154   fprintf( fp, "<b>%s</b><br>\n", defender->getCharacter()->getName() );
155   fprintf( fp, "<a href=\"#details\">Character details...</a><br><br>");
156   fprintf( fp, "<table><tr>\n" );
157 
158   int atkOriginalLevel = attacker->getLevel();
159   int defOriginalLevel = defender->getLevel();
160 
161   float max, min;
162   float sum=0, low=0, high=0, ATKave;
163   for( int n = 0; n < SHOW_MAX_LEVEL; n++ ) {
164 
165     if( n && !( n % 3 ) ) {
166       fprintf( fp, "</tr><tr>" );
167     }
168 
169     int attackLevel = n + 1;
170     attacker->setLevel( attackLevel );
171     // adjust the skills
172     setMinSkills( attacker );
173     fprintf( fp, "<td><div style='background: gray; color: white;'>Attacker's Level: %d</div>\n", attackLevel );
174 
175     for( int i = 0; i < 2; i++ ) {
176 
177       defender->setLevel( !i ? 1 : attacker->getLevel() );
178       setMinSkills( defender );
179       fprintf( fp, "<div style='background: gray; color: white;'>Defender's Level: %d</div>\n", defender->getLevel() );
180 
181       // -------------------------------------------------
182       // Attack roll
183       sum = low = high = 0;
184       attacker->getAttack( weapon, &max, &min );
185       fprintf( fp, "ATK range:<b>%.2f - %.2f</b><br>\n", min, max );
186       for( int i = 0; i < count; i++ ) {
187         computeHighLow( attacker->getAttack( weapon ), &sum, &low, &high );
188       }
189       ATKave = sum / static_cast<double>(count);
190       fprintf( fp, "ATK roll: <b>%.2f</b>(%.2f - %.2f)<br>\n", ATKave, low, high );
191       // -------------------------------------------------
192 
193       // -------------------------------------------------
194       // Armor class at level 1
195 			float armor, dodgePenalty;
196 			defender->getArmor( &armor, &dodgePenalty,
197 													weapon ? weapon->getRpgItem()->getDamageType() :
198 													RpgItem::DAMAGE_TYPE_CRUSHING );
199       fprintf( fp , "Armor: <span style='background: %s'><b>%.2f</b></span><br>\n", ( ATKave > armor ? "red" : "green" ), armor );
200 			/*
201       fprintf( fp , "Armor: <span style='background: %s'><b>%.2f</b></span>\
202                (%.2f %% %.2f)<br>\n",
203                ( ATKave > ac ? "red" : "green" ),
204                armor, total, skill );
205 			*/
206       // -------------------------------------------------
207     }
208 
209     fprintf( fp, "</td>" );
210     fprintf( fp, "\n" );
211   }
212   fprintf( fp, "</tr></table><br>\n" );
213 
214   // reset
215   attacker->setLevel( atkOriginalLevel );
216   defender->setLevel( defOriginalLevel );
217   // adjust the skills
218   setMinSkills( attacker );
219   setMinSkills( defender );
220 
221   fprintf( fp, "<br><a name=\"details\"></a><b>Character details:</b>" );
222   fprintf( fp, "<table><tr><td style='border: none;' valign=top>" );
223   fprintf( fp, "Attacker: <b>%s</b> with %s<br>Level: %d<br>\n",
224            attacker->getCharacter()->getName(),
225            weapon->getRpgItem()->getName(),
226            attacker->getLevel() );
227   printBackpack( fp, attacker );
228 
229   fprintf( fp, "</td><td style='border: none;' valign=top>" );
230   fprintf( fp, "Defender: <b>%s</b><br>Level: %d<br>\n",
231            defender->getCharacter()->getName(),
232            defender->getLevel() );
233   printBackpack( fp, defender );
234   fprintf( fp, "</td></tr></table>" );
235 
236   fclose( fp );
237   return true;
238 }
239 
computeHighLow(float value,float * sum,float * low,float * high)240 void CombatTest::computeHighLow( float value, float *sum, float *low, float *high ) {
241   if( !(*high) ) {
242     *low = *high = value;
243   } else if( value > *high ) {
244     *high = value;
245   } else if( value < *low ) {
246     *low = value;
247   }
248   *sum += value;
249 }
250 
printBackpack(FILE * fp,Creature * creature)251 void CombatTest::printBackpack( FILE *fp, Creature *creature ) {
252   fprintf( fp, "<b>Skills:</b><table><tr><td>Name</td>\
253            <td>Value</td><td>MIN-MAX</td></tr>\n" );
254   char color[20];
255   for( int i = 0; i < Skill::SKILL_COUNT; i++ ) {
256 
257     int n = creature->getSkill( i );
258     if( n < MAX_SKILL / 4.0f ) strcpy( color, "red" );
259     else if( n < MAX_SKILL / 2.0f ) strcpy( color, "orange" );
260     else if( n < MAX_SKILL - MAX_SKILL / 4.0f ) strcpy( color, "white" );
261     else strcpy( color, "green" );
262 
263     fprintf( fp, "<tr><td><b>%s</b></td>\
264              <td bgcolor=%s>%d</td>",
265              Skill::skills[ i ]->getName(), color, n );
266 
267     fprintf( fp, "</tr>\n" );
268   }
269   fprintf( fp, "</table>\n" );
270 
271   fprintf( fp, "<b>Backpack:</b><ul>\n" );
272   for( int i = 0; i < creature->getBackpackContentsCount(); i++ ) {
273     fprintf( fp, "<li>%s A:%d %s<br>\n",
274              creature->getBackpackItem( i )->getRpgItem()->getName(),
275              creature->getBackpackItem( i )->getRpgItem()->getDamage(),
276              ( creature->isEquipped( i ) ? "<i>Equipped</i>" : "" ) );
277   }
278   fprintf( fp, "</ul>\n" );
279 }
280 
createCharacter(Session * session,char const * characterShortName,char * name,int level)281 Creature *CombatTest::createCharacter( Session *session,
282                                        char const* characterShortName,
283                                        char *name,
284                                        int level ) {
285   Character *character = Character::getRandomCharacter();
286   Creature *c =
287     new Creature( session,
288                   character,
289                   name,
290 	              Constants::SEX_MALE,
291                   0 );
292   //c->setDeityIndex( info[i].deityType->getSelectedLine() );
293   c->setLevel( level );
294   c->setExp( 0 );
295   c->setHp();
296   c->setMp();
297   c->setHunger(10);
298   c->setThirst(10);
299 
300   // assign portraits
301   //c->setPortraitTextureIndex( info[i].portraitIndex );
302 
303   setMinSkills( c );
304 
305   return c;
306 }
307 
308 // FIXME: made to compile but is non-sensical
setMinSkills(Creature * c)309 void CombatTest::setMinSkills( Creature *c ) {
310   // starting skills
311   //Character *character = c->getCharacter();
312   for(int i = 0; i < Skill::SKILL_COUNT; i++) {
313     int n = c->getLevel() * 10;
314     if(n > 99) n = 99;
315     c->setSkill( i, n );
316   }
317 }
318 
equipItem(Session * session,Creature * c,char const * itemName,int itemLevel)319 Item *CombatTest::equipItem( Session *session,
320                              Creature *c,
321                              char const* itemName,
322                              int itemLevel ) {
323   Item *item = new Item( session, RpgItem::getItemByName( itemName ), itemLevel );
324   c->addToBackpack( item, true );
325   c->equipFromBackpack( c->getBackpackContentsCount() - 1 );
326   return item;
327 }
328 
329