Ticket #2322: AI_in_one_global_WIP_v0.2.diff
File AI_in_one_global_WIP_v0.2.diff, 92.3 KB (added by , 10 years ago) |
---|
-
source/simulation2/components/CCmpAIManager.cpp
78 78 NONCOPYABLE(CAIPlayer); 79 79 public: 80 80 CAIPlayer(CAIWorker& worker, const std::wstring& aiName, player_id_t player, uint8_t difficulty, 81 const shared_ptr<ScriptRuntime>& runtime, boost::rand48& rng) :82 m_Worker(worker), m_AIName(aiName), m_Player(player), m_Difficulty(difficulty), m_ScriptInterface( "Engine", "AI", runtime)81 shared_ptr<ScriptInterface> scriptInterface) : 82 m_Worker(worker), m_AIName(aiName), m_Player(player), m_Difficulty(difficulty), m_ScriptInterface(scriptInterface) 83 83 { 84 m_ScriptInterface.SetCallbackData(static_cast<void*> (this));85 86 m_ScriptInterface.ReplaceNondeterministicRNG(rng);87 m_ScriptInterface.LoadGlobalScripts();88 89 m_ScriptInterface.RegisterFunction<void, std::wstring, CAIPlayer::IncludeModule>("IncludeModule");90 m_ScriptInterface.RegisterFunction<void, CAIPlayer::DumpHeap>("DumpHeap");91 m_ScriptInterface.RegisterFunction<void, CAIPlayer::ForceGC>("ForceGC");92 m_ScriptInterface.RegisterFunction<void, CScriptValRooted, CAIPlayer::PostCommand>("PostCommand");93 94 m_ScriptInterface.RegisterFunction<void, std::wstring, std::vector<u32>, u32, u32, u32, CAIPlayer::DumpImage>("DumpImage");95 96 m_ScriptInterface.RegisterFunction<void, std::wstring, CScriptVal, CAIPlayer::RegisterSerializablePrototype>("RegisterSerializablePrototype");97 84 } 98 85 99 86 ~CAIPlayer() … … 103 90 m_Commands.clear(); 104 91 } 105 92 106 static void IncludeModule(void* cbdata, std::wstring name)107 {108 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);109 110 self->LoadScripts(name);111 }112 static void DumpHeap(void* cbdata)113 {114 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);115 116 //std::cout << JS_GetGCParameter(self->m_ScriptInterface.GetRuntime(), JSGC_BYTES) << std::endl;117 self->m_ScriptInterface.DumpHeap();118 }119 static void ForceGC(void* cbdata)120 {121 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);122 123 JS_GC(self->m_ScriptInterface.GetContext());124 }125 static void PostCommand(void* cbdata, CScriptValRooted cmd)126 {127 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);128 129 self->m_Commands.push_back(self->m_ScriptInterface.WriteStructuredClone(cmd.get()));130 }131 132 /**133 * Debug function for AI scripts to dump 2D array data (e.g. terrain tile weights).134 * TODO: check if this needs to be here too.135 */136 static void DumpImage(void* UNUSED(cbdata), std::wstring name, std::vector<u32> data, u32 w, u32 h, u32 max)137 {138 // TODO: this is totally not threadsafe.139 140 VfsPath filename = L"screenshots/aidump/" + name;141 142 if (data.size() != w*h)143 {144 debug_warn(L"DumpImage: data size doesn't match w*h");145 return;146 }147 148 if (max == 0)149 {150 debug_warn(L"DumpImage: max must not be 0");151 return;152 }153 154 const size_t bpp = 8;155 int flags = TEX_BOTTOM_UP|TEX_GREY;156 157 const size_t img_size = w * h * bpp/8;158 const size_t hdr_size = tex_hdr_size(filename);159 shared_ptr<u8> buf;160 AllocateAligned(buf, hdr_size+img_size, maxSectorSize);161 Tex t;162 if (tex_wrap(w, h, bpp, flags, buf, hdr_size, &t) < 0)163 return;164 165 u8* img = buf.get() + hdr_size;166 for (size_t i = 0; i < data.size(); ++i)167 img[i] = (u8)((data[i] * 255) / max);168 169 tex_write(&t, filename);170 tex_free(&t);171 }172 173 static void RegisterSerializablePrototype(void* cbdata, std::wstring name, CScriptVal proto)174 {175 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata);176 // Add our player number to avoid name conflicts with other prototypes177 // TODO: it would be better if serializable prototypes were stored in ScriptInterfaces178 // and then each serializer would access those matching its own context, but that's179 // not possible with AIs sharing data across contexts180 std::wstringstream protoID;181 protoID << self->m_Player << L"." << name.c_str();182 self->m_Worker.RegisterSerializablePrototype(protoID.str(), proto);183 }184 185 bool LoadScripts(const std::wstring& moduleName)186 {187 // Ignore modules that are already loaded188 if (m_LoadedModules.find(moduleName) != m_LoadedModules.end())189 return true;190 191 // Mark this as loaded, to prevent it recursively loading itself192 m_LoadedModules.insert(moduleName);193 194 // Load and execute *.js195 VfsPaths pathnames;196 vfs::GetPathnames(g_VFS, L"simulation/ai/" + moduleName + L"/", L"*.js", pathnames);197 for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)198 {199 if (!m_ScriptInterface.LoadGlobalScriptFile(*it))200 {201 LOGERROR(L"Failed to load script %ls", it->string().c_str());202 return false;203 }204 }205 206 return true;207 }208 209 93 bool Initialise(bool callConstructor) 210 94 { 211 if (!LoadScripts(m_AIName)) 95 // LoadScripts will only load each script once even though we call it for each player 96 if (!m_Worker.LoadScripts(m_AIName)) 212 97 return false; 213 98 214 99 OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; … … 221 106 222 107 // Get the constructor name from the metadata 223 108 std::string constructor; 224 if (!m_ScriptInterface .GetProperty(metadata.get(), "constructor", constructor))109 if (!m_ScriptInterface->GetProperty(metadata.get(), "constructor", constructor)) 225 110 { 226 111 LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str()); 227 112 return false; … … 229 114 230 115 // Get the constructor function from the loaded scripts 231 116 CScriptVal ctor; 232 if (!m_ScriptInterface .GetProperty(m_ScriptInterface.GetGlobalObject(), constructor.c_str(), ctor)117 if (!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), constructor.c_str(), ctor) 233 118 || ctor.undefined()) 234 119 { 235 120 LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str()); 236 121 return false; 237 122 } 238 123 239 m_ScriptInterface .GetProperty(metadata.get(), "useShared", m_UseSharedComponent);124 m_ScriptInterface->GetProperty(metadata.get(), "useShared", m_UseSharedComponent); 240 125 241 126 CScriptVal obj; 242 127 … … 244 129 { 245 130 // Set up the data to pass as the constructor argument 246 131 CScriptVal settings; 247 m_ScriptInterface .Eval(L"({})", settings);248 m_ScriptInterface .SetProperty(settings.get(), "player", m_Player, false);249 m_ScriptInterface .SetProperty(settings.get(), "difficulty", m_Difficulty, false);132 m_ScriptInterface->Eval(L"({})", settings); 133 m_ScriptInterface->SetProperty(settings.get(), "player", m_Player, false); 134 m_ScriptInterface->SetProperty(settings.get(), "difficulty", m_Difficulty, false); 250 135 ENSURE(m_Worker.m_HasLoadedEntityTemplates); 251 m_ScriptInterface .SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false);136 m_ScriptInterface->SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false); 252 137 253 obj = m_ScriptInterface .CallConstructor(ctor.get(), settings.get());138 obj = m_ScriptInterface->CallConstructor(ctor.get(), settings.get()); 254 139 } 255 140 else 256 141 { 257 142 // For deserialization, we want to create the object with the correct prototype 258 143 // but don't want to actually run the constructor again 259 144 // XXX: actually we don't currently use this path for deserialization - maybe delete it? 260 obj = m_ScriptInterface .NewObjectFromConstructor(ctor.get());145 obj = m_ScriptInterface->NewObjectFromConstructor(ctor.get()); 261 146 } 262 147 263 148 if (obj.undefined()) … … 266 151 return false; 267 152 } 268 153 269 m_Obj = CScriptValRooted(m_ScriptInterface .GetContext(), obj);154 m_Obj = CScriptValRooted(m_ScriptInterface->GetContext(), obj); 270 155 return true; 271 156 } 272 157 273 void Run(CScriptVal state )158 void Run(CScriptVal state, int playerID) 274 159 { 275 160 m_Commands.clear(); 276 m_ScriptInterface .CallFunctionVoid(m_Obj.get(), "HandleMessage", state);161 m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID); 277 162 } 278 163 // overloaded with a sharedAI part. 279 164 // javascript can handle both natively on the same function. 280 void Run(CScriptVal state, CScriptValRooted SharedAI)165 void Run(CScriptVal state, int playerID, CScriptValRooted SharedAI) 281 166 { 282 167 m_Commands.clear(); 283 m_ScriptInterface .CallFunctionVoid(m_Obj.get(), "HandleMessage", state, SharedAI);168 m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "HandleMessage", state, playerID, SharedAI); 284 169 } 285 170 void InitAI(CScriptVal state, CScriptValRooted SharedAI) 286 171 { 287 172 m_Commands.clear(); 288 m_ScriptInterface .CallFunctionVoid(m_Obj.get(), "Init", state, SharedAI);173 m_ScriptInterface->CallFunctionVoid(m_Obj.get(), "Init", state, m_Player, SharedAI); 289 174 } 290 175 291 176 CAIWorker& m_Worker; … … 294 179 uint8_t m_Difficulty; 295 180 bool m_UseSharedComponent; 296 181 297 ScriptInterfacem_ScriptInterface;182 shared_ptr<ScriptInterface> m_ScriptInterface; 298 183 CScriptValRooted m_Obj; 299 184 std::vector<shared_ptr<ScriptInterface::StructuredClone> > m_Commands; 300 std::set<std::wstring> m_LoadedModules;301 185 }; 302 186 303 187 public: … … 313 197 // removed as soon whenever the new pathfinder is committed 314 198 // And the AIs can stop relying on their own little hands. 315 199 m_ScriptRuntime(ScriptInterface::CreateRuntime(33554432)), 316 m_ScriptInterface( "Engine", "AI", m_ScriptRuntime),200 m_ScriptInterface(new ScriptInterface("Engine", "AI", m_ScriptRuntime)), 317 201 m_TurnNum(0), 318 202 m_CommandsComputed(true), 319 203 m_HasLoadedEntityTemplates(false), … … 321 205 { 322 206 323 207 // TODO: ought to seed the RNG (in a network-synchronised way) before we use it 324 m_ScriptInterface .ReplaceNondeterministicRNG(m_RNG);325 m_ScriptInterface .LoadGlobalScripts();208 m_ScriptInterface->ReplaceNondeterministicRNG(m_RNG); 209 m_ScriptInterface->LoadGlobalScripts(); 326 210 327 m_ScriptInterface .SetCallbackData(NULL);211 m_ScriptInterface->SetCallbackData(static_cast<void*> (this)); 328 212 329 m_ScriptInterface.RegisterFunction<void, CScriptValRooted, CAIWorker::PostCommand>("PostCommand"); 330 m_ScriptInterface.RegisterFunction<void, CAIWorker::DumpHeap>("DumpHeap"); 331 m_ScriptInterface.RegisterFunction<void, CAIWorker::ForceGC>("ForceGC"); 213 m_ScriptInterface->RegisterFunction<void, int, CScriptValRooted, CAIWorker::PostCommand>("PostCommand"); 214 m_ScriptInterface->RegisterFunction<void, std::wstring, CAIWorker::IncludeModule>("IncludeModule"); 215 m_ScriptInterface->RegisterFunction<void, CAIWorker::DumpHeap>("DumpHeap"); 216 m_ScriptInterface->RegisterFunction<void, CAIWorker::ForceGC>("ForceGC"); 332 217 333 m_ScriptInterface .RegisterFunction<void, std::wstring, std::vector<u32>, u32, u32, u32, CAIWorker::DumpImage>("DumpImage");218 m_ScriptInterface->RegisterFunction<void, std::wstring, std::vector<u32>, u32, u32, u32, CAIWorker::DumpImage>("DumpImage"); 334 219 } 335 220 336 221 ~CAIWorker() … … 343 228 m_PassabilityMapVal = CScriptValRooted(); 344 229 m_TerritoryMapVal = CScriptValRooted(); 345 230 } 231 232 bool LoadScripts(const std::wstring& moduleName) 233 { 234 // Ignore modules that are already loaded 235 if (m_LoadedModules.find(moduleName) != m_LoadedModules.end()) 236 return true; 346 237 347 // This is called by AIs if they use the v3 API. 348 // If the AIs originate the call, cbdata is not NULL. 349 // If the shared component does, it is, so it must not be taken into account. 350 static void PostCommand(void* cbdata, CScriptValRooted cmd) 238 // Mark this as loaded, to prevent it recursively loading itself 239 m_LoadedModules.insert(moduleName); 240 241 // Load and execute *.js 242 VfsPaths pathnames; 243 vfs::GetPathnames(g_VFS, L"simulation/ai/" + moduleName + L"/", L"*.js", pathnames); 244 for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it) 245 { 246 if (!m_ScriptInterface->LoadGlobalScriptFile(*it)) 247 { 248 LOGERROR(L"Failed to load script %ls", it->string().c_str()); 249 return false; 250 } 251 } 252 253 return true; 254 } 255 256 static void IncludeModule(void* cbdata, std::wstring name) 351 257 { 352 if (cbdata == NULL) { 353 debug_warn(L"Warning: the shared component has tried to push an engine command. Ignoring."); 354 return; 258 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 259 self->LoadScripts(name); 260 } 261 262 static void PostCommand(void* cbdata, int playerid, CScriptValRooted cmd) 263 { 264 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 265 self->PostCommand(playerid, cmd); 266 } 267 268 void PostCommand(int playerid, CScriptValRooted cmd) 269 { 270 bool playerFound = false; 271 for (int i=0; i<m_Players.size(); i++) 272 { 273 if (m_Players[i]->m_Player == playerid) 274 { 275 m_Players[i]->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(cmd.get())); 276 playerFound = true; 277 } 355 278 } 356 CAIPlayer* self = static_cast<CAIPlayer*> (cbdata); 357 self->m_Commands.push_back(self->m_ScriptInterface.WriteStructuredClone(cmd.get())); 279 280 if (!playerFound) 281 LOGERROR(L"Invalid playerid in PostCommand!"); 358 282 } 359 283 // The next two ought to be implmeneted someday but for now as it returns "null" it can't 360 284 static void DumpHeap(void* cbdata) … … 364 288 return; 365 289 } 366 290 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 367 self->m_ScriptInterface .DumpHeap();291 self->m_ScriptInterface->DumpHeap(); 368 292 } 369 293 static void ForceGC(void* cbdata) 370 294 { … … 374 298 } 375 299 CAIWorker* self = static_cast<CAIWorker*> (cbdata); 376 300 PROFILE3("AI compute GC"); 377 JS_GC(self->m_ScriptInterface .GetContext());301 JS_GC(self->m_ScriptInterface->GetContext()); 378 302 } 379 303 380 304 /** … … 424 348 425 349 // reset the value so it can be used to determine if we actually initialized it. 426 350 m_HasSharedComponent = false; 427 351 352 if (LoadScripts(L"common-api-v3")) 353 m_HasSharedComponent = true; 354 else 355 return false; 356 /* 428 357 VfsPaths sharedPathnames; 429 358 // Check for "shared" module. 430 359 vfs::GetPathnames(g_VFS, L"simulation/ai/common-api-v3/", L"*.js", sharedPathnames); 431 360 for (VfsPaths::iterator it = sharedPathnames.begin(); it != sharedPathnames.end(); ++it) 432 361 { 433 if (!m_ScriptInterface .LoadGlobalScriptFile(*it))362 if (!m_ScriptInterface->LoadGlobalScriptFile(*it)) 434 363 { 435 364 LOGERROR(L"Failed to load shared script %ls", it->string().c_str()); 436 365 return false; … … 439 368 } 440 369 if (!m_HasSharedComponent) 441 370 return false; 442 371 */ 443 372 // mainly here for the error messages 444 373 OsPath path = L"simulation/ai/common-api-v2/"; 445 374 446 375 // Constructor name is SharedScript 447 376 CScriptVal ctor; 448 if (!m_ScriptInterface .GetProperty(m_ScriptInterface.GetGlobalObject(), "SharedScript", ctor)377 if (!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), "SharedScript", ctor) 449 378 || ctor.undefined()) 450 379 { 451 380 LOGERROR(L"Failed to create shared AI component: %ls: can't find constructor '%hs'", path.string().c_str(), "SharedScript"); … … 454 383 455 384 // Set up the data to pass as the constructor argument 456 385 CScriptVal settings; 457 m_ScriptInterface .Eval(L"({})", settings);386 m_ScriptInterface->Eval(L"({})", settings); 458 387 CScriptVal playersID; 459 m_ScriptInterface .Eval(L"({})", playersID);388 m_ScriptInterface->Eval(L"({})", playersID); 460 389 461 390 for (size_t i = 0; i < m_Players.size(); ++i) 462 391 { 463 jsval val = m_ScriptInterface .ToJSVal(m_ScriptInterface.GetContext(), m_Players[i]->m_Player);464 m_ScriptInterface .SetPropertyInt(playersID.get(), i, CScriptVal(val), true);392 jsval val = m_ScriptInterface->ToJSVal(m_ScriptInterface->GetContext(), m_Players[i]->m_Player); 393 m_ScriptInterface->SetPropertyInt(playersID.get(), i, CScriptVal(val), true); 465 394 } 466 395 467 m_ScriptInterface .SetProperty(settings.get(), "players", playersID);396 m_ScriptInterface->SetProperty(settings.get(), "players", playersID); 468 397 ENSURE(m_HasLoadedEntityTemplates); 469 m_ScriptInterface .SetProperty(settings.get(), "templates", m_EntityTemplates, false);398 m_ScriptInterface->SetProperty(settings.get(), "templates", m_EntityTemplates, false); 470 399 471 400 if (hasTechs) 472 401 { 473 m_ScriptInterface .SetProperty(settings.get(), "techTemplates", m_TechTemplates, false);402 m_ScriptInterface->SetProperty(settings.get(), "techTemplates", m_TechTemplates, false); 474 403 } 475 404 else 476 405 { 477 406 // won't get the tech templates directly. 478 407 CScriptVal fakeTech; 479 m_ScriptInterface .Eval("({})", fakeTech);480 m_ScriptInterface .SetProperty(settings.get(), "techTemplates", fakeTech, false);408 m_ScriptInterface->Eval("({})", fakeTech); 409 m_ScriptInterface->SetProperty(settings.get(), "techTemplates", fakeTech, false); 481 410 } 482 m_SharedAIObj = CScriptValRooted(m_ScriptInterface .GetContext(),m_ScriptInterface.CallConstructor(ctor.get(), settings.get()));411 m_SharedAIObj = CScriptValRooted(m_ScriptInterface->GetContext(),m_ScriptInterface->CallConstructor(ctor.get(), settings.get())); 483 412 484 413 485 414 if (m_SharedAIObj.undefined()) … … 493 422 494 423 bool AddPlayer(const std::wstring& aiName, player_id_t player, uint8_t difficulty, bool callConstructor) 495 424 { 496 shared_ptr<CAIPlayer> ai(new CAIPlayer(*this, aiName, player, difficulty, m_Script Runtime, m_RNG));425 shared_ptr<CAIPlayer> ai(new CAIPlayer(*this, aiName, player, difficulty, m_ScriptInterface)); 497 426 if (!ai->Initialise(callConstructor)) 498 427 return false; 499 428 … … 501 430 if (!m_HasSharedComponent) 502 431 m_HasSharedComponent = ai->m_UseSharedComponent; 503 432 504 m_ScriptInterface .MaybeGC();433 m_ScriptInterface->MaybeGC(); 505 434 506 435 m_Players.push_back(ai); 507 436 … … 513 442 // this will be run last by InitGame.Js, passing the full game representation. 514 443 // For now it will run for the shared Component. 515 444 // This is NOT run during deserialization. 516 CScriptVal state = m_ScriptInterface .ReadStructuredClone(gameState);517 JSContext* cx = m_ScriptInterface .GetContext();445 CScriptVal state = m_ScriptInterface->ReadStructuredClone(gameState); 446 JSContext* cx = m_ScriptInterface->GetContext(); 518 447 519 448 m_PassabilityMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, passabilityMap)); 520 449 m_TerritoryMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, territoryMap)); 521 450 if (m_HasSharedComponent) 522 451 { 523 m_ScriptInterface .SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true);524 m_ScriptInterface .SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true);452 m_ScriptInterface->SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true); 453 m_ScriptInterface->SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true); 525 454 526 m_ScriptInterface .CallFunctionVoid(m_SharedAIObj.get(), "init", state);527 m_ScriptInterface .MaybeGC();455 m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "init", state); 456 m_ScriptInterface->MaybeGC(); 528 457 529 458 for (size_t i = 0; i < m_Players.size(); ++i) 530 459 { … … 545 474 { 546 475 m_PassabilityMap = passabilityMap; 547 476 548 JSContext* cx = m_ScriptInterface .GetContext();477 JSContext* cx = m_ScriptInterface->GetContext(); 549 478 m_PassabilityMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_PassabilityMap)); 550 479 } 551 480 … … 553 482 { 554 483 m_TerritoryMap = territoryMap; 555 484 556 JSContext* cx = m_ScriptInterface .GetContext();485 JSContext* cx = m_ScriptInterface->GetContext(); 557 486 m_TerritoryMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_TerritoryMap)); 558 487 } 559 488 … … 583 512 } 584 513 585 514 void RegisterTechTemplates(const shared_ptr<ScriptInterface::StructuredClone>& techTemplates) { 586 JSContext* cx = m_ScriptInterface .GetContext();587 m_TechTemplates = CScriptValRooted(cx, m_ScriptInterface .ReadStructuredClone(techTemplates));515 JSContext* cx = m_ScriptInterface->GetContext(); 516 m_TechTemplates = CScriptValRooted(cx, m_ScriptInterface->ReadStructuredClone(techTemplates)); 588 517 } 589 518 590 519 void LoadEntityTemplates(const std::vector<std::pair<std::string, const CParamNode*> >& templates) 591 520 { 592 521 m_HasLoadedEntityTemplates = true; 593 522 594 m_ScriptInterface .Eval("({})", m_EntityTemplates);523 m_ScriptInterface->Eval("({})", m_EntityTemplates); 595 524 596 525 for (size_t i = 0; i < templates.size(); ++i) 597 526 { 598 jsval val = templates[i].second->ToJSVal(m_ScriptInterface .GetContext(), false);599 m_ScriptInterface .SetProperty(m_EntityTemplates.get(), templates[i].first.c_str(), CScriptVal(val), true);527 jsval val = templates[i].second->ToJSVal(m_ScriptInterface->GetContext(), false); 528 m_ScriptInterface->SetProperty(m_EntityTemplates.get(), templates[i].first.c_str(), CScriptVal(val), true); 600 529 } 601 530 602 531 // Since the template data is shared between AI players, freeze it 603 532 // to stop any of them changing it and confusing the other players 604 m_ScriptInterface .FreezeObject(m_EntityTemplates.get(), true);533 m_ScriptInterface->FreezeObject(m_EntityTemplates.get(), true); 605 534 } 606 535 607 536 void Serialize(std::ostream& stream, bool isDebug) … … 610 539 611 540 if (isDebug) 612 541 { 613 CDebugSerializer serializer( m_ScriptInterface, stream);542 CDebugSerializer serializer(*m_ScriptInterface, stream); 614 543 serializer.Indent(4); 615 544 SerializeState(serializer); 616 545 } 617 546 else 618 547 { 619 CStdSerializer serializer( m_ScriptInterface, stream);548 CStdSerializer serializer(*m_ScriptInterface, stream); 620 549 // TODO: see comment in Deserialize() 621 550 serializer.SetSerializablePrototypes(m_SerializablePrototypes); 622 551 SerializeState(serializer); … … 637 566 if (m_HasSharedComponent) 638 567 { 639 568 CScriptVal sharedData; 640 if (!m_ScriptInterface .CallFunction(m_SharedAIObj.get(), "Serialize", sharedData))569 if (!m_ScriptInterface->CallFunction(m_SharedAIObj.get(), "Serialize", sharedData)) 641 570 LOGERROR(L"AI shared script Serialize call failed"); 642 571 serializer.ScriptVal("sharedData", sharedData); 643 572 } … … 650 579 serializer.NumberU32_Unbounded("num commands", (u32)m_Players[i]->m_Commands.size()); 651 580 for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j) 652 581 { 653 CScriptVal val = m_ScriptInterface .ReadStructuredClone(m_Players[i]->m_Commands[j]);582 CScriptVal val = m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j]); 654 583 serializer.ScriptVal("command", val); 655 584 } 656 585 657 bool hasCustomSerialize = m_ScriptInterface .HasProperty(m_Players[i]->m_Obj.get(), "Serialize");586 bool hasCustomSerialize = m_ScriptInterface->HasProperty(m_Players[i]->m_Obj.get(), "Serialize"); 658 587 if (hasCustomSerialize) 659 588 { 660 589 CScriptVal scriptData; 661 if (!m_ScriptInterface .CallFunction(m_Players[i]->m_Obj.get(), "Serialize", scriptData))590 if (!m_ScriptInterface->CallFunction(m_Players[i]->m_Obj.get(), "Serialize", scriptData)) 662 591 LOGERROR(L"AI script Serialize call failed"); 663 592 serializer.ScriptVal("data", scriptData); 664 593 } … … 673 602 { 674 603 ENSURE(m_CommandsComputed); // deserializing while we're still actively computing would be bad 675 604 676 CStdDeserializer deserializer( m_ScriptInterface, stream);605 CStdDeserializer deserializer(*m_ScriptInterface, stream); 677 606 678 607 m_PlayerMetadata.clear(); 679 608 m_Players.clear(); … … 695 624 { 696 625 CScriptVal sharedData; 697 626 deserializer.ScriptVal("sharedData", sharedData); 698 if (!m_ScriptInterface .CallFunctionVoid(m_SharedAIObj.get(), "Deserialize", sharedData))627 if (!m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "Deserialize", sharedData)) 699 628 LOGERROR(L"AI shared script Deserialize call failed"); 700 629 } 701 630 … … 717 646 { 718 647 CScriptVal val; 719 648 deserializer.ScriptVal("command", val); 720 m_Players.back()->m_Commands.push_back(m_ScriptInterface .WriteStructuredClone(val.get()));649 m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val.get())); 721 650 } 722 651 723 652 // TODO: this is yucky but necessary while the AIs are sharing data between contexts; … … 726 655 // prototypes could be stored in their ScriptInterface 727 656 deserializer.SetSerializablePrototypes(m_DeserializablePrototypes); 728 657 729 bool hasCustomDeserialize = m_ScriptInterface .HasProperty(m_Players.back()->m_Obj.get(), "Deserialize");658 bool hasCustomDeserialize = m_ScriptInterface->HasProperty(m_Players.back()->m_Obj.get(), "Deserialize"); 730 659 if (hasCustomDeserialize) 731 660 { 732 661 CScriptVal scriptData; 733 662 deserializer.ScriptVal("data", scriptData); 734 663 if (m_Players[i]->m_UseSharedComponent) 735 664 { 736 if (!m_ScriptInterface .CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData, m_SharedAIObj))665 if (!m_ScriptInterface->CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData, m_SharedAIObj)) 737 666 LOGERROR(L"AI script Deserialize call failed"); 738 667 } 739 else if (!m_ScriptInterface .CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData))668 else if (!m_ScriptInterface->CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData)) 740 669 { 741 670 LOGERROR(L"AI script deserialize() call failed"); 742 671 } … … 770 699 if (m_PlayerMetadata.find(path) == m_PlayerMetadata.end()) 771 700 { 772 701 // Load and cache the AI player metadata 773 m_PlayerMetadata[path] = m_ScriptInterface .ReadJSONFile(path);702 m_PlayerMetadata[path] = m_ScriptInterface->ReadJSONFile(path); 774 703 } 775 704 776 705 return m_PlayerMetadata[path]; … … 786 715 if (m_TurnNum++ % 50 == 0) 787 716 { 788 717 PROFILE3("AI compute GC"); 789 m_ScriptInterface .MaybeGC();718 m_ScriptInterface->MaybeGC(); 790 719 } 791 720 return; 792 721 } … … 795 724 CScriptVal state; 796 725 { 797 726 PROFILE3("AI compute read state"); 798 state = m_ScriptInterface .ReadStructuredClone(m_GameState);799 m_ScriptInterface .SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true);800 m_ScriptInterface .SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true);727 state = m_ScriptInterface->ReadStructuredClone(m_GameState); 728 m_ScriptInterface->SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true); 729 m_ScriptInterface->SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true); 801 730 } 802 731 803 732 // It would be nice to do 804 // m_ScriptInterface .FreezeObject(state.get(), true);733 // m_ScriptInterface->FreezeObject(state.get(), true); 805 734 // to prevent AI scripts accidentally modifying the state and 806 735 // affecting other AI scripts they share it with. But the performance 807 736 // cost is far too high, so we won't do that. … … 810 739 if (m_HasSharedComponent) 811 740 { 812 741 PROFILE3("AI run shared component"); 813 m_ScriptInterface .CallFunctionVoid(m_SharedAIObj.get(), "onUpdate", state);742 m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "onUpdate", state); 814 743 } 815 744 816 745 for (size_t i = 0; i < m_Players.size(); ++i) … … 818 747 PROFILE3("AI script"); 819 748 PROFILE2_ATTR("player: %d", m_Players[i]->m_Player); 820 749 PROFILE2_ATTR("script: %ls", m_Players[i]->m_AIName.c_str()); 750 821 751 if (m_HasSharedComponent && m_Players[i]->m_UseSharedComponent) 822 m_Players[i]->Run(state, m_SharedAIObj);752 m_Players[i]->Run(state, m_Players[i]->m_Player, m_SharedAIObj); 823 753 else 824 m_Players[i]->Run(state );754 m_Players[i]->Run(state, m_Players[i]->m_Player); 825 755 } 826 756 827 757 // Run GC if we are about to overflow 828 if (JS_GetGCParameter(m_ScriptInterface .GetRuntime(), JSGC_BYTES) > 33000000)758 if (JS_GetGCParameter(m_ScriptInterface->GetRuntime(), JSGC_BYTES) > 33000000) 829 759 { 830 760 PROFILE3("AI compute GC"); 831 761 832 JS_GC(m_ScriptInterface .GetContext());762 JS_GC(m_ScriptInterface->GetContext()); 833 763 } 834 764 835 765 // Run the GC every so often. … … 838 768 /*if (m_TurnNum++ % 20 == 0) 839 769 { 840 770 PROFILE3("AI compute GC"); 841 m_ScriptInterface .MaybeGC();771 m_ScriptInterface->MaybeGC(); 842 772 }*/ 843 773 } 844 774 845 775 shared_ptr<ScriptRuntime> m_ScriptRuntime; 846 ScriptInterfacem_ScriptInterface;776 shared_ptr<ScriptInterface> m_ScriptInterface; 847 777 boost::rand48 m_RNG; 848 778 u32 m_TurnNum; 849 779 … … 858 788 CScriptValRooted m_SharedAIObj; 859 789 std::vector<SCommandSets> m_Commands; 860 790 791 std::set<std::wstring> m_LoadedModules; 792 861 793 shared_ptr<ScriptInterface::StructuredClone> m_GameState; 862 794 Grid<u16> m_PassabilityMap; 863 795 CScriptValRooted m_PassabilityMapVal; -
binaries/data/mods/public/simulation/ai/common-api-v2/base.js
1 var PlayerID = -1; 2 1 3 function BaseAI(settings) 2 4 { 3 5 if (!settings) … … 112 114 return null; 113 115 }; 114 116 115 BaseAI.prototype.HandleMessage = function(state )117 BaseAI.prototype.HandleMessage = function(state, playerID) 116 118 { 119 PlayerID = playerID; 117 120 if (!this._entities) 118 121 { 119 122 // Do a (shallow) clone of all the initial entity properties (in order … … 237 240 238 241 BaseAI.prototype.chat = function(message) 239 242 { 240 Engine.PostCommand( {"type": "chat", "message": message});243 Engine.PostCommand(PlayerID, {"type": "chat", "message": message}); 241 244 }; 242 245 243 246 BaseAI.prototype.registerUpdatingEntityCollection = function(entCollection) -
binaries/data/mods/public/simulation/ai/common-api-v2/entity.js
372 372 373 373 move: function(x, z, queued) { 374 374 queued = queued || false; 375 Engine.PostCommand( {"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued});375 Engine.PostCommand(PlayerID, {"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued}); 376 376 return this; 377 377 }, 378 378 379 379 garrison: function(target) { 380 Engine.PostCommand( {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false});380 Engine.PostCommand(PlayerID, {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false}); 381 381 return this; 382 382 }, 383 383 384 384 attack: function(unitId) { 385 Engine.PostCommand( {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false});385 Engine.PostCommand(PlayerID, {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false}); 386 386 return this; 387 387 }, 388 388 389 389 gather: function(target, queued) { 390 390 queued = queued || false; 391 Engine.PostCommand( {"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued});391 Engine.PostCommand(PlayerID, {"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued}); 392 392 return this; 393 393 }, 394 394 395 395 repair: function(target, queued) { 396 396 queued = queued || false; 397 Engine.PostCommand( {"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued});397 Engine.PostCommand(PlayerID, {"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued}); 398 398 return this; 399 399 }, 400 400 401 401 returnResources: function(target, queued) { 402 402 queued = queued || false; 403 Engine.PostCommand( {"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued});403 Engine.PostCommand(PlayerID, {"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued}); 404 404 return this; 405 405 }, 406 406 407 407 destroy: function() { 408 Engine.PostCommand( {"type": "delete-entities", "entities": [this.id()]});408 Engine.PostCommand(PlayerID, {"type": "delete-entities", "entities": [this.id()]}); 409 409 return this; 410 410 }, 411 411 … … 423 423 return this; 424 424 } 425 425 426 Engine.PostCommand( {426 Engine.PostCommand(PlayerID, { 427 427 "type": "train", 428 428 "entities": [this.id()], 429 429 "template": type, … … 437 437 // TODO: verify this unit can construct this, just for internal 438 438 // sanity-checking and error reporting 439 439 440 Engine.PostCommand( {440 Engine.PostCommand(PlayerID, { 441 441 "type": "construct", 442 442 "entities": [this.id()], 443 443 "template": template, -
binaries/data/mods/public/simulation/ai/common-api-v2/entitycollection.js
109 109 EntityCollection.prototype.move = function(x, z, queued) 110 110 { 111 111 queued = queued || false; 112 Engine.PostCommand( {"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued});112 Engine.PostCommand(PlayerID, {"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued}); 113 113 return this; 114 114 }; 115 115 116 116 EntityCollection.prototype.destroy = function() 117 117 { 118 Engine.PostCommand( {"type": "delete-entities", "entities": this.toIdArray()});118 Engine.PostCommand(PlayerID, {"type": "delete-entities", "entities": this.toIdArray()}); 119 119 return this; 120 120 }; 121 121 -
binaries/data/mods/public/simulation/ai/common-api-v3/map-module.js
2 2 * Copied with changes from QuantumState's original for qBot, it's a component for storing 8 bit values. 3 3 */ 4 4 5 const TERRITORY_PLAYER_MASK = 0x3F;6 7 5 function Map(sharedScript, originalMap, actualCopy){ 8 6 // get the map to find out the correct dimensions 9 7 var gameMap = sharedScript.passabilityMap; -
binaries/data/mods/public/simulation/ai/common-api-v3/entity.js
584 584 585 585 move: function(x, z, queued) { 586 586 queued = queued || false; 587 Engine.PostCommand( {"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });587 Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued }); 588 588 return this; 589 589 }, 590 590 591 591 attackMove: function(x, z, queued) { 592 592 queued = queued || false; 593 Engine.PostCommand( {"type": "attack-walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });593 Engine.PostCommand(PlayerID,{"type": "attack-walk", "entities": [this.id()], "x": x, "z": z, "queued": queued }); 594 594 return this; 595 595 }, 596 596 597 597 // violent, aggressive, defensive, passive, standground 598 598 setStance: function(stance,queued){ 599 Engine.PostCommand( {"type": "stance", "entities": [this.id()], "name" : stance, "queued": queued });599 Engine.PostCommand(PlayerID,{"type": "stance", "entities": [this.id()], "name" : stance, "queued": queued }); 600 600 return this; 601 601 }, 602 602 603 603 // TODO: replace this with the proper "STOP" command 604 604 stopMoving: function() { 605 605 if (this.position() !== undefined) 606 Engine.PostCommand( {"type": "walk", "entities": [this.id()], "x": this.position()[0], "z": this.position()[1], "queued": false});606 Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": this.position()[0], "z": this.position()[1], "queued": false}); 607 607 }, 608 608 609 609 unload: function(id) { 610 610 if (!this._template.GarrisonHolder) 611 611 return undefined; 612 Engine.PostCommand( {"type": "unload", "garrisonHolder": this.id(), "entities": [id]});612 Engine.PostCommand(PlayerID,{"type": "unload", "garrisonHolder": this.id(), "entities": [id]}); 613 613 return this; 614 614 }, 615 615 … … 617 617 unloadAll: function() { 618 618 if (!this._template.GarrisonHolder) 619 619 return undefined; 620 Engine.PostCommand( {"type": "unload-all-own", "garrisonHolders": [this.id()]});620 Engine.PostCommand(PlayerID,{"type": "unload-all-own", "garrisonHolders": [this.id()]}); 621 621 return this; 622 622 }, 623 623 624 624 garrison: function(target) { 625 Engine.PostCommand( {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false});625 Engine.PostCommand(PlayerID,{"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false}); 626 626 return this; 627 627 }, 628 628 629 629 attack: function(unitId) { 630 Engine.PostCommand( {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false});630 Engine.PostCommand(PlayerID,{"type": "attack", "entities": [this.id()], "target": unitId, "queued": false}); 631 631 return this; 632 632 }, 633 633 … … 639 639 FleeDirection[0] = (FleeDirection[0]/dist) * 8; 640 640 FleeDirection[1] = (FleeDirection[1]/dist) * 8; 641 641 642 Engine.PostCommand( {"type": "walk", "entities": [this.id()], "x": this.position()[0] + FleeDirection[0]*5, "z": this.position()[1] + FleeDirection[1]*5, "queued": false});642 Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": this.position()[0] + FleeDirection[0]*5, "z": this.position()[1] + FleeDirection[1]*5, "queued": false}); 643 643 } 644 644 return this; 645 645 }, 646 646 647 647 gather: function(target, queued) { 648 648 queued = queued || false; 649 Engine.PostCommand( {"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued});649 Engine.PostCommand(PlayerID,{"type": "gather", "entities": [this.id()], "target": target.id(), "queued": queued}); 650 650 return this; 651 651 }, 652 652 653 653 repair: function(target, queued) { 654 654 queued = queued || false; 655 Engine.PostCommand( {"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued});655 Engine.PostCommand(PlayerID,{"type": "repair", "entities": [this.id()], "target": target.id(), "autocontinue": false, "queued": queued}); 656 656 return this; 657 657 }, 658 658 659 659 returnResources: function(target, queued) { 660 660 queued = queued || false; 661 Engine.PostCommand( {"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued});661 Engine.PostCommand(PlayerID,{"type": "returnresource", "entities": [this.id()], "target": target.id(), "queued": queued}); 662 662 return this; 663 663 }, 664 664 665 665 destroy: function() { 666 Engine.PostCommand( {"type": "delete-entities", "entities": [this.id()] });666 Engine.PostCommand(PlayerID,{"type": "delete-entities", "entities": [this.id()] }); 667 667 return this; 668 668 }, 669 669 670 670 barter: function(buyType, sellType, amount) { 671 Engine.PostCommand( {"type": "barter", "sell" : sellType, "buy" : buyType, "amount" : amount });671 Engine.PostCommand(PlayerID,{"type": "barter", "sell" : sellType, "buy" : buyType, "amount" : amount }); 672 672 return this; 673 673 }, 674 674 … … 686 686 return this; 687 687 } 688 688 689 Engine.PostCommand( {689 Engine.PostCommand(PlayerID,{ 690 690 "type": "train", 691 691 "entities": [this.id()], 692 692 "template": type, … … 699 699 construct: function(template, x, z, angle, metadata) { 700 700 // TODO: verify this unit can construct this, just for internal 701 701 // sanity-checking and error reporting 702 703 Engine.PostCommand({ 702 Engine.PostCommand(PlayerID,{ 704 703 "type": "construct", 705 704 "entities": [this.id()], 706 705 "template": template, … … 716 715 }, 717 716 718 717 research: function(template) { 719 Engine.PostCommand( { "type": "research", "entity": this.id(), "template": template });718 Engine.PostCommand(PlayerID,{ "type": "research", "entity": this.id(), "template": template }); 720 719 return this; 721 720 }, 722 721 723 722 stopProduction: function(id) { 724 Engine.PostCommand( { "type": "stop-production", "entity": this.id(), "id": id });723 Engine.PostCommand(PlayerID,{ "type": "stop-production", "entity": this.id(), "id": id }); 725 724 return this; 726 725 }, 727 726 … … 732 731 for (var i in queue) 733 732 { 734 733 if (queue[i].progress < percentToStopAt) 735 Engine.PostCommand( { "type": "stop-production", "entity": this.id(), "id": queue[i].id });734 Engine.PostCommand(PlayerID,{ "type": "stop-production", "entity": this.id(), "id": queue[i].id }); 736 735 } 737 736 return this; 738 737 } -
binaries/data/mods/public/simulation/ai/common-api-v3/entitycollection.js
188 188 EntityCollection.prototype.move = function(x, z, queued) 189 189 { 190 190 queued = queued || false; 191 Engine.PostCommand( {"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued});191 Engine.PostCommand(PlayerID,{"type": "walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued}); 192 192 return this; 193 193 }; 194 194 EntityCollection.prototype.attackMove = function(x, z, queued) 195 195 { 196 196 queued = queued || false; 197 Engine.PostCommand( {"type": "attack-walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued});197 Engine.PostCommand(PlayerID,{"type": "attack-walk", "entities": this.toIdArray(), "x": x, "z": z, "queued": queued}); 198 198 return this; 199 199 }; 200 200 EntityCollection.prototype.moveIndiv = function(x, z, queued) … … 206 206 // It disables JIT compiling of this loop. Don't remove it unless you are sure that the underlying issue has been resolved! 207 207 // TODO: Check this again after the SpiderMonkey upgrade. 208 208 try {} finally {} 209 Engine.PostCommand( {"type": "walk", "entities": [this._entities[id].id()], "x": x, "z": z, "queued": queued});209 Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this._entities[id].id()], "x": x, "z": z, "queued": queued}); 210 210 } 211 211 return this; 212 212 }; 213 213 EntityCollection.prototype.destroy = function() 214 214 { 215 Engine.PostCommand( {"type": "delete-entities", "entities": this.toIdArray()});215 Engine.PostCommand(PlayerID,{"type": "delete-entities", "entities": this.toIdArray()}); 216 216 return this; 217 217 }; 218 218 EntityCollection.prototype.attack = function(unit) … … 226 226 { 227 227 unitId = unit; 228 228 } 229 Engine.PostCommand( {"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false});229 Engine.PostCommand(PlayerID,{"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false}); 230 230 return this; 231 231 }; 232 232 // violent, aggressive, defensive, passive, standground 233 233 EntityCollection.prototype.setStance = function(stance) 234 234 { 235 Engine.PostCommand( {"type": "stance", "entities": this.toIdArray(), "name" : stance, "queued": false});235 Engine.PostCommand(PlayerID,{"type": "stance", "entities": this.toIdArray(), "name" : stance, "queued": false}); 236 236 return this; 237 237 }; 238 238 -
binaries/data/mods/public/simulation/ai/common-api-v3/baseAI.js
6 6 return; 7 7 8 8 this.player = settings.player; 9 PlayerID = this.player;10 9 11 10 // played turn, in case you don't want the AI to play every turn. 12 11 this.turn = 0; … … 29 28 this.isDeserialized = true; 30 29 }; 31 30 32 BaseAI.prototype.Init = function(state, sharedAI)31 BaseAI.prototype.Init = function(state, playerID, sharedAI) 33 32 { 33 PlayerID = playerID; 34 34 // define some references 35 35 this.entities = sharedAI.entities; 36 36 this.templates = sharedAI.templates; … … 43 43 this.techModifications = sharedAI._techModifications[this.player]; 44 44 this.playerData = sharedAI.playersData[this.player]; 45 45 46 this.gameState = sharedAI.gameState[ PlayerID];46 this.gameState = sharedAI.gameState[this.player]; 47 47 this.gameState.ai = this; 48 48 this.sharedScript = sharedAI; 49 49 … … 56 56 { // AIs override this function 57 57 }; 58 58 59 BaseAI.prototype.HandleMessage = function(state, sharedAI)59 BaseAI.prototype.HandleMessage = function(state, playerID, sharedAI) 60 60 { 61 61 this.events = sharedAI.events; 62 PlayerID = playerID; 62 63 63 64 if (this.isDeserialized && this.turn !== 0) 64 65 { … … 76 77 77 78 BaseAI.prototype.chat = function(message) 78 79 { 79 Engine.PostCommand( {"type": "chat", "message": message});80 Engine.PostCommand(PlayerID,{"type": "chat", "message": message}); 80 81 }; 81 82 BaseAI.prototype.chatTeam = function(message) 82 83 { 83 Engine.PostCommand( {"type": "chat", "message": "/team " +message});84 Engine.PostCommand(PlayerID,{"type": "chat", "message": "/team " +message}); 84 85 }; 85 86 BaseAI.prototype.chatEnemies = function(message) 86 87 { 87 Engine.PostCommand( {"type": "chat", "message": "/enemy " +message});88 Engine.PostCommand(PlayerID,{"type": "chat", "message": "/enemy " +message}); 88 89 }; 89 90 -
binaries/data/mods/public/simulation/ai/aegis/headquarters.js
12 12 -picking new CC locations. 13 13 */ 14 14 15 var HQ = function() { 16 this.targetNumBuilders = Config.Economy.targetNumBuilders; // number of workers we want building stuff 15 var HQ = function(Config) { 17 16 18 this. dockStartTime = Config.Economy.dockStartTime * 1000;19 this.t echStartTime = Config.Economy.techStartTime * 1000;17 this.Config = Config; 18 this.targetNumBuilders = this.Config.Economy.targetNumBuilders; // number of workers we want building stuff 20 19 20 this.dockStartTime = this.Config.Economy.dockStartTime * 1000; 21 this.techStartTime = this.Config.Economy.techStartTime * 1000; 22 21 23 this.dockFailed = false; // sanity check 22 24 this.waterMap = false; // set by the aegis.js file. 23 25 … … 27 29 this.baseManagers = {}; 28 30 29 31 // this means we'll have about a big third of women, and thus we can maximize resource gathering rates. 30 this.femaleRatio = Config.Economy.femaleRatio;32 this.femaleRatio = this.Config.Economy.femaleRatio; 31 33 32 34 this.fortressStartTime = 0; 33 this.fortressLapseTime = Config.Military.fortressLapseTime * 1000;34 this.defenceBuildingTime = Config.Military.defenceBuildingTime * 1000;35 this.attackPlansStartTime = Config.Military.attackPlansStartTime * 1000;36 this.defenceManager = new Defence( );35 this.fortressLapseTime = this.Config.Military.fortressLapseTime * 1000; 36 this.defenceBuildingTime = this.Config.Military.defenceBuildingTime * 1000; 37 this.attackPlansStartTime = this.Config.Military.attackPlansStartTime * 1000; 38 this.defenceManager = new Defence(this.Config); 37 39 38 40 this.navalManager = new NavalManager(); 39 41 … … 48 50 this.basesMap = new Map(gameState.sharedScript, new Uint8Array(gameState.getMap().data.length)); 49 51 this.basesMap.setMaxVal(255); 50 52 51 if ( Config.Economy.targetNumWorkers)52 this.targetNumWorkers = Config.Economy.targetNumWorkers;53 if (this.Config.Economy.targetNumWorkers) 54 this.targetNumWorkers = this.Config.Economy.targetNumWorkers; 53 55 else if (this.targetNumWorkers === undefined) 54 this.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*(0.2 + Math.min(+( Config.difficulty)*0.125,0.3))), 1);56 this.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*(0.2 + Math.min(+(this.Config.difficulty)*0.125,0.3))), 1); 55 57 56 58 57 59 // Let's get our initial situation here. … … 79 81 if (ent.resourceSupplyType().generic === "treasure" && SquareVectorDistance(ent.position(), CC.position()) < 5000) 80 82 treasureAmount[i] += ent.resourceSupplyMax(); 81 83 }); 82 this.baseManagers[1] = new BaseManager( );84 this.baseManagers[1] = new BaseManager(this.Config); 83 85 this.baseManagers[1].init(gameState, events); 84 86 this.baseManagers[1].setAnchor(CC); 85 87 this.baseManagers[1].initTerritory(this, gameState); 86 88 this.baseManagers[1].initGatheringFunctions(this, gameState); 87 89 88 if ( Config.debug)90 if (this.Config.debug) 89 91 this.basesMap.dumpIm("basesMap.png"); 90 92 var self = this; 91 93 … … 112 114 } 113 115 114 116 var map = new Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps["wood"].map); 115 if ( Config.debug)117 if (this.Config.debug) 116 118 map.dumpIm("map_CC_Wood.png"); 117 119 118 120 //this.reassignIdleWorkers(gameState); … … 125 127 126 128 // load units and buildings from the config files 127 129 128 if (civ in Config.buildings.moderate){129 this.bModerate = Config.buildings.moderate[civ];130 if (civ in this.Config.buildings.moderate){ 131 this.bModerate = this.Config.buildings.moderate[civ]; 130 132 }else{ 131 this.bModerate = Config.buildings.moderate['default'];133 this.bModerate = this.Config.buildings.moderate['default']; 132 134 } 133 135 134 if (civ in Config.buildings.advanced){135 this.bAdvanced = Config.buildings.advanced[civ];136 if (civ in this.Config.buildings.advanced){ 137 this.bAdvanced = this.Config.buildings.advanced[civ]; 136 138 }else{ 137 this.bAdvanced = Config.buildings.advanced['default'];139 this.bAdvanced = this.Config.buildings.advanced['default']; 138 140 } 139 141 140 if (civ in Config.buildings.fort){141 this.bFort = Config.buildings.fort[civ];142 if (civ in this.Config.buildings.fort){ 143 this.bFort = this.Config.buildings.fort[civ]; 142 144 }else{ 143 this.bFort = Config.buildings.fort['default'];145 this.bFort = this.Config.buildings.fort['default']; 144 146 } 145 147 146 148 for (var i in this.bAdvanced){ … … 193 195 if (ent.isOwn(PlayerID) && ent.getMetadata(PlayerID, "base") === -1) 194 196 { 195 197 // Okay so let's try to create a new base around this. 196 var bID = uniqueIDBases;197 this.baseManagers[bID] = new BaseManager( );198 var bID = playerGlobals[PlayerID].uniqueIDBases; 199 this.baseManagers[bID] = new BaseManager(this.Config); 198 200 this.baseManagers[bID].init(gameState, events, true); 199 201 this.baseManagers[bID].setAnchor(ent); 200 202 this.baseManagers[bID].initTerritory(this, gameState); … … 411 413 // TODO: improve choice alogrithm 412 414 HQ.prototype.switchWorkerBase = function(gameState, worker, type) { 413 415 var bestBase = 0; 416 414 417 for (var i in this.baseManagers) 415 418 { 416 419 if (this.baseManagers[i].willGather[type] >= 1) … … 645 648 var best = friendlyTiles.findBestTile(6, obstructions); 646 649 var bestIdx = best[0]; 647 650 648 if ( Config.debug)651 if (this.Config.debug) 649 652 { 650 653 friendlyTiles.map[bestIdx] = 270; 651 654 friendlyTiles.dumpIm("cc_placement_base_" + gameState.getTimeElapsed() + "_" + resource + "_" + best[1] + ".png",301); … … 674 677 }; 675 678 676 679 HQ.prototype.buildMarket = function(gameState, queues){ 677 if (gameState.getPopulation() > Config.Economy.popForMarket && gameState.currentPhase() >= 2 ) {680 if (gameState.getPopulation() > this.Config.Economy.popForMarket && gameState.currentPhase() >= 2 ) { 678 681 if (queues.economicBuilding.countQueuedUnitsWithClass("BarterMarket") === 0 && 679 682 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_market")) === 0){ 680 683 //only ever build one storehouse/CC/market at a time … … 685 688 686 689 // Build a farmstead to go to town phase faster and prepare for research. Only really active on higher diff mode. 687 690 HQ.prototype.buildFarmstead = function(gameState, queues){ 688 if (gameState.getPopulation() > Config.Economy.popForFarmstead) {691 if (gameState.getPopulation() > this.Config.Economy.popForFarmstead) { 689 692 // achtung: "DropsiteFood" does not refer to CCs. 690 693 if (queues.economicBuilding.countQueuedUnitsWithClass("DropsiteFood") === 0 && 691 694 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_farmstead")) === 0){ … … 752 755 if (numPlanned < 3 || (numPlanned < 5 && gameState.getPopulation() > 80)) 753 756 { 754 757 var plan = new ConstructionPlan(gameState, "structures/{civ}_house", { "base" : 1 }); 758 // make the difficulty available to the isGo function without having to pass it as argument 759 var difficulty = this.Config.difficulty; 755 760 // change the starting condition to "less than 15 slots left". 756 761 plan.isGo = function (gameState) { 757 762 var HouseNb = gameState.countEntitiesByType(gameState.applyCiv("foundation|structures/{civ}_house"), true); … … 761 766 freeSlots = gameState.getPopulationLimit() + HouseNb*5 - gameState.getPopulation(); 762 767 else 763 768 freeSlots = gameState.getPopulationLimit() + HouseNb*10 - gameState.getPopulation(); 764 if (gameState.getPopulation() > 55 && Config.difficulty > 1)769 if (gameState.getPopulation() > 55 && difficulty > 1) 765 770 return (freeSlots <= 21); 766 else if (gameState.getPopulation() >= 20 && Config.difficulty !== 0)771 else if (gameState.getPopulation() >= 20 && difficulty !== 0) 767 772 return (freeSlots <= 16); 768 773 else 769 774 return (freeSlots <= 10); … … 781 786 var capacity = { "wood" : 0, "stone" : 0, "metal" : 0 } 782 787 var need = { "wood" : true, "stone" : true, "metal" : true }; 783 788 var posss = []; 789 784 790 for (i in this.baseManagers) 785 791 { 786 792 var base = this.baseManagers[i]; 787 793 for (type in count) 788 794 { 789 if (base.getResourceLevel(gameState, type, "all") > 1500*Math.max( Config.difficulty,2))795 if (base.getResourceLevel(gameState, type, "all") > 1500*Math.max(this.Config.difficulty,2)) 790 796 count[type]++; 791 797 capacity[type] += base.getWorkerCapacity(gameState, type); 792 798 if (base.willGather[type] !== 2) … … 878 884 }; 879 885 880 886 HQ.prototype.buildBlacksmith = function(gameState, queues){ 881 if (gameState.getTimeElapsed() > Config.Military.timeForBlacksmith*1000) {887 if (gameState.getTimeElapsed() > this.Config.Military.timeForBlacksmith*1000) { 882 888 if (queues.militaryBuilding.length() === 0 && 883 889 gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_blacksmith")) === 0) { 884 890 var tp = gameState.getTemplate(gameState.applyCiv("structures/{civ}_blacksmith")); … … 896 902 Engine.ProfileStart("Build buildings"); 897 903 var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(Filters.not(Filters.byHasMetadata(PlayerID, "plan"))).length; 898 904 899 if (workersNumber > Config.Military.popForBarracks1) {905 if (workersNumber > this.Config.Military.popForBarracks1) { 900 906 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) + queues.militaryBuilding.length() < 1) { 901 907 debug ("Trying to build barracks"); 902 908 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); 903 909 } 904 910 } 905 911 906 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 2 && workersNumber > Config.Military.popForBarracks2)912 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) < 2 && workersNumber > this.Config.Military.popForBarracks2) 907 913 if (queues.militaryBuilding.length() < 1) 908 914 queues.militaryBuilding.addItem(new ConstructionPlan(gameState, this.bModerate[0], { "base" : 1 })); 909 915 … … 917 923 } 918 924 } 919 925 //build advanced military buildings 920 if (workersNumber >= Config.Military.popForBarracks2 - 15 && gameState.currentPhase() > 2){926 if (workersNumber >= this.Config.Military.popForBarracks2 - 15 && gameState.currentPhase() > 2){ 921 927 if (queues.militaryBuilding.length() === 0){ 922 928 var inConst = 0; 923 929 for (var i in this.bAdvanced) … … 1047 1053 1048 1054 // Some functions are run every turn 1049 1055 // Others once in a while 1050 HQ.prototype.update = function(gameState, queues, events) { 1056 HQ.prototype.update = function(gameState, queues, events) { 1051 1057 Engine.ProfileStart("Headquarters update"); 1052 1058 1053 1059 this.checkEvents(gameState,events,queues); … … 1057 1063 this.trainMoreWorkers(gameState, queues); 1058 1064 1059 1065 // sandbox doesn't expand. 1060 if ( Config.difficulty !== 0)1066 if (this.Config.difficulty !== 0) 1061 1067 this.checkBasesRessLevel(gameState, queues); 1062 1068 1063 1069 this.buildMoreHouses(gameState,queues); … … 1065 1071 if (gameState.getTimeElapsed() > this.techStartTime && gameState.currentPhase() > 2) 1066 1072 this.tryResearchTechs(gameState,queues); 1067 1073 1068 if ( Config.difficulty > 1)1074 if (this.Config.difficulty > 1) 1069 1075 this.tryBartering(gameState); 1070 1076 1071 1077 this.buildFarmstead(gameState, queues); … … 1087 1093 for (i in this.baseManagers) 1088 1094 { 1089 1095 this.baseManagers[i].checkEvents(gameState, events, queues) 1090 if ( ( (+i + gameState.ai.playedTurn) % ( uniqueIDBases - 1)) === 0)1096 if ( ( (+i + gameState.ai.playedTurn) % (playerGlobals[PlayerID].uniqueIDBases - 1)) === 0) 1091 1097 this.baseManagers[i].update(gameState, queues, events); 1092 1098 } 1093 1099 … … 1174 1180 if (gameState.ai.strategy === "rush" && this.startedAttacks["CityAttack"].length !== 0) { 1175 1181 // and then we revert. 1176 1182 gameState.ai.strategy = "normal"; 1177 Config.Economy.femaleRatio = 0.4;1183 this.Config.Economy.femaleRatio = 0.4; 1178 1184 gameState.ai.modules.economy.targetNumWorkers = Math.max(Math.floor(gameState.getPopulationMax()*0.55), 1); 1179 1185 } else if (gameState.ai.strategy === "rush" && this.upcomingAttacks["CityAttack"].length === 0) 1180 1186 { 1181 Lalala = new CityAttack(gameState, this, this.TotalAttackNumber, -1, "rush")1187 Lalala = new CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1, "rush") 1182 1188 this.TotalAttackNumber++; 1183 1189 this.upcomingAttacks["CityAttack"].push(Lalala); 1184 1190 debug ("Starting a little something"); … … 1193 1199 } else { 1194 1200 // basically only the first plan, really. 1195 1201 if (this.upcomingAttacks["CityAttack"].length == 0 && gameState.getTimeElapsed() < 12*60000) { 1196 var Lalala = new CityAttack(gameState, this, this.TotalAttackNumber, -1);1202 var Lalala = new CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1); 1197 1203 if (Lalala.failed) 1198 1204 { 1199 1205 this.attackPlansEncounteredWater = true; // hack … … 1202 1208 this.TotalAttackNumber++; 1203 1209 this.upcomingAttacks["CityAttack"].push(Lalala); 1204 1210 } 1205 } else if (this.upcomingAttacks["CityAttack"].length == 0 && Config.difficulty !== 0) {1206 var Lalala = new CityAttack(gameState, this, this.TotalAttackNumber, -1, "superSized");1211 } else if (this.upcomingAttacks["CityAttack"].length == 0 && this.Config.difficulty !== 0) { 1212 var Lalala = new CityAttack(gameState, this, this.Config, this.TotalAttackNumber, -1, "superSized"); 1207 1213 if (Lalala.failed) 1208 1214 { 1209 1215 this.attackPlansEncounteredWater = true; // hack … … 1243 1249 this.buildDropsites(gameState, queues); 1244 1250 Engine.ProfileStop(); 1245 1251 1246 if ( Config.difficulty !== 0)1252 if (this.Config.difficulty !== 0) 1247 1253 this.tryBartering(gameState); 1248 1254 1249 1255 this.buildFarmstead(gameState, queues); -
binaries/data/mods/public/simulation/ai/aegis/worker.js
199 199 }; 200 200 201 201 Worker.prototype.startGathering = function(baseManager, gameState) { 202 202 203 var resource = this.ent.getMetadata(PlayerID, "gather-type"); 203 204 var ent = this.ent; 204 205 var self = this; … … 254 255 } 255 256 }); 256 257 } 258 257 259 // we've found no fitting dropsites close enough from us. 258 260 // So'll try with far away. 259 261 if (!nearestResources || nearestResources.length === 0) { … … 271 273 } 272 274 }); 273 275 } 274 276 275 277 if (!nearestResources || nearestResources.length === 0){ 276 278 if (resource === "food") 277 279 if (this.buildAnyField(gameState)) -
binaries/data/mods/public/simulation/ai/aegis/base-manager.js
10 10 -updating whatever needs updating, keeping track of stuffs (rebuilding needs…) 11 11 */ 12 12 13 var BaseManager = function() { 13 var BaseManager = function(Config) { 14 this.Config = Config; 14 15 this.farmingFields = false; 15 this.ID = uniqueIDBases++;16 this.ID = playerGlobals[PlayerID].uniqueIDBases++; 16 17 17 18 // anchor building: seen as the main building of the base. Needs to have territorial influence 18 19 this.anchor = undefined; … … 318 319 // TODO: get workers on those resources and do something with them. 319 320 } 320 321 321 if ( Config.debug)322 if (this.Config.debug) 322 323 { 323 324 // Make resources glow wildly 324 325 if (type == "food") { 325 326 self.dropsites[ent.id()][type][2].forEach(function(ent){ 326 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0,0]});327 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0,0]}); 327 328 }); 328 329 self.dropsites[ent.id()][type][1].forEach(function(ent){ 329 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,0,0]});330 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,0,0]}); 330 331 }); 331 332 self.dropsites[ent.id()][type][0].forEach(function(ent){ 332 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]});333 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]}); 333 334 }); 334 335 } 335 336 if (type == "wood") { 336 337 self.dropsites[ent.id()][type][2].forEach(function(ent){ 337 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0]});338 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0]}); 338 339 }); 339 340 self.dropsites[ent.id()][type][1].forEach(function(ent){ 340 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,0]});341 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,0]}); 341 342 }); 342 343 self.dropsites[ent.id()][type][0].forEach(function(ent){ 343 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]});344 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]}); 344 345 }); 345 346 } 346 347 if (type == "stone") { 347 348 self.dropsites[ent.id()][type][2].forEach(function(ent){ 348 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0.5,0]});349 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0.5,0.5,0]}); 349 350 }); 350 351 self.dropsites[ent.id()][type][1].forEach(function(ent){ 351 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,2,0]});352 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,2,0]}); 352 353 }); 353 354 self.dropsites[ent.id()][type][0].forEach(function(ent){ 354 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,10,0]});355 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,10,0]}); 355 356 }); 356 357 } 357 358 if (type == "metal") { 358 359 self.dropsites[ent.id()][type][2].forEach(function(ent){ 359 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0.5]});360 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0.5,0.5]}); 360 361 }); 361 362 self.dropsites[ent.id()][type][1].forEach(function(ent){ 362 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,2]});363 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,2,2]}); 363 364 }); 364 365 self.dropsites[ent.id()][type][0].forEach(function(ent){ 365 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,10]});366 Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,10]}); 366 367 }); 367 368 } 368 369 } … … 452 453 } 453 454 } 454 455 455 if ( Config.debug)456 if (this.Config.debug) 456 457 friendlyTiles.dumpIm("DP_" + resource + "_" + gameState.getTimeElapsed() + ".png"); 457 458 458 459 var best = friendlyTiles.findBestTile(2, obstructions); // try to find a spot to place a DP. … … 589 590 if (!this.isFarming && count < 1600 && queues.field.length === 0) 590 591 { 591 592 // tell the queue manager we'll be trying to build fields shortly. 592 for (var i = 0; i < Config.Economy.initialFields;++i)593 for (var i = 0; i < this.Config.Economy.initialFields;++i) 593 594 { 594 595 var plan = new ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID }); 595 596 plan.isGo = function() { return false; }; // don't start right away. … … 771 772 } 772 773 773 774 BaseManager.prototype.assignToFoundations = function(gameState, noRepair) { 775 774 776 // If we have some foundations, and we don't have enough builder-workers, 775 777 // try reassigning some other workers who are nearby 776 778 … … 832 834 833 835 var assigned = gameState.getOwnEntitiesByMetadata("target-foundation", target.id()).length; 834 836 835 var targetNB = Config.Economy.targetNumBuilders; // TODO: dynamic that.837 var targetNB = this.Config.Economy.targetNumBuilders; // TODO: dynamic that. 836 838 if (target.hasClass("CivCentre") || target.buildTime() > 150 || target.hasClass("House")) 837 839 targetNB *= 2; 838 840 if (target.getMetadata(PlayerID, "baseAnchor") == true) -
binaries/data/mods/public/simulation/ai/aegis/plan-transport.js
18 18 var TransportPlan = function(gameState, units, destination, allAtOnce, escortSize, onlyIfOK) { 19 19 var self = this; 20 20 21 this.ID = uniqueIDTPlans++;21 this.ID = playerGlobals[PlayerID].uniqueIDTPlans++; 22 22 23 23 var unitsID = []; 24 24 if (units.length !== undefined) -
binaries/data/mods/public/simulation/ai/aegis/queueplan-building.js
4 4 5 5 this.metadata = metadata; 6 6 7 this.ID = uniqueIDBOPlans++;7 this.ID = playerGlobals[PlayerID].uniqueIDBOPlans++; 8 8 9 9 this.template = gameState.getTemplate(this.type); 10 10 if (!this.template) { -
binaries/data/mods/public/simulation/ai/aegis/config.js
1 // Baseconfig is the highest difficulty. 2 var baseConfig = { 3 "Military" : { 1 var Config = function() { 2 this.debug = false; // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard. 3 this.difficulty = 2; // overriden by the GUI 4 5 this.Military = { 4 6 "fortressLapseTime" : 540, // Time to wait between building 2 fortresses 5 7 "defenceBuildingTime" : 600, // Time to wait before building towers or fortresses 6 8 "attackPlansStartTime" : 0, // time to wait before attacking. Start as soon as possible (first barracks) … … 8 10 "popForBarracks1" : 15, 9 11 "popForBarracks2" : 95, 10 12 "timeForBlacksmith" : 900, 11 } ,12 "Economy" :{13 }; 14 this.Economy = { 13 15 "townPhase" : 180, // time to start trying to reach town phase (might be a while after. Still need the requirements + ress ) 14 16 "cityPhase" : 840, // time to start trying to reach city phase 15 17 "popForMarket" : 80, … … 19 21 "targetNumBuilders" : 1.5, // Base number of builders per foundation. 20 22 "femaleRatio" : 0.4, // percent of females among the workforce. 21 23 "initialFields" : 2 22 } ,24 }; 23 25 24 26 // Note: attack settings are set directly in attack_plan.js 25 27 26 28 // defence 27 "Defence" : { 29 this.Defence = 30 { 28 31 "defenceRatio" : 5, // see defence.js for more info. 29 32 "armyCompactSize" : 700, // squared. Half-diameter of an army. 30 33 "armyBreakawaySize" : 900 // squared. 31 } ,34 }; 32 35 33 36 // military 34 "buildings" : { 37 this.buildings = 38 { 35 39 "moderate" : { 36 40 "default" : [ "structures/{civ}_barracks" ] 37 41 }, … … 51 55 "default" : [ "structures/{civ}_fortress" ], 52 56 "celt" : [ "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ] 53 57 } 54 } ,58 }; 55 59 56 60 // qbot 57 "priorities" : { // Note these are dynamic, you are only setting the initial values 61 this.priorities = 62 { // Note these are dynamic, you are only setting the initial values 58 63 "house" : 350, 59 64 "villager" : 40, 60 65 "citizenSoldier" : 60, … … 67 72 "majorTech" : 700, 68 73 "minorTech" : 50, 69 74 "civilCentre" : 400 70 }, 71 "difficulty" : 2, // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard. 72 "debug" : false 75 }; 73 76 }; 74 77 75 var Config = { 76 "debug": false, 77 "difficulty" : 2, // overriden by the GUI 78 updateDifficulty: function(difficulty) 78 //Config.prototype = new BaseConfig(); 79 80 Config.prototype.updateDifficulty = function(difficulty) 81 { 82 this.difficulty = difficulty; 83 // changing settings based on difficulty. 84 if (this.difficulty === 1) 79 85 { 80 Config.difficulty = difficulty; 81 // changing settings based on difficulty. 82 if (Config.difficulty === 1) 83 { 84 Config.Military.defenceBuildingTime = 1200; 85 Config.Military.attackPlansStartTime = 960; 86 Config.Military.popForBarracks1 = 35; 87 Config.Military.popForBarracks2 = 150; // shouldn't reach it 88 Config.Military.popForBlacksmith = 150; // shouldn't reach it 86 this.Military.defenceBuildingTime = 1200; 87 this.Military.attackPlansStartTime = 960; 88 this.Military.popForBarracks1 = 35; 89 this.Military.popForBarracks2 = 150; // shouldn't reach it 90 this.Military.popForBlacksmith = 150; // shouldn't reach it 89 91 90 Config.Economy.cityPhase = 1800;91 Config.Economy.popForMarket = 80;92 Config.Economy.techStartTime = 600;93 Config.Economy.femaleRatio = 0.6;94 Config.Economy.initialFields = 1;95 96 97 else if (Config.difficulty === 0)98 99 Config.Military.defenceBuildingTime = 450;100 Config.Military.attackPlansStartTime = 9600000; // never101 Config.Military.popForBarracks1 = 60;102 Config.Military.popForBarracks2 = 150; // shouldn't reach it103 Config.Military.popForBlacksmith = 150; // shouldn't reach it92 this.Economy.cityPhase = 1800; 93 this.Economy.popForMarket = 80; 94 this.Economy.techStartTime = 600; 95 this.Economy.femaleRatio = 0.6; 96 this.Economy.initialFields = 1; 97 // Config.Economy.targetNumWorkers will be set by AI scripts. 98 } 99 else if (this.difficulty === 0) 100 { 101 this.Military.defenceBuildingTime = 450; 102 this.Military.attackPlansStartTime = 9600000; // never 103 this.Military.popForBarracks1 = 60; 104 this.Military.popForBarracks2 = 150; // shouldn't reach it 105 this.Military.popForBlacksmith = 150; // shouldn't reach it 104 106 105 Config.Economy.cityPhase = 240000; 106 Config.Economy.popForMarket = 200; 107 Config.Economy.techStartTime = 1800; 108 Config.Economy.femaleRatio = 0.2; 109 Config.Economy.initialFields = 1; 110 // Config.Economy.targetNumWorkers will be set by AI scripts. 111 } 107 this.Economy.cityPhase = 240000; 108 this.Economy.popForMarket = 200; 109 this.Economy.techStartTime = 1800; 110 this.Economy.femaleRatio = 0.2; 111 this.Economy.initialFields = 1; 112 // Config.Economy.targetNumWorkers will be set by AI scripts. 112 113 } 113 114 }; 114 115 Config.__proto__ = baseConfig; -
binaries/data/mods/public/simulation/ai/aegis/queueplan-training.js
2 2 this.type = gameState.applyCiv(type); 3 3 this.metadata = metadata; 4 4 5 this.ID = uniqueIDBOPlans++;5 this.ID = playerGlobals[PlayerID].uniqueIDBOPlans++; 6 6 7 7 this.template = gameState.getTemplate(this.type); 8 8 if (!this.template) -
binaries/data/mods/public/simulation/ai/aegis/aegis.js
1 1 // "local" global variables for stuffs that will need a unique ID 2 2 // Note that since order of loading is alphabetic, this means this file must go before any other file using them. 3 var uniqueIDBOPlans = 0; // training/building/research plans 4 var uniqueIDBases = 1; // base manager ID. Starts at one because "0" means "no base" on the map 5 var uniqueIDTPlans = 1; // transport plans. starts at 1 because 0 might be used as none. 3 var playerGlobals = []; 4 var g_debugEnabled = false; 6 5 7 6 function AegisBot(settings) { 8 7 BaseAI.call(this, settings); 9 8 10 Config.updateDifficulty(settings.difficulty); 9 this.Config = new Config(); 10 11 this.Config.updateDifficulty(settings.difficulty); 11 12 12 13 this.turn = 0; 13 14 14 15 this.playedTurn = 0; 15 16 this.priorities = Config.priorities;16 17 this.priorities = this.Config.priorities; 17 18 18 19 // this.queues can only be modified by the queue manager or things will go awry. 19 20 this.queues = {}; 20 21 for (i in this.priorities) 21 22 this.queues[i] = new Queue(); 22 23 23 this.queueManager = new QueueManager(this. queues, this.priorities);24 this.queueManager = new QueueManager(this.Config, this.queues, this.priorities); 24 25 25 this.HQ = new HQ( );26 this.HQ = new HQ(this.Config); 26 27 27 28 this.firstTime = true; 28 29 … … 35 36 AegisBot.prototype = new BaseAI(); 36 37 37 38 AegisBot.prototype.CustomInit = function(gameState, sharedScript) { 38 39 40 playerGlobals[PlayerID] = {}; 41 playerGlobals[PlayerID].uniqueIDBOPlans = 0; // training/building/research plans 42 playerGlobals[PlayerID].uniqueIDBases = 1; // base manager ID. Starts at one because "0" means "no base" on the map 43 playerGlobals[PlayerID].uniqueIDTPlans = 1; // transport plans. starts at 1 because 0 might be used as none. 44 39 45 this.HQ.init(gameState,sharedScript.events,this.queues); 40 debug ("Initialized with the difficulty " + Config.difficulty);46 debug ("Initialized with the difficulty " + this.Config.difficulty); 41 47 42 var ents = gameState.getEntities().filter(Filters.byOwner( PlayerID));48 var ents = gameState.getEntities().filter(Filters.byOwner(this.player)); 43 49 var myKeyEntities = ents.filter(function(ent) { 44 50 return ent.hasClass("CivCentre"); 45 51 }); 46 52 47 53 if (myKeyEntities.length == 0){ 48 myKeyEntities = gameState.getEntities().filter(Filters.byOwner( PlayerID));54 myKeyEntities = gameState.getEntities().filter(Filters.byOwner(this.player)); 49 55 } 50 56 51 57 var filter = Filters.byClass("CivCentre"); 52 var enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner( PlayerID))).filter(filter);58 var enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner(this.player))).filter(filter); 53 59 54 60 if (enemyKeyEntities.length == 0){ 55 enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner( PlayerID)));61 enemyKeyEntities = gameState.getEntities().filter(Filters.not(Filters.byOwner(this.player))); 56 62 } 57 63 58 64 this.myIndex = this.accessibility.getAccessValue(myKeyEntities.toEntityArray()[0].position()); … … 65 71 var pos = [this.pathInfo.mkeyPos[0] + 150*Math.cos(this.pathInfo.angle),this.pathInfo.mkeyPos[1] + 150*Math.sin(this.pathInfo.angle)]; 66 72 var path = this.pathFinder.getPath(this.pathInfo.ekeyPos, pos, 2, 2);// uncomment for debug:*/, 300000, gameState); 67 73 68 //Engine.DumpImage("initialPath" + PlayerID+ ".png", this.pathFinder.TotorMap.map, this.pathFinder.TotorMap.width,this.pathFinder.TotorMap.height,255);74 //Engine.DumpImage("initialPath" + this.player + ".png", this.pathFinder.TotorMap.map, this.pathFinder.TotorMap.width,this.pathFinder.TotorMap.height,255); 69 75 70 76 if (path !== undefined && path[1] !== undefined && path[1] == false) { 71 77 // path is viable and doesn't require boating. … … 81 87 } 82 88 83 89 AegisBot.prototype.OnUpdate = function(sharedScript) { 90 84 91 if (this.gameFinished){ 85 92 return; 86 93 } … … 132 139 var cityPhase = this.gameState.cityPhase(); 133 140 // try going up phases. 134 141 // TODO: softcode this. 135 if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > ( Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40142 if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40 136 143 && this.gameState.findResearchers(townPhase,true).length != 0 && this.queues.majorTech.length() === 0 137 144 && this.gameState.getOwnEntities().filter(Filters.byClass("Village")).length > 5) 138 145 { … … 142 149 this.queues.majorTech.addItem(new ResearchPlan(this.gameState, townPhase,0,-1,true)); // we rush the town phase. 143 150 debug ("Trying to reach town phase"); 144 151 } 145 else if (this.gameState.canResearch(cityPhase,true) && this.gameState.getTimeElapsed() > ( Config.Economy.cityPhase*1000)152 else if (this.gameState.canResearch(cityPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.cityPhase*1000) 146 153 && this.gameState.getOwnEntitiesByRole("worker").length > 85 147 154 && this.gameState.findResearchers(cityPhase, true).length != 0 && this.queues.majorTech.length() === 0) { 148 155 debug ("Trying to reach city phase"); … … 215 222 // deactivated for now. 216 223 this.strategy = "normal"; 217 224 // rarely and if we can assume it's not a water map. 218 if (!this.pathInfo.needboat && 0)//Math.random() < 0.2 && Config.difficulty == 2)225 if (!this.pathInfo.needboat && 0)//Math.random() < 0.2 && this.Config.difficulty == 2) 219 226 { 220 227 this.strategy = "rush"; 221 228 // going to rush. 222 229 this.HQ.targetNumWorkers = 0; 223 Config.Economy.townPhase = 480;224 Config.Economy.cityPhase = 900;225 Config.Economy.farmsteadStartTime = 600;226 Config.Economy.femaleRatio = 0; // raise it since we'll want to rush age 2.230 this.Config.Economy.townPhase = 480; 231 this.Config.Economy.cityPhase = 900; 232 this.Config.Economy.farmsteadStartTime = 600; 233 this.Config.Economy.femaleRatio = 0; // raise it since we'll want to rush age 2. 227 234 } 228 235 }; 229 236 … … 238 245 };*/ 239 246 240 247 function debug(output){ 241 if ( Config.debug){248 if (g_debugEnabled){ 242 249 if (typeof output === "string"){ 243 250 warn(output); 244 251 }else{ -
binaries/data/mods/public/simulation/ai/aegis/defence.js
1 1 // directly imported from Marilyn, with slight modifications to work with qBot. 2 2 3 function Defence( ){3 function Defence(Config){ 4 4 this.defenceRatio = Config.Defence.defenceRatio;// How many defenders we want per attacker. Need to balance fewer losses vs. lost economy 5 5 // note: the choice should be a no-brainer most of the time: better deflect the attack. 6 6 // This is also sometimes forcebly overcome by the defense manager. -
binaries/data/mods/public/simulation/ai/aegis/queueplan-research.js
1 1 var ResearchPlan = function(gameState, type, startTime, expectedTime, rush) { 2 2 this.type = type; 3 3 4 this.ID = uniqueIDBOPlans++;4 this.ID = playerGlobals[PlayerID].uniqueIDBOPlans++; 5 5 6 6 this.template = gameState.getTemplate(this.type); 7 7 if (!this.template || this.template.researchTime === undefined) { -
binaries/data/mods/public/simulation/ai/aegis/map-module.js
31 31 for (var y = 0; y < passabilityMap.height; ++y) 32 32 { 33 33 var i = x + y*passabilityMap.width; 34 var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);34 var tilePlayer = (territoryMap.data[i] & 0x3F); 35 35 36 36 if (gameState.ai.myIndex !== gameState.ai.accessibility.landPassMap[i]) 37 37 { … … 88 88 var obstructionTiles = new Uint8Array(passabilityMap.data.length); 89 89 for (var i = 0; i < passabilityMap.data.length; ++i) 90 90 { 91 var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);91 var tilePlayer = (territoryMap.data[i] & 0x3F); 92 92 var invalidTerritory = ( 93 93 (!buildOwn && tilePlayer == playerID) || 94 94 (!buildAlly && gameState.isPlayerAlly(tilePlayer) && tilePlayer != playerID) || … … 133 133 var ret = new Map(gameState.sharedScript, map.data); 134 134 135 135 ret.getOwner = function(p) { 136 return this.point(p) & TERRITORY_PLAYER_MASK;136 return this.point(p) & 0x3F; 137 137 } 138 138 ret.getOwnerIndex = function(p) { 139 return this.map[p] & TERRITORY_PLAYER_MASK;139 return this.map[p] & 0x3F; 140 140 } 141 141 return ret; 142 142 }; -
binaries/data/mods/public/simulation/ai/aegis/queue-manager.js
17 17 // 18 18 // This system should be improved. It's probably not flexible enough. 19 19 20 var QueueManager = function(queues, priorities) { 20 var QueueManager = function(Config, queues, priorities) { 21 this.Config = Config; 21 22 this.queues = queues; 22 23 this.priorities = priorities; 23 24 this.account = {}; … … 143 144 // estimate time based on priority + cost + nb 144 145 // TODO: work on this. 145 146 for (type in qCosts) 147 { 146 148 qCosts[type] += (cost[type] + Math.min(cost[type],this.priorities[name])); 149 } 147 150 qTime += 30000; 148 151 } else { 149 152 // TODO: work on this. … … 282 285 283 286 // nice readable HTML version. 284 287 QueueManager.prototype.HTMLprintQueues = function(gameState){ 285 if (! Config.debug)288 if (!this.Config.debug) 286 289 return; 287 290 log("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"> <html> <head> <title>Aegis Queue Manager</title> <link rel=\"stylesheet\" href=\"table.css\"> </head> <body> <table> <caption>Aegis Build Order</caption> "); 288 291 for (var i in this.queues){ … … 522 525 var self = this; 523 526 this.queueArrays = []; 524 527 for (var p in this.queues) 528 { 525 529 this.queueArrays.push([p,this.queues[p]]); 530 } 526 531 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); 527 532 } 528 533 } … … 539 544 var self = this; 540 545 this.queueArrays = []; 541 546 for (var p in this.queues) 547 { 542 548 this.queueArrays.push([p,this.queues[p]]); 549 } 543 550 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); 544 551 } 545 552 } … … 548 555 if (this.queues[queueName] !== undefined) 549 556 this.priorities[queueName] = newPriority; 550 557 this.queueArrays = []; 551 for (var p in this.queues) { 558 for (var p in this.queues) 559 { 552 560 this.queueArrays.push([p,this.queues[p]]); 553 561 } 554 562 this.queueArrays.sort(function (a,b) { return (self.priorities[b[0]] - self.priorities[a[0]]) }); -
binaries/data/mods/public/simulation/ai/aegis/attack_plan.js
6 6 * There is a basic support for naval expeditions here. 7 7 */ 8 8 9 function CityAttack(gameState, HQ, uniqueID, targetEnemy, type , targetFinder) {9 function CityAttack(gameState, HQ, Config, uniqueID, targetEnemy, type , targetFinder) { 10 10 11 this.Config = Config; 11 12 //This is the list of IDs of the units in the plan 12 13 this.idList=[]; 13 14 … … 50 51 51 52 this.maxPreparationTime = 210*1000; 52 53 // in this case we want to have the attack ready by the 13th minute. Countdown. Minimum 2 minutes. 53 if (type !== "superSized" && Config.difficulty >= 1)54 if (type !== "superSized" && this.Config.difficulty >= 1) 54 55 this.maxPreparationTime = 780000 - gameState.getTimeElapsed() < 120000 ? 120000 : 780000 - gameState.getTimeElapsed(); 55 56 56 57 this.pausingStart = 0; -
binaries/data/mods/public/simulation/ai/qbot/attackMoveToLocation.js
1 function AttackMoveToLocation(gameState, militaryManager, minAttackSize, maxAttackSize, targetFinder){ 1 function AttackMoveToLocation(gameState, Config, militaryManager, minAttackSize, maxAttackSize, targetFinder){ 2 3 this.Config = Config; 2 4 this.minAttackSize = minAttackSize || Config.attack.minAttackSize; 3 5 this.maxAttackSize = maxAttackSize || Config.attack.maxAttackSize; 4 6 this.idList=[]; … … 17 19 var enemyCount = militaryManager.measureEnemyCount(gameState); 18 20 19 21 // We require our army to be >= this strength 20 var targetStrength = enemyStrength * Config.attack.enemyRatio;22 var targetStrength = enemyStrength * this.Config.attack.enemyRatio; 21 23 22 24 var availableCount = militaryManager.countAvailableUnits(); 23 25 var availableStrength = militaryManager.measureAvailableStrength(); -
binaries/data/mods/public/simulation/ai/qbot/worker.js
34 34 35 35 this.startApproachingResourceTime = gameState.getTimeElapsed(); 36 36 37 //Engine.PostCommand( {"type": "set-shading-color", "entities": [this.ent.id()], "rgb": [10,0,0]});37 //Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [this.ent.id()], "rgb": [10,0,0]}); 38 38 }else{ 39 39 // If we haven't reached the resource in 2 minutes twice in a row and none of the resource has been 40 40 // gathered then mark it as inaccessible. … … 61 61 this.ent.repair(target); 62 62 } 63 63 64 //Engine.PostCommand( {"type": "set-shading-color", "entities": [this.ent.id()], "rgb": [0,10,0]});64 //Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [this.ent.id()], "rgb": [0,10,0]}); 65 65 } 66 66 67 67 Engine.ProfileStart("Update Gatherer Counts"); … … 248 248 }else{ 249 249 return type.generic; 250 250 } 251 }; 252 Kein Zeilenumbruch am Ende der Datei 251 }; -
binaries/data/mods/public/simulation/ai/qbot/defence.js
1 function Defence( ){1 function Defence(Config){ 2 2 this.ACQUIRE_DIST = Config.defence.acquireDistance; 3 3 this.RELEASE_DIST = Config.defence.releaseDistance; 4 4 -
binaries/data/mods/public/simulation/ai/qbot/military.js
6 6 * 7 7 */ 8 8 9 var MilitaryAttackManager = function() { 9 var MilitaryAttackManager = function(Config) { 10 11 this.Config = Config 10 12 // these use the structure soldiers[unitId] = true|false to register the units 11 13 this.attackManagers = [AttackMoveToLocation]; 12 14 this.availableAttacks = []; … … 16 18 this.attackCount = 0; 17 19 this.lastAttackTime = 0; 18 20 19 this.defenceManager = new Defence( );21 this.defenceManager = new Defence(Config); 20 22 }; 21 23 22 24 MilitaryAttackManager.prototype.init = function(gameState) { … … 24 26 25 27 // load units and buildings from the config files 26 28 27 if (civ in Config.buildings.moderate){28 this.bModerate = Config.buildings.moderate[civ];29 if (civ in this.Config.buildings.moderate){ 30 this.bModerate = this.Config.buildings.moderate[civ]; 29 31 }else{ 30 this.bModerate = Config.buildings.moderate['default'];32 this.bModerate = this.Config.buildings.moderate['default']; 31 33 } 32 34 33 if (civ in Config.buildings.advanced){34 this.bAdvanced = Config.buildings.advanced[civ];35 if (civ in this.Config.buildings.advanced){ 36 this.bAdvanced = this.Config.buildings.advanced[civ]; 35 37 }else{ 36 this.bAdvanced = Config.buildings.advanced['default'];38 this.bAdvanced = this.Config.buildings.advanced['default']; 37 39 } 38 40 39 if (civ in Config.buildings.fort){40 this.bFort = Config.buildings.fort[civ];41 if (civ in this.Config.buildings.fort){ 42 this.bFort = this.Config.buildings.fort[civ]; 41 43 }else{ 42 this.bFort = Config.buildings.fort['default'];44 this.bFort = this.Config.buildings.fort['default']; 43 45 } 44 46 45 47 for (var i in this.bAdvanced){ … … 54 56 }; 55 57 // TODO: figure out how to make this generic 56 58 for (var i in this.attackManagers){ 57 this.availableAttacks[i] = new this.attackManagers[i](gameState, this );59 this.availableAttacks[i] = new this.attackManagers[i](gameState, this.Config, this); 58 60 } 59 61 60 62 var enemies = gameState.getEnemyEntities(); … … 435 437 this.currentAttacks.push(this.availableAttacks[i]); 436 438 //debug("Attacking!"); 437 439 } 438 this.availableAttacks.splice(i, 1, new this.attackManagers[i](gameState, this ));440 this.availableAttacks.splice(i, 1, new this.attackManagers[i](gameState, this.Config, this)); 439 441 } 440 442 Engine.ProfileStop(); 441 443 -
binaries/data/mods/public/simulation/ai/qbot/entity-extend.js
3 3 }; 4 4 5 5 Entity.prototype.garrison = function(target) { 6 Engine.PostCommand( {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false});6 Engine.PostCommand(PlayerID, {"type": "garrison", "entities": [this.id()], "target": target.id(),"queued": false}); 7 7 return this; 8 8 }; 9 9 10 10 Entity.prototype.attack = function(unitId) 11 11 { 12 Engine.PostCommand( {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false});12 Engine.PostCommand(PlayerID, {"type": "attack", "entities": [this.id()], "target": unitId, "queued": false}); 13 13 return this; 14 }; 15 Kein Zeilenumbruch am Ende der Datei 14 }; -
binaries/data/mods/public/simulation/ai/qbot/config.js
1 var baseConfig = { 2 "attack" : { 1 function Config() { 2 this.debug = false 3 4 this.attack = { 3 5 "minAttackSize" : 20, // attackMoveToLocation 4 6 "maxAttackSize" : 60, // attackMoveToLocation 5 7 "enemyRatio" : 1.5, // attackMoveToLocation 6 8 "groupSize" : 10 // military 7 } ,9 }; 8 10 9 11 // defence 10 "defence" :{12 this.defence = { 11 13 "acquireDistance" : 220, 12 14 "releaseDistance" : 250, 13 15 "groupRadius" : 20, 14 16 "groupBreakRadius" : 40, 15 17 "groupMergeRadius" : 10, 16 18 "defenderRatio" : 2 17 } ,19 }; 18 20 19 21 // military 20 "buildings" :{22 this.buildings = { 21 23 "moderate" : { 22 24 "default" : [ "structures/{civ}_barracks" ] 23 25 }, … … 37 39 "default" : [ "structures/{civ}_fortress" ], 38 40 "celt" : [ "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ] 39 41 } 40 } ,42 }; 41 43 42 44 // qbot 43 "priorities" :{ // Note these are dynamic, you are only setting the initial values45 this.priorities = { // Note these are dynamic, you are only setting the initial values 44 46 "house" : 500, 45 47 "citizenSoldier" : 100, 46 48 "villager" : 100, … … 51 53 "militaryBuilding" : 50, 52 54 "defenceBuilding" : 17, 53 55 "civilCentre" : 1000 54 }, 55 56 "debug" : false 56 }; 57 57 }; 58 58 59 var Config = {60 "debug": false61 };62 63 Config.__proto__ = baseConfig;64 Kein Zeilenumbruch am Ende der Datei -
binaries/data/mods/public/simulation/ai/qbot/qbot.js
1 var g_debugEnabled = false; 1 2 2 3 function QBotAI(settings) { 3 4 BaseAI.call(this, settings); … … 4 5 5 6 this.turn = 0; 6 7 8 this.Config = new Config(); 9 7 10 this.modules = { 8 11 "economy": new EconomyManager(), 9 "military": new MilitaryAttackManager( ),12 "military": new MilitaryAttackManager(this.Config), 10 13 "housing": new HousingManager() 11 14 }; 12 15 16 13 17 // this.queues cannot be modified past initialisation or queue-manager will break 14 18 this.queues = { 15 19 house : new Queue(), … … 26 30 27 31 this.productionQueues = []; 28 32 29 this.priorities = Config.priorities;33 this.priorities = this.Config.priorities; 30 34 31 35 this.queueManager = new QueueManager(this.queues, this.priorities); 32 36 … … 161 165 }; 162 166 163 167 function debug(output){ 164 if ( Config.debug){168 if (g_debugEnabled){ 165 169 if (typeof output === "string"){ 166 170 warn(output); 167 171 }else{ -
binaries/data/mods/public/simulation/ai/qbot/economy.js
357 357 // Make resources glow wildly 358 358 if (resource == "food"){ 359 359 ent.getMetadata("nearby-resources-" + resource).forEach(function(ent){ 360 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]});360 Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [ent.id()], "rgb": [10,0,0]}); 361 361 }); 362 362 } 363 363 if (resource == "wood"){ 364 364 ent.getMetadata("nearby-resources-" + resource).forEach(function(ent){ 365 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]});365 Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,10,0]}); 366 366 }); 367 367 } 368 368 if (resource == "metal"){ 369 369 ent.getMetadata("nearby-resources-" + resource).forEach(function(ent){ 370 Engine.PostCommand( {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0,10]});370 Engine.PostCommand(PlayerID, {"type": "set-shading-color", "entities": [ent.id()], "rgb": [0,0,10]}); 371 371 }); 372 372 }*/ 373 373 }); -
binaries/data/mods/public/simulation/ai/qbot/entitycollection-extend.js
7 7 unitId = unit; 8 8 } 9 9 10 Engine.PostCommand( {"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false});10 Engine.PostCommand(PlayerID, {"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false}); 11 11 return this; 12 12 }; 13 13 … … 37 37 }else{ 38 38 return [sumPos[0]/count, sumPos[1]/count]; 39 39 } 40 }; 41 Kein Zeilenumbruch am Ende der Datei 40 };