Jump to content

Search the Community

Showing results for tags 'javascript'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • Welcome
    • Announcements / News
    • Introductions & Off-Topic Discussion
    • Help & Feedback
  • 0 A.D.
    • General Discussion
    • Gameplay Discussion
    • Game Development & Technical Discussion
    • Art Development
    • Game Modification
    • Project Governance
    • Testing

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start





Website URL







First Name

Last Name

Skype ID

Found 10 results

  1. Github repo: https://github.com/Mare-Nostrum-0AD/popup_choices Zipfile: popup_choices.1.zip Hey everyone! Here's a new feature I've been planning to create for a while. It allows Scenario designers to include "popup choice" menus in their trigger scripts. These popup choice menus can have up to three buttons, with each button (optionally) triggering a function when it is clicked. This allows you to create scenarios with storylines and more interesting scripted events, and also to display information to the player during gameplay (i.e. a "Historical Background" blurb at the beginning of the scenario). The instructions for how to use this are contained in the README.md of the github repo and zipfile I linked to above. I included an example script at maps/scenarios/demo_popup_choices_triggers.js. To try out the scenario, go to the Scenario selection menu, filter by Demo maps, and look for DEMO: Popup Choices. You'll have to know at least a little JavaScript to use this feature, of course. I know a lot of you here aren't coders, so I'll try to build a "template" scenario script and a library of functions for simple use cases to make this as accessible as possible to everyone. I'm also willing to help people build their scenarios, as long as it's just a small or medium sized project. I'm also including this feature in my other mod, Mare Nostrum, from now on. I hope y'all can make some interesting scenarios with this!
  2. \gui\session\ sprites.xml session.xml \gui\session\minimap\ MiniMap.xml \art\textures\ui\session\
  3. Can we make it possible to dictate where techs can go in the UI? It would be very helpful (and logical) to be able to place techs beneath the units that they primarily affect. For instance, Rank Promotion techs and "Tradition" techs ("Archery Tradition", "Hoplite Tradition" etc.) can go directly beneath the unit. Example: It could go in the building's template in the productionqueue/technologies component, perhaps productionque/technologies/row. <ProductionQueue> <BatchTimeModifier>0.8</BatchTimeModifier> <Entities datatype="tokens"> units/{civ}/infantry_javelineer_b units/{civ}/infantry_slinger_b units/{civ}/infantry_archer_b units/{civ}/infantry_crossbowman_b </Entities> <Technologies> <Row2 datatype="tokens"> upgrade_rank_advanced_infantry_jav upgrade_rank_elite_infantry_jav upgrade_rank_advanced_infantry_slinger upgrade_rank_elite_infantry_slinger upgrade_rank_advanced_infantry_archer upgrade_rank_elite_infantry_archer </Row2> <Row3 datatype="tokens"> <br/> <br/> special_archery_tradition </Row3> <Row4 datatype="tokens"> training_levy_infantry_ranged </Row4> </Technologies> </ProductionQueue>
  4. ERROR: JavaScript error: gui/gamesetup/Pages/MapBrowserPage/GridBrowser.js line 1 redeclaration of let GridBrowser @gui/gamesetup/Pages/MapBrowserPage/GridBrowser.js:1:1 onPress@gui/pregame/MainMenuItems.js:64:13 performButtonAction@gui/pregame/MainMenuItemHandler.js:77:9 pressButton@gui/pregame/MainMenuItemHandler.js:63:10 ERROR: JavaScript error: gui/gamesetup/Pages/MapBrowserPage/GridBrowserItem.js line 1 redeclaration of let GridBrowserItem @gui/gamesetup/Pages/MapBrowserPage/GridBrowserItem.js:1:1 onPress@gui/pregame/MainMenuItems.js:64:13 performButtonAction@gui/pregame/MainMenuItemHandler.js:77:9 pressButton@gui/pregame/MainMenuItemHandler.js:63:10 ERROR: JavaScript error: gui/gamesetup/Pages/MapBrowserPage/MatchSort.js line 1 redeclaration of const MatchSort @gui/gamesetup/Pages/MapBrowserPage/MatchSort.js:1:1 onPress@gui/pregame/MainMenuItems.js:64:13 performButtonAction@gui/pregame/MainMenuItemHandler.js:77:9 pressButton@gui/pregame/MainMenuItemHandler.js:63:10
  5. While discussing a quirk of the common AI API on IRC Stan suggested to take a code coverage measurement on the existent simulation components, since I had the toolchain already set up for AI development. I took the challenge and now present first results. However, I decided to not attach this to the already running jasmine-thread since I consider it an independent topic. To reproduce the measurements: Attached to this posting is a zip archive. Unzip it to binaries/data/mods/public/simulation. A new directory CoverageMeasurement will show up. Inside that directory, the subdirectory instrumented already contains the results of an instrumented run. Load the jscoverage.html file into a fully-scripting-enabled browser to see the results. They will look somewhat like this: To rerun the analysis, launch the runcomponenttests.sh shell script from the CoverageMeasurement directory. That script requires that the zip archive has been unpacked at the particular destination and 0AD fully compiled (SpiderMonkey shell is compiled via the update-workspaces.sh script). Observations during analysis: The test scripts are normally run from the pyrogenesis test script file test_scripts.h via the cxxtest subsystem. This means the scripts can enjoy the full Pyrogenesis environment, which is not available when runcomponenttests.sh runs the test scripts via SpiderMonkeyShell. For example, I had to manually define all interface identifiers IID_XXX in the jscover-driver.js file which contains the actual 0AD-specific analysis logic. Since I just faked the missing Engine functions, the logic of some test cases might not work, giving improper coverage results. Still, I found some component methods which seem to be not tested. My homebrew driver script runs all test scripts in the same JS environment without resetting the global scope. This caused SpiderMonkey errors when const values were redefined. To overcome this, the shell script wraps the content of each test script into a "(function () { test script })()"; encapsulation using an sed script. Some test scripts still caused errors and I resorted to skipping them for the first draft. Error analysis seemed too cumbersome when it is unclear whether this approach is feasible at all. The skipped test cases are marked in the CoverageMeasurement/jscover-driver.js file. Code coverage measurements are taken via the JSCover tool (not the most recent version). This tool is originally intended for web development and so relies on running a JSCover server in the background, while browsing the reports. I hacked the JSCover main script to allow browsing the results without the server running, as this was needed to integrate the JSCover results into a JSDoc documentation site. The hacked jscoverage.js script is found in the CoverageMeasurement/JSCover directory. Any comments or questions welcome. CoverageMeasurement.zip
  6. I know this may be controversial, but I think the current SpecificName scheme adds a minor amount of confusion, or at least a better scheme may add some more clarity where currently there is little. So, for example: <GenericName>Gallic Champion</GenericName> <SpecificName>Soliduros</SpecificName> This is actually a Swordsman, along with whatever that means to the game, but you don't know that from the name of the unit. What I would suggest is something like this: <GenericName>Champion Swordsman</GenericName> <SpecificName>Gallic Champion</SpecificName> <EthnicName>Soliduros</EthnicName> In the UI, it would show: Gallic Champion (Champion Swordsman) Likewise: Spartiate Hoplite (Champion Spearman) This now gives you a much better idea what "kind" of unit it is. The <EthnicName> "Spartiátēs" and "Soldurios" would show up elsewhere, likely in the Information viewer. Extended, we could give the player the option of what they want to see in the UI and tooltips.
  7. Hi guys, do you know where I should look to learn about the functions that I can call from a map script (.js file)? For example, I have this: let targets = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).GetNonGaiaEntities().filter(ent => { let cmpIdentity = Engine.QueryInterface(ent, IID_Identity); return cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), target_classes); }); Where do I look to find this function GetNonGaiaEntities()? I wanted to include in this filter also the player number. Okay, problem solved... I used eval() to see what is this object Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager) and found that it is an ICmpRangeManager. Then I googled it and found a list of methods in http://sathyam.me/0adblog/docs/classICmpRangeManager.html.
  8. Hi. I was attempting to greatly simplify all of the builder units in the game, namely infantry, by removing their builder components in each individual file, something like 50 files. I then just made one master list in the generic infantry template using the {civ} tag for all, thinking the individual soldiers would just be able to build the buildings they have in their civ. For example. Instead of 50 individual soldiers having this in their templates: <Builder> <Entities datatype="tokens"> structures/{civ}_catapult structures/sele_military_colony structures/sele_library structures/sele_wonder </Entities> </Builder> I created one glorious, beautiful master list in the template_unit_infantry: <Builder> <Rate>1.0</Rate> <Entities datatype="tokens"> structures/{civ}_civil_centre structures/{civ}_military_colony structures/{civ}_house structures/{civ}_storehouse structures/{civ}_farmstead structures/{civ}_field structures/{civ}_rotarymill structures/{civ}_corral structures/{civ}_dock structures/{civ}_shipyard structures/{civ}_market structures/{civ}_pillar_ashoka structures/{civ}_outpost structures/{civ}_defense_tower other/wallset_palisade structures/{civ}_wallset_short structures/{civ}_wallset_stone structures/{civ}_wallset_siege structures/{civ}_barracks structures/{civ}_stables structures/{civ}_barracks_aux structures/{civ}_elephant_stables structures/{civ}_embassy_celtic structures/{civ}_embassy_iberian structures/{civ}_embassy_italiote structures/{civ}_syssiton structures/{civ}_gymnasion structures/{civ}_blacksmith structures/{civ}_kennel structures/{civ}_government_center structures/{civ}_statue structures/{civ}_temple structures/{civ}_temple_vesta structures/{civ}_arch structures/{civ}_theatron structures/{civ}_library structures/{civ}_lighthouse structures/{civ}_apadana structures/{civ}_prytaneion structures/{civ}_army_camp structures/{civ}_fortress structures/{civ}_catapult structures/{civ}_wonder </Entities> </Builder> I did this thinking it would work, since something almost exactly the same works for the ProductionQueue element for training units: <ProductionQueue> <BatchTimeModifier>0.8</BatchTimeModifier> <Entities datatype="tokens"> units/{civ}_infantry_spearman_b units/{civ}_infantry_pikeman_b units/{civ}_infantry_swordsman_b units/{civ}_infantry_javelinist_b units/{civ}_infantry_slinger_b units/{civ}_infantry_archer_b units/{civ}_infantry_crossbowman_b units/{civ}_cavalry_swordsman_b units/{civ}_cavalry_spearman_b units/{civ}_cavalry_javelinist_b units/{civ}_cavalry_archer_b units/{civ}_cavalry_crossbowman_b </Entities> <Technologies datatype="tokens"> training_levy_infantry training_mobilization training_total_war </Technologies> </ProductionQueue> See, when training units it just picks the right units based on what is available for the civ. Can this be extended to the <Builder> component too? Otherwise I get this nastiness: ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_barracks_aux.xml" ERROR: Failed to load entity template 'structures/chin_barracks_aux' ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_elephant_stables.xml" ERROR: Failed to load entity template 'structures/chin_elephant_stables' ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_embassy_celtic.xml" ERROR: Failed to load entity template 'structures/chin_embassy_celtic' ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_embassy_iberian.xml" ERROR: Failed to load entity template 'structures/chin_embassy_iberian' ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_military_colony.xml" ERROR: Failed to load entity template 'structures/chin_military_colony' ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_rotarymill.xml" ERROR: Failed to load entity template 'structures/chin_rotarymill' ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_pillar_ashoka.xml" ERROR: Failed to load entity template 'structures/chin_pillar_ashoka' ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_wallset_short.xml" ERROR: Failed to load entity template 'structures/chin_wallset_short' ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_wallset_siege.xml" ERROR: Failed to load entity template 'structures/chin_wallset_siege' ERROR: CCacheLoader failed to find archived or source file for: "simulation/templates/structures/chin_stables.xml" This can be done to the public mod templates too, if we can get this to work. One benefit, besides template cleanliness and consistency, is that you can now put the RotaryMill, for example, in the GUI next to the Farmstead where it belongs, whereas currently it's put at the end of the GUI list with the Fortress because the tokens are always added to the end.
  9. Hi. I see this commit here, which is a good commit for what the game has now: https://trac.wildfiregames.com/changeset/19673 Also, some technical discussion here: https://code.wildfiregames.com/D460 I was wondering if it would be better for the civ.json files to call the templates and auras directly and get the information directly from these files, rather than having to manually keep the civ.json files up to date. Maybe what I am suggesting is too difficult for the benefit, but I think it would simplify things a lot and eventually allow for a better presentation in the History section of the game. So, instead of It could look like: That's a reduction of 40 lines from just one civ file, or about 25% and looks a lot cleaner. The History section would pull the relevant information directly from the aura, technology, and template files listed. See, I left the Silver Owls bonus written out because it's part of their phase tech, but I could just as easily pull those effects out of the phase tech into a different tech file and call that instead.
  10. Hi, I am currently finishing up a project on implementing some emotions in the Petrabot to test a library I've written in C++. However I have run into a problem regarding the data transfer between the Pyrogenesis C++ layer and the mod javascript layer. I apologize for the amount of code in advance, but I am completely stumped as to where the error might be happening. In short, I am trying to convert data contained in a data wrapper class I've made to transfer data from the library. As far as feedback is concerned the data seems to be sent properly without any hiccups as the Javascript end seems to recognize the emotions vector as an object. However, the problem arises when I try to reference the "who" integer as it returns as undefined (this may very well be the case with more of the members of the Emotions wrapper, however I have no evidence that this is the case as of yet). class EmoState { public: class Emotions { public: int who; int strongest; std::vector<const Emote> emotes; Emotions::Emotions(); Emotions::~Emotions(); void SetWho(int s); void SetStrongest(int s); void AddEmotion(const Emote& e); }; int strAt; std::vector<Emotions> emotions; EmoState::EmoState(); EmoState::~EmoState(); void SetStrAt(int s); void AddEmotions(Emotions& e); }; The when the bot requests the data through GetEmoState (below), the C++ architecture fetches the current EmoState (which I've confirmed functions correctly through multiple tests) and tries to convert it for use with the bot. (Though I doubt this script contains the error, I included it to give a complete view of what's happening), static JS::Value GetEmoState(ScriptInterface::CxPrivate* pCxPrivate, int playerid) { ENSURE(pCxPrivate->pCBData); CAIWorker* self = static_cast<CAIWorker*> (pCxPrivate->pCBData); JSContext* cx(self->m_ScriptInterface->GetContext()); JS::RootedValue emoState(cx); const EmoState emoStates = self->ValTest.EmotionalState(playerid); self->m_ScriptInterface->ToJSVal<EmoState>(cx, &emoState, emoStates); return emoState; } The data conversion I wrote to handle the container is as seen below, I suspect that the error lies somewhere in this block of code, however I am not sure what I might have written wrong. template<> void ScriptInterface::ToJSVal<Emote>(JSContext* cx, JS::MutableHandleValue ret, const Emote& val) { JSAutoRequest rq(cx); JS::RootedValue who(cx); JS::RootedValue name(cx); JS::RootedValue intensity(cx); JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); if (!obj) { ret.setUndefined(); LOGERROR("Failed to create emote object"); return; } ToJSVal<int>(cx, &who, *val.directedAt); ToJSVal<int>(cx, &name, *val.name); ToJSVal<double>(cx, &intensity, *val.intensity); JS_SetProperty(cx, obj, "directedAt", who); JS_SetProperty(cx, obj, "name", name); JS_SetProperty(cx, obj, "intensity", intensity); ret.setObject(*obj); } template<> void ScriptInterface::ToJSVal<EmoState::Emotions>(JSContext* cx, JS::MutableHandleValue ret, const EmoState::Emotions& val) { JSAutoRequest rq(cx); JS::RootedValue who(cx); JS::RootedValue strongest(cx); JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); if (!obj) { ret.setUndefined(); LOGERROR("Failed to create emotions object"); return; } JS::RootedObject em(cx, JS_NewArrayObject(cx, 0)); if (!em) { ret.setUndefined(); LOGERROR("Failed to create emotions object"); return; } for (size_t i = 0; i < val.emotes.size(); ++i) { JS::RootedValue el(cx); ScriptInterface::ToJSVal<Emote>(cx, &el, val.emotes[i]); JS_SetElement(cx, em, i, el); } JS::RootedValue em2(cx); em2.setObject(*em); ToJSVal<int>(cx, &who, val.who); ToJSVal<int>(cx, &strongest, val.strongest); JS_SetProperty(cx, obj, "who", who); JS_SetProperty(cx, obj, "strongest", strongest); JS_SetProperty(cx, obj, "emotes", em2); ret.setObject(*obj); } template<> void ScriptInterface::ToJSVal<EmoState>(JSContext* cx, JS::MutableHandleValue ret, const EmoState& val) { JSAutoRequest rq(cx); JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); if (!obj) { ret.setUndefined(); LOGERROR("Failed to create EmoState object"); return; } JS::RootedValue strAt(cx); ScriptInterface::ToJSVal(cx, &strAt, val.strAt); JS::RootedObject em(cx, JS_NewArrayObject(cx, 0)); if (!em) { ret.setUndefined(); LOGERROR("Failed to create EmoState object"); return; } for (size_t i = 0; i < val.emotions.size(); ++i) { JS::RootedValue el(cx); ScriptInterface::ToJSVal<EmoState::Emotions>(cx, &el, val.emotions[i]); JS_SetElement(cx, em, i, el); } JS::RootedValue em2(cx); em2.setObject(*em); JS_SetProperty(cx, obj, "strAt", strAt); JS_SetProperty(cx, obj, "emotions", em2); ret.setObject(*obj); } As mentioned before, the javascript code (as seen below) requests the data, which is then applied to their relevant variables on the javascript end. The specific problem variable in the script is the "eS.who" variable which returns undefined and as such the if statement defaults to else. let emoState = Engine.GetEmoState(PlayerID); let pHF = this.PersonalEmoState.HopeFear; let pJD = this.PersonalEmoState.JoyDistress; let pPS = this.PersonalEmoState.PrideShame; for(let eS in emoState.emotions) { if(eS.who === PlayerID) { this.PersonalEmoState.Strongest = eS.strongest; this.PersonalEmoState.PrideShame = eS.emotes[0].intensity; this.PersonalEmoState.JoyDistress = eS.emotes[1].intensity; this.PersonalEmoState.HopeFear = eS.emotes[2].intensity; this.PersonalEmoState.SatisfactionFearsconfirmed = eS.emotes[3].intensity; this.PersonalEmoState.ReliefDisappointment = eS.emotes[4].intensity; this.PersonalEmoState.GratificationRemorse = eS.emotes[5].intensity; } else { let pGA = m.EmotionHandler.SocialEmoState[eS.who].GratitudeAnger; m.EmotionHandler.SocialEmoState[eS.who].Strongest = eS.strongest; m.EmotionHandler.SocialEmoState[eS.who].AdmirationReproach = eS.emotes[0].intensity; m.EmotionHandler.SocialEmoState[eS.who].HappyforResentment = eS.emotes[1].intensity; m.EmotionHandler.SocialEmoState[eS.who].GloatingPity = eS.emotes[2].intensity; m.EmotionHandler.SocialEmoState[eS.who].GratitudeAnger = eS.emotes[3].intensity; if(gameState.isPlayerAlly(eS.who)) { pJD = (pJD === this.PersonalEmoState.JoyDistress ? 0 : this.PersonalEmoState.JoyDistress); pPS = (pPS === this.PersonalEmoState.PrideShame ? 0 : this.PersonalEmoState.PrideShame); if(pGA !== m.EmotionHandler.SocialEmoState[eS.who].GratitudeAnger) { pGA = m.EmotionHandler.SocialEmoState[eS.who].GratitudeAnger ? 0 : this.PersonalEmoState.PrideShame; this.Config.personality.cooperative = Math.max(Math.min(1, this.Config.personality.cooperative + ((pGA + pPS + pJD)/3)), 0); } } } } this.StrongestAt = emoState.strAt; Once again, I am very sorry for the long post and mass of code. I hope someone will be able to help me as I believe I can make this a cool update. If my tests of the system are successful I am planning on developing a fully Javascript version of my library, which I'll submit as a fork to the Petrabot for people to play with as they want.
  • Create New...