// mingw on linux: i686-w64-mingw32-gcc -mabi=ms -shared -o Dll.dll Dll.c -I../include -L. -lBWAPIC // gcc on linux: gcc -shared -fPIC -o Dll.so Dll.c -I../include -L. -lBWAPIC #ifdef _WIN32 #include #define DLLEXPORT __declspec(dllexport) #else #define DLLEXPORT #endif #include #include #include #include #include #include #include #include typedef struct BWAPI_Game BWAPI_Game; // BWAPI::Game typedef struct BWAPI_AIModule BWAPI_AIModule; // BWAPI::AIModule static Game* Broodwar; typedef struct ExampleAIModule { const AIModule_vtable* vtable_; const char* name; } ExampleAIModule; bool isMineralField(Unit* unit); void drawWatermark(const int frame_count); void printStartLocations(); void printEvent(); void registerEventHandler(Game* game); void onStart(AIModule* self) { ExampleAIModule* module = (ExampleAIModule*) self; Game_sendText(Broodwar, "Hello from bwapi-c!"); Game_sendText(Broodwar, "My name is %s", module->name); } void onEnd(AIModule* module, bool isWinner) { Game_sendText(Broodwar, "Game ended"); } void onFrame(AIModule* self) { const int frame_count = Game_getFrameCount(Broodwar); CoordinateType CoordinateType_None = { .id = 0 }; Game_drawText(Broodwar, CoordinateType_None, 10, 10, "Frame %d", frame_count); drawWatermark(frame_count); Player* const ai = Game_self(Broodwar); if (0 < frame_count && frame_count < 1000) { printEvent(); } if (frame_count == 50) { printStartLocations(); } if (frame_count == 150) { // registerEvent test Game_registerEvent(Broodwar, ®isterEventHandler, NULL, 10, 0); } Iterator* const units = (Iterator*) Player_getUnits(ai); assert(units); for (; Iterator_valid(units); Iterator_next(units)) { Unit* const unit = (Unit*) Iterator_get(units); assert(unit); if ( !Unit_exists(unit) ) continue; const UnitType type = Unit_getType(unit); switch (type.id) { case 7: // SCV case 41: // Drone case 64: // Probe if (Unit_isIdle(unit)) { if (Unit_isCarryingGas(unit) || Unit_isCarryingMinerals(unit)) { Unit_returnCargo(unit, false); } else { Unit* const closest_mineral = Unit_getClosestUnit(unit, &isMineralField, /*radius*/ 999999); if (closest_mineral) Unit_rightClick_Unit(unit, closest_mineral, false); } } break; case 106: {// Terran_Command_Center UnitType SCV = {.id = 7 }; Unit_train(unit, SCV); Iterator* const tqueue = (Iterator*) Unit_getTrainingQueue(unit); assert(tqueue); int x, y; for (x = 10, y = 20; Iterator_valid(tqueue); Iterator_next(tqueue), y += 10) { UnitType* const unittype = (UnitType*) Iterator_get(tqueue); assert(unittype); Game_drawText(Broodwar, CoordinateType_None, x, y, "UnitType %d", unittype->id); } Iterator_release(tqueue); } break; case 154: { // Protoss_Nexus UnitType Probe = {.id = 64 }; Unit_train(unit, Probe); } break; case 131: // Zerg_Hatchery case 132: // Zerg_Lair case 133: { // Zerg_Hive UnitType Drone = {.id = 41 }; Unit_train(unit, Drone); } break; } } Iterator_release(units); } bool isMineralField(Unit* unit) { int type_id = Unit_getType(unit).id; return type_id == 176 // Resource_Mineral_Field || type_id == 177 // Resource_Mineral_Field_Type_2 || type_id == 178; // Resource_Mineral_Field_Type_3 } void drawWatermark(const int frame_count) { if (20 <= frame_count && frame_count <= 200) { TextSize hugeSize = {.size = 3}; Position position = {.x = 224, .y = 20}; Game_setTextSize(Broodwar, hugeSize); Game_drawTextScreen(Broodwar, position, "BWAPIC demo"); } } // the example of Game_getEvents void printEvent() { Iterator* const events = (Iterator*) Game_getEvents(Broodwar); assert(events); // print only the first event because in OpenBW this code really spams too much to the console if (Iterator_valid(events)) { const Event e = * (Event*)Iterator_get(events); if (e.type.id != 2) { // MatchFrame Game_sendText(Broodwar, "EventType = (%d)", e.type.id); Game_sendText(Broodwar, "Position = (%d,%d)", e.position.x, e.position.y); if (e.player) { Game_sendText(Broodwar, "Player minerals = %d", Player_minerals(e.player)); } else { Game_sendText(Broodwar, "Player = NULL"); } if (e.unit) { Game_sendText(Broodwar, "Unit id = %d", Unit_getID(e.unit)); } else { Game_sendText(Broodwar, "Unit = NULL"); } BwString* txt = Event_getText(&e); Game_sendText(Broodwar, "Text = (%s)", BwString_data(txt)); BwString_release(txt); } } Iterator_release(events); } // the example of Game_getStartLocations void printStartLocations() { Iterator* const positions = (Iterator*) Game_getStartLocations(Broodwar); if (!Iterator_valid(positions)) { Game_sendText(Broodwar, "Start location iterator is empty."); } int i; for(i = 0; Iterator_valid(positions); Iterator_next(positions), i++) { const TilePosition tp = *(TilePosition*) Iterator_get(positions); Game_sendText(Broodwar, "Start location %d = (%d, %d)", i, tp.x, tp.y); } Iterator_release(positions); } void registerEventHandler(Game* game) { Game_sendText(game, "The message from registerEventHandler"); } void onSendText(AIModule* module, const char* text) {} void onReceiveText(AIModule* module, Player* player, const char* text) {} void onPlayerLeft(AIModule* module, Player* player) {} void onNukeDetect(AIModule* module, Position target) {} void onUnitDiscover(AIModule* module, Unit* unit) {} void onUnitEvade(AIModule* module, Unit* unit) {} void onUnitShow(AIModule* module, Unit* unit) {} void onUnitHide(AIModule* module, Unit* unit) {} void onUnitCreate(AIModule* module, Unit* unit) {} void onUnitDestroy(AIModule* module, Unit* unit) {} void onUnitMorph(AIModule* module, Unit* unit) {} void onUnitRenegade(AIModule* module, Unit* unit) {} void onSaveGame(AIModule* module, const char* gameName) {} void onUnitComplete(AIModule* module, Unit* unit) {} static AIModule_vtable module_vtable = { onStart, onEnd, onFrame, onSendText, onReceiveText, onPlayerLeft, onNukeDetect, onUnitDiscover, onUnitEvade, onUnitShow, onUnitHide, onUnitCreate, onUnitDestroy, onUnitMorph, onUnitRenegade, onSaveGame, onUnitComplete }; DLLEXPORT void gameInit(BWAPI_Game* game) { Broodwar = (Game*) game; BWAPIC_setGame(Broodwar); } DLLEXPORT BWAPI_AIModule* newAIModule() { ExampleAIModule* const module = (ExampleAIModule*) malloc( sizeof(ExampleAIModule) ); module->name = "ExampleAIModule"; module->vtable_ = &module_vtable; return (BWAPI_AIModule*) createAIModuleWrapper( (AIModule*) module ); } #ifdef _WIN32 BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: break; } return TRUE; } #endif