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