CRAW now runs on Windows 7 too - the problem was that Windows 7 has moved some functi...
[craw.git] / craw / d2_functions.cpp
blob05e94c5ced569a8f13eeecee25a6394d01cce9f6
1 #include <windows.h>
2 #include <ail/array.hpp>
3 #include <ail/string.hpp>
4 #include <boost/foreach.hpp>
5 #include "d2_functions.hpp"
6 #include "utility.hpp"
8 class module_offset_handler
10 public:
11 module_offset_handler(unsigned image_base, unsigned module_base):
12 image_base(image_base),
13 module_base(module_base)
17 template <typename type>
18 void fix(type & function, unsigned offset)
20 function = reinterpret_cast<type>(module_base + offset - image_base);
23 template <>
24 void fix<unsigned>(unsigned & function, unsigned offset)
26 function = module_base + offset - image_base;
30 private:
31 unsigned
32 image_base,
33 module_base;
36 namespace
38 unsigned
39 d2win_base = 0x6F8E0000,
40 d2gfx_base = 0x6FA80000,
41 d2common_base = 0x6FD50000,
42 d2client_base = 0x6FAB0000,
43 d2net_base = 0x6FBF0000,
44 bnclient_base = 0x6FF20000;
46 bool d2client_has_been_loaded = false;
48 unsigned const life_mana_shift = 8;
50 unsigned data_tables;
51 unsigned roster_list;
53 unsigned player_pointer;
54 unsigned automap_layer_address;
56 unsigned initialise_automap_layer_address;
59 //D2Win.dll
60 set_font_size_type d2_set_font_size;
61 draw_text_type d2_draw_text;
62 get_text_width_type d2_get_text_width;
64 //D2Gfx.dll
65 draw_line_type d2_draw_line;
67 //D2Common.dll
68 get_unit_stat_type d2_get_unit_stat;
69 get_level_type d2_get_level;
70 get_layer_type d2_get_layer;
71 add_room_data_tye d2_add_room_data;
72 remove_room_data_type d2_remove_room_data;
73 initialise_level_type d2_initialise_level;
74 get_object_table_entry_type d2_get_object_table_entry;
75 get_inventory_item_type d2_get_inventory_item;
76 get_next_inventory_item_type d2_get_next_inventory_item;
77 get_item_text_type d2_get_item_text;
78 map_to_screen_coordinates_type d2_map_to_screen_coordinates;
79 get_skill_level_type d2_get_skill_level;
80 get_unit_state_type d2_get_unit_state;
82 //D2Client.dll
83 get_player_unit_type d2_get_player_unit;
84 get_difficulty_type d2_get_difficulty;
85 reveal_automap_room_type d2_reveal_automap_room;
86 new_automap_cell_type d2_new_automap_cell;
87 add_automap_cell_type d2_add_automap_cell;
88 leave_game_type d2_leave_game;
89 get_unit_pointer_type d2_get_unit_pointer;
90 get_item_name_type d2_get_item_name;
91 click_map_type d2_click_map;
92 find_server_side_unit_type d2_find_server_side_unit;
93 find_client_side_unit_type d2_find_client_side_unit;
94 get_unit_owner_type d2_get_unit_owner;
95 print_chat_text_type d2_print_chat_text;
97 unsigned light_handler_address;
99 unsigned automap_handler_address;
100 unsigned automap_loop_address;
102 unsigned get_unit_name_address;
104 unsigned
105 add_unit_address1,
106 add_unit_address2;
108 unsigned item_handler_call_address;
110 unsigned
111 mouse_x_address,
112 mouse_y_address;
114 unsigned server_side_unit_list_address;
116 unsigned
117 unit_is_selectable_address,
118 unit_selection_data_address;
120 //D2Net.dll
121 send_packet_type d2_send_packet;
122 receive_packet_type d2_receive_packet;
124 //Bnclient.dll
125 unsigned server_token_address = 0;
127 void initialise_d2win_addresses(unsigned base)
129 module_offset_handler offset_handler(d2win_base, base);
131 offset_handler.fix(d2_set_font_size, 0x6F8F08D0);
132 offset_handler.fix(d2_draw_text, 0x6F8F0890);
133 offset_handler.fix(d2_get_text_width, 0x6F8EFFF0);
136 void initialise_d2gfx_addresses(unsigned base)
138 module_offset_handler offset_handler(d2gfx_base, base);
140 offset_handler.fix(d2_draw_line, 0x6FA87CA0);
143 void initialise_d2common_addresses(unsigned base)
145 module_offset_handler offset_handler(d2common_base, base);
147 offset_handler.fix(d2_get_unit_stat, 0x6FD84E20);
148 offset_handler.fix(d2_get_level, 0x6FDC2520);
149 offset_handler.fix(d2_get_layer, 0x6FDC3870);
150 offset_handler.fix(d2_add_room_data, 0x6FDA68F0);
151 offset_handler.fix(d2_remove_room_data, 0x6FDA6830);
152 offset_handler.fix(d2_initialise_level, 0x6FDC2C40);
153 offset_handler.fix(d2_get_object_table_entry, 0x6FD87300);
154 offset_handler.fix(d2_get_inventory_item, 0x6FDB7500);
155 offset_handler.fix(d2_get_next_inventory_item, 0x6FDB8400);
156 offset_handler.fix(d2_get_item_text, 0x6FDAC980);
157 offset_handler.fix(d2_map_to_screen_coordinates, 0x6FDABF50);
158 offset_handler.fix(d2_get_skill_level, 0x6FD5E660);
159 offset_handler.fix(d2_get_unit_state, 0x6FDC09A0);
161 offset_handler.fix(data_tables, 0x6FDEB500);
164 void initialise_d2client_addresses(unsigned base)
166 module_offset_handler offset_handler(d2client_base, base);
168 offset_handler.fix(d2_get_player_unit, 0x6FACE490);
169 offset_handler.fix(d2_get_difficulty, 0x6FB29CD0);
170 offset_handler.fix(d2_reveal_automap_room, 0x6FAF04C0);
171 offset_handler.fix(d2_new_automap_cell, 0x6FAED5B0);
172 offset_handler.fix(d2_add_automap_cell, 0x6FAEF090);
173 offset_handler.fix(d2_leave_game, 0x6FB2AB00);
174 offset_handler.fix(d2_get_unit_pointer, 0x6FACF1C0);
175 offset_handler.fix(d2_get_item_name, 0x6FB5B3C0);
176 offset_handler.fix(d2_click_map, 0x6FB0CE80);
177 offset_handler.fix(d2_find_server_side_unit, 0x6FACF1C0);
178 offset_handler.fix(d2_find_client_side_unit, 0x6FACF1A0);
179 offset_handler.fix(d2_get_unit_owner, 0x6FB73160);
180 offset_handler.fix(d2_print_chat_text, 0x6FB21740);
182 offset_handler.fix(roster_list, 0x6FBCC080);
183 offset_handler.fix(player_pointer, 0x6FBCC3D0);
184 offset_handler.fix(automap_layer_address, 0x6FBCC2B4);
185 offset_handler.fix(initialise_automap_layer_address, 0x6FAF0650);
187 offset_handler.fix(light_handler_address, 0x6FB0F8F0);
188 offset_handler.fix(automap_handler_address, 0x6FAEF920);
189 offset_handler.fix(automap_loop_address, 0x6FAF0350);
190 offset_handler.fix(get_unit_name_address, 0x6FACF3D0);
192 offset_handler.fix(add_unit_address1, 0x6FACFD9B);
193 offset_handler.fix(add_unit_address2, 0x6FACFD9E);
195 offset_handler.fix(item_handler_call_address, 0x6FB48635);
197 offset_handler.fix(mouse_x_address, 0x6FBC21D0);
198 offset_handler.fix(mouse_y_address, 0x6FBC21CC);
200 offset_handler.fix(server_side_unit_list_address, 0x6FBCA964);
202 //offset_handler.fix(unit_is_selectable_address, 0x6FAD0010);
203 offset_handler.fix(unit_is_selectable_address, 0x6FAD0071);
205 //offset_handler.fix(unit_selection_data_address, 0x6FBCC1D0);
207 d2client_has_been_loaded = true;
210 void initialise_d2net_addresses(unsigned base)
212 module_offset_handler offset_handler(d2net_base, base);
214 offset_handler.fix(d2_send_packet, 0x6FBF6F90);
215 offset_handler.fix(d2_receive_packet, 0x6FBF6510);
218 void initialise_bnclient_addresses(unsigned base)
220 module_offset_handler offset_handler(bnclient_base, base);
222 offset_handler.fix(server_token_address, 0x6FF3F5D8);
225 void draw_text(std::string const & text, int x, int y, unsigned colour, bool centered)
227 std::size_t buffer_size = text.size() + 1;
228 wchar_t * wide_string_data = new wchar_t[buffer_size];
230 std::memset(wide_string_data, 0, buffer_size * 2);
231 MultiByteToWideChar(0, MB_PRECOMPOSED, text.c_str(), text.length(), wide_string_data, buffer_size);
233 unsigned font_size = 6;
235 unsigned old_font_size = d2_set_font_size(font_size);
236 if(centered)
238 unsigned
239 width,
240 file_number;
242 d2_get_text_width(wide_string_data, &width, &file_number);
244 x -= width / 2;
247 d2_draw_text(wide_string_data, x, y, colour, -1);
248 d2_set_font_size(old_font_size);
250 delete wide_string_data;
253 struct coordinate
259 coordinate(int x, int y):
260 x(x),
261 y(y)
266 void __stdcall draw_box(int x, int y, unsigned colour)
268 bool const continuous = true;
270 int const square_size = 3;
272 coordinate const coordinates[] =
274 coordinate(- square_size, square_size),
275 coordinate(square_size, square_size),
276 coordinate(square_size, - square_size),
277 coordinate(- square_size, - square_size),
278 coordinate(- square_size, square_size)
281 std::size_t
282 limit,
283 increment;
285 if(continuous)
287 limit = ail::countof(coordinates) - 1;
288 increment = 1;
290 else
292 limit = ail::countof(coordinates);
293 increment = 2;
296 for(std::size_t i = 0; i < limit; i += increment)
298 coordinate const & start = coordinates[i];
299 coordinate const & end = coordinates[i + 1];
300 d2_draw_line(x + start.x, y + start.y, x + end.x, y + end.y, colour, 0xff);
304 bool get_life_or_mana(unsigned & current, unsigned & maximum, unsigned stat1, unsigned stat2)
306 unit * player_unit = d2_get_player_unit();
307 if(player_unit == 0)
308 return false;
309 current = d2_get_unit_stat(player_unit, stat1, 0) >> life_mana_shift;
310 maximum = d2_get_unit_stat(player_unit, stat2, 0) >> life_mana_shift;
311 return true;
314 bool get_life(unsigned & current_life, unsigned & maximum_life)
316 return get_life_or_mana(current_life, maximum_life, 6, 7);
319 bool get_mana(unsigned & current_mana, unsigned & maximum_mana)
321 return get_life_or_mana(current_mana, maximum_mana, 8, 9);
324 monster_statistics & get_monster_statistics(std::size_t index)
326 char * root = *reinterpret_cast<char **>(data_tables);
327 monster_statistics * table = *reinterpret_cast<monster_statistics **>(root + 0xA78);
328 return table[index];
331 roster_unit * get_player_roster(unsigned player_id)
333 for(roster_unit * i = reinterpret_cast<roster_unit *>(roster_list); i; i = i->next_roster)
335 if(i->unit_id == player_id)
336 return i;
338 return 0;
341 unit * get_player()
343 return *reinterpret_cast<unit **>(player_pointer);
346 automap_layer * get_automap_layer()
348 return *reinterpret_cast<automap_layer **>(automap_layer_address);
351 __declspec(naked) automap_layer_type_2 * __fastcall initialise_automap_layer_stub(unsigned layer_number)
353 __asm
355 push eax
356 mov eax, ecx
357 call initialise_automap_layer_address
358 pop eax
363 automap_layer_type_2 * initialise_automap_layer(unsigned level_number)
365 automap_layer_type_2 * layer = d2_get_layer(level_number);
366 if(!layer)
367 return 0;
368 return initialise_automap_layer_stub(layer->layer_number);
371 automap_cell ** get_layer_objects_pointer()
373 return &(get_automap_layer()->objects);
376 bool get_player_level_number(unsigned & output)
378 unit * unit_pointer = d2_get_player_unit();
380 //is this really necessary? Damn you, D2BS.
382 unit_pointer &&
383 unit_pointer->path_data_pointer &&
384 unit_pointer->path_data_pointer->room_1 &&
385 unit_pointer->path_data_pointer->room_1->room_2 &&
386 unit_pointer->path_data_pointer->room_1->room_2->level
389 output = unit_pointer->path_data_pointer->room_1->room_2->level->level_number;
390 return true;
393 return false;
396 bool get_player_id(unsigned & output)
398 unit * unit_pointer = d2_get_player_unit();
399 if(unit_pointer == 0)
400 return false;
402 output = unit_pointer->id;
404 return true;
407 wchar_t * get_unit_name(unit * unit_pointer)
409 wchar_t * output;
410 __asm
412 mov eax, unit_pointer
413 call get_unit_name_address
414 mov output, eax
416 return output;
419 roster_vector get_roster_units()
421 roster_vector output;
423 roster_unit * roster_pointer = *reinterpret_cast<roster_unit **>(roster_list);
424 while(roster_pointer)
426 output.push_back(roster_unit(*roster_pointer));
427 roster_pointer = roster_pointer->next_roster;
430 return output;
433 bool get_name_by_id(unsigned id, std::string & output)
435 roster_vector roster_units = get_roster_units();
436 BOOST_FOREACH(roster_unit & current_unit, roster_units)
438 if(current_unit.unit_id == id)
440 output = current_unit.get_name();
441 return true;
445 return false;
448 bool get_non_empty_tp_tome_id(unsigned & output)
450 unit * unit_pointer = d2_get_player_unit();
451 if(!unit_pointer)
452 return false;
454 inventory * inventory_pointer = unit_pointer->inventory_pointer;
455 if(!inventory_pointer)
456 return false;
458 for(unit * current_item = d2_get_inventory_item(inventory_pointer); current_item != 0; current_item = d2_get_next_inventory_item(current_item))
460 item_data * item_data_pointer = current_item->item_data_pointer;
461 if(!item_data_pointer)
462 continue;
464 //inventory check
465 if(item_data_pointer->item_location != 0)
466 continue;
468 item_text * item_text_pointer = d2_get_item_text(current_item->table_index);
469 if(item_text_pointer == 0)
470 continue;
472 if(item_text_pointer->get_code() != "tbk")
473 continue;
475 //retrieve quantity
476 unsigned count = d2_get_unit_stat(current_item, 70, 0);
477 if(count == 0)
478 continue;
480 output = current_item->id;
481 return true;
484 return false;
487 bool player_is_in_game()
489 if(!d2client_has_been_loaded)
490 return false;
492 return d2_get_player_unit() != 0;
495 bool get_item_name(unit * input, std::string & name, std::string & special_name)
497 wchar_t buffer[0x100];
498 std::memset(buffer, 0, sizeof(buffer));
499 attach_point();
500 if(!d2_get_item_name(input, buffer, ail::countof(buffer)))
501 return false;
503 std::string data = wchar_to_string(buffer);
504 string_vector tokens = ail::tokenise(data, "\n");
505 switch(tokens.size())
507 default:
508 error("d2_get_item_name returned an invalid item name for item " + ail::hex_string_32(reinterpret_cast<unsigned>(input)) + ": \"" + data + "\"");
509 exit_process();
510 return false;
512 case 1:
513 name = data;
514 special_name.clear();
515 break;
517 case 2:
518 name = tokens[1];
519 special_name = tokens[0];
520 break;
523 return true;
526 void move_click(int x, int y)
528 d2_map_to_screen_coordinates(&x, &y);
529 x -= *reinterpret_cast<int *>(mouse_x_address);
530 y -= *reinterpret_cast<int *>(mouse_y_address);
531 d2_click_map(0, x, y, 8);
534 bool get_unit_by_id(unsigned id, unsigned type, unit * & output)
536 output = d2_find_server_side_unit(id, type);
537 if(output != 0)
538 return true;
540 output = d2_find_client_side_unit(id, type);
542 return output != 0;
545 bool get_skill_level(unsigned skill_id, unsigned & output)
547 unit * unit_pointer = d2_get_player_unit();
548 if(!unit_pointer)
549 return false;
551 for(skill_data * current_skill = unit_pointer->skill_pointer->first_skill; current_skill; current_skill = current_skill->next_skill)
553 if(current_skill->skill_information_pointer->identifier == skill_id)
555 output = d2_get_skill_level(unit_pointer, current_skill, true);
556 return true;
560 return false;
563 bool get_minions(unsigned player_id, std::vector<unit> & output)
565 unit * unit_pointer;
566 if(!get_unit_by_id(player_id, unit_player, unit_pointer))
567 return false;
569 act_data * act_data_pointer = unit_pointer->act_data_pointer;
570 if(act_data_pointer == 0)
571 return false;
573 for(room_data_type_1 * room_pointer = act_data_pointer->room_1; room_pointer; room_pointer = room_pointer->next_room)
575 for(unit * unit_pointer = room_pointer->first_unit; unit_pointer; unit_pointer = unit_pointer->next_list_entry)
577 unit & current_unit = *unit_pointer;
578 if(current_unit.type == unit_monster && d2_get_unit_owner(current_unit.id) == player_id)
579 output.push_back(current_unit);
583 return true;
586 void print_chat_text(std::string const & message)
588 //write_line(ail::hex_string(message));
589 wchar_t * wide_string = string_to_wchar(message);
590 //write_line(ail::hex_string(std::string((char *)wide_string, message.size() * 2)));
591 d2_print_chat_text(wide_string, 0);
592 delete wide_string;