[Utility] Card Hunter Battle Replayer

Discussion in 'Card Hunter General Chat' started by ParodyKnaveBob, Nov 8, 2017.

  1. ParodyKnaveBob

    ParodyKnaveBob Thaumaturge

    Well, good news and bad news. (I'd hoped to just bring good news, but here we are, ha ha.)

    The good news is that this week, I added ingestion of characters! $E^ b


    Yes, they're showing in proper order and everything. $E^ J

    The bad news is that this is in Windows only. For some unknown reason, browsers are choking before they even get past the players, which they used to do fine.


    That's in Edge, Chrome, and Firefox. Edge actually gives me a console error, but as per Microsoft norm, it's barely any info at all; Chrome and Firefox, though, surprised me with no console message describing this error. I'm sure I'll track it down eventually, but it kinda tarnishes my news. $;^ J Once I get this through, I'll feel better about uploading the Web app (which will still be super rough and sparse of any functionality anyway, lol).

    A touch more good news: I actually properly connect characters to their individual players! Also, I'm already laying groundwork as I go for more than just ranked play; I really hope to see that happen, although ranked is the easiest launch pad to start with of course. Finally, the main delays working with this this week have been due to my actually playing CH fairly regularly for the first time in months, heheheh.

    A touch more bad news: The players are actually not in order, ironically, (ironic since getting them is a prerequisite to properly getting the characters, who are in order, ha,) but replacing this earlier shortcut with properly ordered design will probably be my next task; the big question is how much I want to build now for team play behind the scenes vs. taking shortcuts again and postponing structuring full teams for later. Also, I have a loose idea for ingesting characters' classes, but I'm not entirely looking forward to it. $E^ b (Finally, just before posting, I wound up playing with a couple other logs, and huh, there's a mistake somewhere that I guess just snuck under my main testing log's radar due to coincidence. Once I find and fix that, it might auto-fix that undefined problem. We'll see.)

    So, to be clear about the yaaay screenshot, @candilicous is actually Player 1 and I Player 2, thus the tool has that wrong, but candilicous' P1 chars are properly first, in order from left to right, and my P2 chars come properly second, also in order from left to right. $:^ ] (This will hopefully be useful in the future for handling logs with insane players who name their characters all the same. Right now, they simply invalidate. Whatcha gonna do. At least I've already accounted for chars named the same as players!)

    All right! I'd better get outta here before this text wall grows too high. Let's see what next week holds.
    Last edited: Feb 12, 2018
    winner, Happenstance and Sir Veza like this.
  2. Kalin

    Kalin Begat G'zok

    Just watch for the first card they draw, right?
    winner likes this.
  3. ParodyKnaveBob

    ParodyKnaveBob Thaumaturge

    No, unfortunately. (However, that's the amazingly easy race determiner! heehee ... at least until fixed leagues and adventures.)
    winner likes this.
  4. ParodyKnaveBob

    ParodyKnaveBob Thaumaturge

    Back already! Just wanted to say more good-news-bad-news: I found the (surprisingly weird) area where the bug hid and managed to squash it! -- but only for Windows. $F^ b Unfortunately, still gotta track the (apparently different) problem on HTML5.

    I could've waited for the weekend (and until I fixed it in browsers) before saying that, but I wanted to clarify/expand my response to @Kalin:

    Amazingly simple design, yes. In fact, this is the entire script I wrote to determine race:

    /// str_race = scr_log_race_from_racial(text);
    purpose: determine a char's race from its racial card (if at all possible)
    scope: inst_ctrl_main
    //NEW: currently assumes for ranked parties, but later, handle leagues & monsters

    0 str: text to parse
    return str: race of char

    switch (argument0) {
    But, don't let my glee over that fool ya. This is the chunk I wrote to actually get the racial card in the first place (with only string_pos() and string_delete() being built-in functions -- and custom Hungarian Systems/Apps because weak-typed language -- not actually PHP, but using that BBCode code block for nicer readability):

    //% try easiest way to get character names, races, and players %//
    if (_str_room != undefined  &&  string_pos(" vs "_str_room)) { // ranked or league only
    _index_line_next scr_log_find_line("Event=Draw Phase Initiated");
        if (
    _index_line_next != INDEX_LIST_NOT_FOUND) {
    _index_line_end scr_log_find_line("Event=Action Phase Initiated"_index_line_next);
            if (
    _index_line_end != INDEX_LIST_NOT_FOUND) {
                while (++
    _index_line_next _index_line_end) {
    _i_player = -1;
    repeat (_count_players) {
                        if (
    scr_log_str_pos(map_battle_players[? ++_i_player], _index_line_next_index_name_begin) == _index_name_begin) {
    //% get race from racial card, then char name, then skim lines until char name changes (for now, same-name chars invalidate) %//
    _index_pos_start _index_name_begin string_length(map_battle_players[? _i_player] + " drew ");
    _index_pos_end scr_log_str_pos(" for "_index_line_next_index_pos_start) - 1;
    _str_race scr_log_race_from_racial(scr_log_get_text(_index_line_next_index_pos_start_index_pos_end));
    _str_name scr_log_get_text(_index_line_next,  _index_pos_end 6); // 6: advance pointer by 1 + length of " for "
    while (scr_log_str_pos(_str_name, ++_index_line_next_index_pos_start)) { // start after player name because some name chars after players!
    _index_line_next// prep for outside while() loop
    Last edited: Feb 13, 2018
    winner, Sir Veza and Flaxative like this.
  5. ParodyKnaveBob

    ParodyKnaveBob Thaumaturge

    ♫~Everybody's codin' for the weekend~♪

    Okay, lots of effort and progress this week, but little fruit to show. I fixed player ingestion on HTML5! It turns out, one line I had coded looked cross-target safe, but in fact compiled just differently enough to C++ (Windows) vs. Javascript (browsers) to work on one and break on the other. Super easy fix, yay.

    Then, I updated my IDE, yay. It broke my HTML5 export, boo. The software producers (YYG) told me of a new (undocumented, whoops,) feature-not-a-bug edge case that had hit me, and I fixed what I needed, yay. It then broke other stuff, boo.
    I cannot fix this one. More delays on uploading a browser version for any of you curious enough to piddle with it, boo.
    However! YYG already expect a bug report from me in a couple/few days, yay. $:^ ]

    Meanwhile, it still works fine on Windows, thus I can continue to build on it, yay. Next up, I intend to finally get players' ingestion to account for proper order. (And/or, perhaps, experiment with some of my HTML/JS/CSS extension code which I noticed might be partially unnecessary, thus letting me simplify some stuff.)
  6. rinco69

    rinco69 Thaumaturge

    Raw code is often the wrong tool for the job of parsing logs. It is much easier to use regular expressions for extracting fields. For instance the following regular expression extracts the player1 and player2 names from the battle log:

    (?ms)^response: joinbattle.*?roomName: (?<player1>.*) vs (?<player2>[^\n]*)

    All programming languages will have a hook into regular expressions. Sure regex is yet another language to learn ontop of coding, but it's worth learning. When writing regular expressions I like to use this website, https://regex101.com/tests
    Sir Veza and ParodyKnaveBob like this.
  7. ParodyKnaveBob

    ParodyKnaveBob Thaumaturge

    He does exist.

    $:^ P
    (Where ya been? Ppl been wonderin'.)

    Yeah, I've considered that regular expressions would be very helpful for this, thank you for the nod -- but other than finding someone's extension (assuming one exists) for my slightly obsolete version of IDE, this language does not have it built in. ... Well, writing this post made me at least do a search for it. Let's see...
    • $4.99 for an Android export extension from a highly reputable source
    • $4.99 for an iOS extension from the same
    • $4.99 for a Windows extension, same
    • oh ho, value pack, $9.99 for Android+iOS+Windows
    • ah, more like it, a free extension written in GML, the IDE's own multiplatform language, meaning I should be able to compile to C++ and Javascript just fine, although the author says it's "not as vast in functionality as regex" hmmm
    • (mm, another free extension, but in C# for Windows export only)
    Huh, I'm surprised. The GML one is worth trying. (I did work in regular expressions via PHP some years ago, but I didn't use them extensively.)

    All right, thank you, yeah, I'll add it to my Trello board now. Currently, I'm still whittling down the project to some bare bones for the sake of a really weird bug report. (That graphical glitch shown above? It doesn't seem related to anything sensible. I can draw the exact same thing using 1. a literal string or 2. a simple variable assignment or 3. a variable assigned through a user event, and it outputs widely different results, sometimes depending on whether a button is toggled in/visible -- including one proper looking result, ha -- and only messing up on the JS export. Yep, definitely wanna help YYG fix this before I add more to my plate.)

    And btw, from my tests, CH very annoyingly does not guarantee which player is #1 or #2 around that vs (which would also only work for ranked matches), but still, I understand the demonstrably better convenience. (Lemme find my current comparable code that gets names, for kicks and giggles...)
    //% try easiest way to get player names %//
    if (_str_room != undefined) {
    _index_vs string_pos(" vs "_str_room);
        if (
    _index_vs) { // if (multiplayer battle) {
    if (string_pos("'s battle vs"_str_room)) { // if (multiplayer custom battle) {
    _index_vs string_pos("'s battle vs"_str_room);
    _str_room string_delete(_str_room_index_vsstring_length("'s battle"));
        } else { 
    // if (custom battle vs Gary) {
    _index_vs string_pos("'s battle (custom)"_str_room);
    _str_room string_replace(_str_room"'s battle (custom)"" vs Gary");
    //NEW account for campaign: "Room=" + adventure code + "(" + player name + ")"
    _index_past_vs _index_vs string_length(" vs ");
    string_copy(_str_room,  1,  _index_vs 1),
    string_copy(_str_room_index_past_vs,  string_length(_str_room) - _index_past_vs 1)

    Yes, regex would be much nicer...
    (But never mind re-learning a newish language, I'd probably have to write this tool nearly from scratch. ~sigh~ I no longer look forward to such undertakings as "fun." Been through too many on other projects through the years.)
    Sir Veza likes this.

Share This Page