// File: /workspace/github_c_makefile_star2_O1/schroeder-lvb[P]sissm/src/pidynbots.c
// Function: computeBotParams
static int _computeBotParams( int refresh )
{
    int minBots, maxBots, i;
    unsigned int currHuman, currBots, minHuman, maxHuman;
    double aiDifficulty;
    char *objName, *mapName, objLetter;
    char strBuf[256], *w, *v;
    int adjust = 0, errCode = 0, botBias, offsetIndex;

    // default parameters
    // 
    minBots      = pidynbotsConfig.MinimumEnemies;
    maxBots      = pidynbotsConfig.MaximumEnemies;
    minHuman     = 1;
    maxHuman     = pidynbotsConfig.MaxPlayersToScaleEnemyCount;
    currHuman    = rosterCount();

    // a wedge code to disable this plugin if non-Checkpoint mode is running
    //
    v = apiGetServerMode();
    if (! ((0==strcmp( v, "checkpoint" )) || (0==strcmp( v, "hardcore"))) )  return 0;

#if 0 
    // DEBUG tap for simulating humans joining and leaving - take out this block later
    static int currHuman_static = 1;
    int currHuman_tmp;
    if ( 0 == debugPoke( "delme.txt", &currHuman_tmp ) ) {
        currHuman_static = currHuman_tmp;
    }
    currHuman = currHuman_static;
    printf("\nDEBUG pidynbots: override to %d\n", currHuman );
    apiSay("pidynbots: override to %d humans", currHuman );
#endif

    aiDifficulty = pidynbotsConfig.AIDifficulty;

    // get current side, map, and objective
    //
    objName   = rosterGetObjective();                    // e.g., "OCCheckpoint_A"
    mapName   = rosterGetMapName();                      // e.g., "Farmhouse_Checkpoint_Security"
    objLetter = rosterGetCoopObjectiveLetter();          // e.g., 'A', 'B', 'C', ... ' '

    logPrintf( LOG_LEVEL_INFO, "pidynbots", "ObjName ::%s:: MapName ::%s:: objLetter ::%c::", 
        objName, mapName, objLetter );

    // search the table if override is found (look for matching map name)
    //
    for (i=0; i<PIDYN_MAXADJUSTERS; i++) {

        if ( NULL != strcasestr( pidynbotsConfig.Adjuster[i], mapName )) {

            // get min/max/dif values 
            //
            if ( NULL != (w = getWord( pidynbotsConfig.Adjuster[i], 1, " " ))) 
                errCode |= ( 1 != sscanf( w, "%d", &minBots ));
            if ( NULL != (w = getWord( pidynbotsConfig.Adjuster[i], 2, " " ))) 
                errCode |= ( 1 != sscanf( w, "%d", &maxBots ));
            if ( NULL != (w = getWord( pidynbotsConfig.Adjuster[i], 3, " " ))) 
                errCode |= ( 1 != sscanf( w, "%lf", &aiDifficulty ));

            // if override was found, look for per-objective adjustments
            //
            if (( !errCode  ) && ( (objLetter >= 'A') && (objLetter <= 'Z') )) {
                offsetIndex = objLetter - 'A';
                offsetIndex += 4;        
                if ( NULL != (w = getWord( pidynbotsConfig.Adjuster[i], offsetIndex, " " ))) {
                    errCode |= ( 1 != sscanf( w, "%d", &adjust ));
                    if ( !errCode ) maxBots += adjust;
                }
            }
            break;
        }
    }

    // poke the new values
    //
    if ( !errCode )  {

        // Update the bot difficulty if it was not overridden by the 
        // operator (picladmin)
        //
        if ( 0L == p2pGetL( "picladmin.p2p.botAdminControlDifficulty", 0L )) {  // check if in-game admin took control
            logPrintf( LOG_LEVEL_INFO, "pidynbots", "Adjusting bot difficulty %lf", aiDifficulty );
            snprintf( strBuf, 256, "%lf", aiDifficulty );
                 apiGameModePropertySet( "aidifficulty",   strBuf ) ;

            // if enabled in config, update the players by showing new params in-game
            //
            if ( 0 != strlen( pidynbotsConfig.showInGame ) ) {
                apiSay("%s Difficulty %6.3lf", pidynbotsConfig.showInGame, aiDifficulty*10.0 );
            }
        }
        
        // Update the bot count if it was not overridden by the 
        // operator (picladmin)
        //
        if ( 0L == p2pGetL( "picladmin.p2p.botAdminControl", 0L )) {  // check if in-game admin took control
            logPrintf( LOG_LEVEL_INFO, "pidynbots", "Adjusting bots %d:%d" , minBots, maxBots );

            // Apply BotBias - this changes min/maxenemies by a specified offset in function of 
            // number of human players are present
            //
            botBias = 0;
            if ( NULL != (w = getWord( pidynbotsConfig.BotBias, currHuman, " " ))) 
               if ( 1 != sscanf( w, "%d", &botBias )) botBias = 0;

            // validate to keep the server from crashing
            // 
            minBots += botBias;                           // offset from bias table
            maxBots += botBias;
            minBots += pidynMinimumOffset;                // offset from game mode table
            maxBots += pidynMmaximumOffset;

            if ( maxBots > pidynbotsConfig.MaxBotsCrashProtect )  
                maxBots = pidynbotsConfig.MaxBotsCrashProtect;
            if ( minBots < 1  )      minBots =  1;
            if ( minBots > maxBots ) maxBots = minBots; 

            snprintf( strBuf, 256, "%d", minBots );
                apiGameModePropertySet( "minimumenemies", strBuf );
            snprintf( strBuf, 256, "%d", maxBots );
                apiGameModePropertySet( "maximumenemies", strBuf );

            // for instant-respawn mode, it uses SoloPlayer set of parameters.  Compute
            // the scaled bots linearly here and poke in the value;
            //
            currBots =  _botScale( currHuman, maxBots, minBots, maxHuman, minHuman );
            snprintf( strBuf, 256, "%d", currBots );
                apiGameModePropertySet( "soloenemies", strBuf );

            // apiSay("Bias %d Bots %d:%d:%d Humans %d", botBias, minBots, maxBots, currBots, currHuman);
            // printf("\n****Bias %d Bots %d:%d:%d Humans %d***\n", botBias, minBots, maxBots, currBots, currHuman);

            // if enabled in config, update the players by showing new params in-game
            //
            if ( 0 != strlen( pidynbotsConfig.showInGame ) ) {
                apiSay("%s Count %d:%d [%d]", pidynbotsConfig.showInGame, minBots*2, maxBots*2, currBots );
            }

        }

        // Admin Bot override is "on", but still must process if instand respawn mode to emulate
        // dynamic bot changes
        //
        else {
           
            // If "respawnMode" AND "not fixed bot" then, recompute the dynamic scaling for this objective
            // Poke the resulting value to soloenemies
            //
            if ( _inRespawnCoopMode( refresh ) ) {

                 // read gamemodeproperty for minenemies and maximumenemies
                 // convert to integer for math
                 //
                 if ( 1 != sscanf( apiGameModePropertyGet( "minimumenemies" ), "%d", &minBots )) errCode = 1;
                 if ( 1 != sscanf( apiGameModePropertyGet( "maximumenemies" ), "%d", &maxBots )) errCode = 1;

                 if ( 0 == errCode ) {
                     // program currBots to soloenemies
                     // 
                     if ( minBots != maxBots )  {
                         currBots =  _botScale( currHuman, maxBots, minBots, maxHuman, minHuman );
                         snprintf( strBuf, 256, "%d", currBots );

                         apiGameModePropertySet( "soloenemies", strBuf );

                         logPrintf( LOG_LEVEL_INFO, "pidynbots", 
                             "Adjusting bots respawn mode with operator override params %d:%d [%d] difficulty %lf", 
                             minBots, maxBots, currBots, aiDifficulty );

                         // if enabled in config, update the players by showing new params in-game
                         //
                         if ( 0 != strlen( pidynbotsConfig.showInGame ) ) {
                             apiSay("%s Count %d:%d [%d]", pidynbotsConfig.showInGame, minBots*2, maxBots*2, currBots );
                         }
                     }
                 }
             }
             else {
                 logPrintf( LOG_LEVEL_INFO, "pidynbots", "Adjusting bots bypassed due to Admin override %d:%d difficulty %lf", 
                     minBots, maxBots, aiDifficulty );
             }
        }

    }
    return 0;  
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x138, %rsp            # imm = 0x138
movl %edi, 0x2c(%rsp)
movl $0x0, 0x1c(%rsp)
movl 0x6e28c(%rip), %eax     # 0x7c0ec
movl %eax, 0x8(%rsp)
movl 0x6e286(%rip), %eax     # 0x7c0f0
movl %eax, 0x4(%rsp)
movl 0x6e280(%rip), %eax     # 0x7c0f4
movl %eax, 0x18(%rsp)
callq 0x149a0
movq %rax, 0x20(%rsp)
callq 0x13a76
movq %rax, %r14
leaq 0xf14a(%rip), %rsi      # 0x1cfdb
movq %rax, %rdi
callq 0x8220
testl %eax, %eax
je 0xdeb4
leaq 0xe15b(%rip), %rsi      # 0x1bfff
movq %r14, %rdi
callq 0x8220
testl %eax, %eax
jne 0xdf3a
movsd 0x6e244(%rip), %xmm0    # 0x7c100
movsd %xmm0, 0x10(%rsp)
callq 0x1423e
movq %rax, %r12
callq 0x14262
movq %rax, %r13
callq 0x1432d
movl %eax, %r15d
movsbl %al, %r14d
leaq 0xf094(%rip), %rsi      # 0x1cf79
leaq 0xf0fa(%rip), %rdx      # 0x1cfe6
xorl %ebx, %ebx
movl $0x2, %edi
movq %r12, %rcx
movq %r13, %r8
movl %r14d, %r9d
xorl %eax, %eax
callq 0x1a227
leaq 0x6e1de(%rip), %rbp     # 0x7c0e8
leaq (%rbx,%rbp), %r12
addq $0x20, %r12
movq %r12, %rdi
movq %r13, %rsi
callq 0x8350
testq %rax, %rax
jne 0xdf4c
addq $0x400, %rbx            # imm = 0x400
cmpq $0x20000, %rbx          # imm = 0x20000
jne 0xdf0a
xorl %r13d, %r13d
testl %r13d, %r13d
je 0xdf8e
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0xe203(%rip), %rdx      # 0x1c156
movq %r12, %rdi
movl $0x1, %esi
callq 0xf4e1
testq %rax, %rax
je 0xe1a7
leaq 0xe15d(%rip), %rsi      # 0x1c0cd
leaq 0x8(%rsp), %rdx
movq %rax, %rdi
xorl %eax, %eax
callq 0x82d0
xorl %r13d, %r13d
cmpl $0x1, %eax
setne %r13b
jmp 0xe1aa
leaq 0xdb1e(%rip), %rdi      # 0x1bab3
xorl %esi, %esi
callq 0x18004
testq %rax, %rax
jne 0xe01d
movsd 0x10(%rsp), %xmm0
leaq 0xefcb(%rip), %rsi      # 0x1cf79
leaq 0xf060(%rip), %rdx      # 0x1d015
movl $0x2, %edi
movb $0x1, %al
callq 0x1a227
movsd 0x10(%rsp), %xmm0
leaq 0xf0f2(%rip), %rdx      # 0x1d0c0
leaq 0x30(%rsp), %r14
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
movb $0x1, %al
callq 0x8190
leaq 0xdabd(%rip), %rdi      # 0x1baa6
movq %r14, %rsi
callq 0x12e70
cmpb $0x0, 0x9251c(%rip)     # 0xa0514
je 0xe01d
movsd 0x10(%rsp), %xmm0
mulsd 0xd6d8(%rip), %xmm0     # 0x1b6e0
leaq 0xf023(%rip), %rdi      # 0x1d032
leaq 0x924fe(%rip), %rsi     # 0xa0514
movb $0x1, %al
callq 0x12fba
leaq 0xda49(%rip), %rdi      # 0x1ba6d
xorl %esi, %esi
callq 0x18004
testq %rax, %rax
je 0xe286
cmpl $0x0, 0x2c(%rsp)
jne 0xe044
cmpl $-0x1, 0x1ba7e(%rip)    # 0x29ac0
jne 0xe06d
leaq 0xf0bc(%rip), %rdi      # 0x1d107
callq 0x12e75
leaq 0xf0b6(%rip), %rsi      # 0x1d10d
movq %rax, %rdi
callq 0x83b0
xorl %ecx, %ecx
testq %rax, %rax
setne %cl
movl %ecx, 0x1ba53(%rip)     # 0x29ac0
cmpl $0x0, 0x1ba4c(%rip)     # 0x29ac0
je 0xe458
leaq 0xd9c2(%rip), %rdi      # 0x1ba43
callq 0x12e75
leaq 0xe040(%rip), %r14      # 0x1c0cd
leaq 0x8(%rsp), %rdx
movq %rax, %rdi
movq %r14, %rsi
xorl %eax, %eax
callq 0x82d0
movl %eax, %ebp
leaq 0xd9aa(%rip), %rdi      # 0x1ba52
callq 0x12e75
leaq 0x4(%rsp), %rdx
movq %rax, %rdi
movq %r14, %rsi
xorl %eax, %eax
callq 0x82d0
cmpl $0x1, %ebp
jne 0xdf3a
cmpl $0x1, %eax
jne 0xdf3a
movl 0x8(%rsp), %eax
movl 0x4(%rsp), %ecx
cmpl %ecx, %eax
je 0xdf3a
seta %dl
movl 0x18(%rsp), %edi
cmpl $0x2, %edi
setb %sil
movl $0x1, %r14d
orb %dl, %sil
jne 0xe149
movq 0x20(%rsp), %rdx
cmpl $0x1, %edx
adcl $0x0, %edx
cmpl %edi, %edx
cmovael %edi, %edx
movl %ecx, %ecx
xorps %xmm0, %xmm0
cvtsi2sd %rcx, %xmm0
movl %eax, %eax
cvtsi2sd %rax, %xmm1
subsd %xmm1, %xmm0
movl %edi, %eax
cvtsi2sd %rax, %xmm2
addsd 0xed12(%rip), %xmm2     # 0x1ce40
divsd %xmm2, %xmm0
decl %edx
xorps %xmm2, %xmm2
cvtsi2sd %rdx, %xmm2
mulsd %xmm0, %xmm2
addsd %xmm1, %xmm2
cvttsd2si %xmm2, %r14
leaq 0xdf7d(%rip), %rdx      # 0x1c0cd
leaq 0x30(%rsp), %rbx
movl $0x100, %esi            # imm = 0x100
movq %rbx, %rdi
movl %r14d, %ecx
xorl %eax, %eax
callq 0x8190
leaq 0xd8f3(%rip), %rdi      # 0x1ba61
movq %rbx, %rsi
callq 0x12e70
movl 0x8(%rsp), %ecx
movl 0x4(%rsp), %r8d
movsd 0x10(%rsp), %xmm0
leaq 0xeded(%rip), %rsi      # 0x1cf79
leaq 0xeedd(%rip), %rdx      # 0x1d070
movl $0x2, %edi
movl %r14d, %r9d
movb $0x1, %al
callq 0x1a227
jmp 0xe422
xorl %r13d, %r13d
leaq 0xdfa5(%rip), %rdx      # 0x1c156
movq %r12, %rdi
movl $0x2, %esi
callq 0xf4e1
testq %rax, %rax
je 0xe1e4
leaq 0xdf03(%rip), %rsi      # 0x1c0cd
leaq 0x4(%rsp), %rdx
movq %rax, %rdi
xorl %eax, %eax
callq 0x82d0
xorl %ecx, %ecx
cmpl $0x1, %eax
setne %cl
orl %ecx, %r13d
leaq 0xdf6b(%rip), %rdx      # 0x1c156
movq %r12, %rdi
movl $0x3, %esi
callq 0xf4e1
testq %rax, %rax
je 0xe21e
leaq 0xeebc(%rip), %rsi      # 0x1d0c0
leaq 0x10(%rsp), %rdx
movq %rax, %rdi
xorl %eax, %eax
callq 0x82d0
xorl %ecx, %ecx
cmpl $0x1, %eax
setne %cl
orl %ecx, %r13d
addb $-0x41, %r15b
cmpb $0x19, %r15b
ja 0xdf35
testl %r13d, %r13d
jne 0xdf35
addl $-0x3d, %r14d
leaq 0xdf16(%rip), %rdx      # 0x1c156
movq %r12, %rdi
movl %r14d, %esi
callq 0xf4e1
testq %rax, %rax
je 0xdf32
leaq 0xde72(%rip), %rsi      # 0x1c0cd
leaq 0x1c(%rsp), %rdx
movq %rax, %rdi
xorl %eax, %eax
callq 0x82d0
movl $0x1, %r13d
cmpl $0x1, %eax
jne 0xdf35
movl 0x1c(%rsp), %eax
addl %eax, 0x4(%rsp)
jmp 0xdf32
movl 0x8(%rsp), %ecx
movl 0x4(%rsp), %r8d
leaq 0xece3(%rip), %rsi      # 0x1cf79
leaq 0xedaa(%rip), %rdx      # 0x1d047
movl $0x2, %edi
xorl %eax, %eax
callq 0x1a227
movl $0x0, 0xc(%rsp)
leaq 0x91e50(%rip), %rdi     # 0xa0108
leaq 0xde97(%rip), %rdx      # 0x1c156
movq 0x20(%rsp), %rsi
callq 0xf4e1
testq %rax, %rax
je 0xe2f1
leaq 0xddf8(%rip), %rsi      # 0x1c0cd
leaq 0xc(%rsp), %rdx
movq %rax, %rdi
xorl %eax, %eax
callq 0x82d0
cmpl $0x1, %eax
je 0xe2f1
movl $0x0, 0xc(%rsp)
movl 0xc(%rsp), %eax
movl 0x8(%rsp), %ecx
addl %eax, %ecx
addl 0x4(%rsp), %eax
addl 0x6dddf(%rip), %eax     # 0x7c0e4
movl 0x6dded(%rip), %edx     # 0x7c0f8
cmpl %edx, %eax
cmovgel %edx, %eax
movl %eax, 0x4(%rsp)
addl 0x6ddc6(%rip), %ecx     # 0x7c0e0
movl %ecx, 0x8(%rsp)
jg 0xe328
movl $0x1, 0x8(%rsp)
movl 0x8(%rsp), %ecx
cmpl %eax, %ecx
jle 0xe334
movl %ecx, 0x4(%rsp)
leaq 0xdd92(%rip), %r14      # 0x1c0cd
leaq 0x30(%rsp), %r15
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
movq %r14, %rdx
xorl %eax, %eax
callq 0x8190
leaq 0xd6ea(%rip), %rdi      # 0x1ba43
movq %r15, %rsi
callq 0x12e70
movl 0x4(%rsp), %ecx
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
movq %r14, %rdx
xorl %eax, %eax
callq 0x8190
leaq 0xd6d4(%rip), %rdi      # 0x1ba52
movq %r15, %rsi
callq 0x12e70
movl 0x4(%rsp), %ecx
movl 0x8(%rsp), %eax
cmpl %eax, %ecx
setb %dl
movl 0x18(%rsp), %edi
cmpl $0x2, %edi
setb %sil
movl $0x1, %r14d
orb %dl, %sil
jne 0xe3f5
movq 0x20(%rsp), %rdx
cmpl $0x1, %edx
adcl $0x0, %edx
cmpl %edi, %edx
cmovael %edi, %edx
movl %ecx, %ecx
cvtsi2sd %rcx, %xmm0
movl %eax, %eax
cvtsi2sd %rax, %xmm1
subsd %xmm1, %xmm0
movl %edi, %eax
cvtsi2sd %rax, %xmm2
addsd 0xea66(%rip), %xmm2     # 0x1ce40
divsd %xmm2, %xmm0
decl %edx
xorps %xmm2, %xmm2
cvtsi2sd %rdx, %xmm2
mulsd %xmm0, %xmm2
addsd %xmm1, %xmm2
cvttsd2si %xmm2, %r14
leaq 0xdcd1(%rip), %rdx      # 0x1c0cd
leaq 0x30(%rsp), %rbx
movl $0x100, %esi            # imm = 0x100
movq %rbx, %rdi
movl %r14d, %ecx
xorl %eax, %eax
callq 0x8190
leaq 0xd647(%rip), %rdi      # 0x1ba61
movq %rbx, %rsi
callq 0x12e70
cmpb $0x0, 0x920eb(%rip)     # 0xa0514
je 0xdf3a
movl 0x8(%rsp), %edx
addl %edx, %edx
movl 0x4(%rsp), %ecx
addl %ecx, %ecx
leaq 0xec1a(%rip), %rdi      # 0x1d05c
leaq 0x920cb(%rip), %rsi     # 0xa0514
movl %r14d, %r8d
xorl %eax, %eax
callq 0x12fba
jmp 0xdf3a
movl 0x8(%rsp), %ecx
movl 0x4(%rsp), %r8d
movsd 0x10(%rsp), %xmm0
leaq 0xeb0b(%rip), %rsi      # 0x1cf79
leaq 0xec4f(%rip), %rdx      # 0x1d0c4
movl $0x2, %edi
movb $0x1, %al
callq 0x1a227
jmp 0xdf3a