- Posts: 345
- Thank you received: 73
Please Log in or Create an account to join the conversation.
WhiskyTest wrote: I had fun writing this at work today because it was so quiet
It is a new ACMD function called 'simulate'.
Get two characters in a room with you and type:
simulate <arg1> <arg2> <number>
(arg1 and arg2 should be the names of the characters)
It will simulate a battle for the two characters however many times you specify for <number> (currently capped at 100 but feel free to alter!)
Then it will tell you who won, how many times, and the average number of combat rounds each fight took.
I wrote it for stock tbaMUD so you will need to change parts to match your own combat system.
In terms of the data displaued I left it pretty lightweight for now because I'm not sure what data would be useful.
The idea is that we can now "playtest" 100 battles with a mob instantly!
The results do NOT take into account skills that might be used, or combat triggers that might fire, but it will calculate equipment bonuses - so I reckon it should give a fairly accurate approximation.
Add to act.hCode:ACMD(do_simulate);
Add to interpreter.cCode:{ "simulate" , "simulate", POS_DEAD , do_simulate , LVL_GOD, 0 },
Add to the end of fight.cCode:/* Usage: simulate <character> <character> <number of battles> * * Intended to assist with balancing, pick two characters in the room with you and * Example: simulate WhiskyTest Orc 100 * * I've capped it at 100 battles, be careful of the do-while loop. Everything will pause * until this completes, potentially freezing your MUD while it works out each battle. * * Change the battle routine to suit your MUD combat rolls * Add new counters to track additional data! * */ ACMD(do_simulate) { /* Data we wish to track for storing in the arrays */ #define WINS 0 #define LOSSES 1 /* Add data counters in here, remember to increment MAX_DATA */ #define MAX_DATA 2 char arg1[MAX_INPUT_LENGTH]; /* arguments for the ACMD function */ char arg2[MAX_INPUT_LENGTH]; char arg3[MAX_INPUT_LENGTH]; int number, x, round; /* Number = number of battles, x = generic counter, round = which round this is */ bool round_over; /* Is the round over yet? Controls the do-while loop*/ int actor1_results[MAX_DATA], actor2_results[MAX_DATA]; /* arrays to store our data */ int total_rounds, diceroll; /* total_rounds = for averaging how long each fight was, diceroll = for rand_number(1, 20) */ int actor1_hitp, actor1_damage, actor1_ac, actor1_calc_thaco, actor1_success; /* Actor1 variables */ int actor2_hitp, actor2_damage, actor2_ac, actor2_calc_thaco, actor2_success; /* Actor2 variables */ struct char_data *actor1, *actor2; /* Our two actors for the simulation, actor1 will always hit first */ one_argument(two_arguments(argument, arg1, arg2), arg3); /* three_arguments */ /* Check we have enough arguments */ if(!*arg1 || !*arg2|| !*arg3) { send_to_char(ch, "Usage: simulate <character 1> <character 2> <#number of battles>\r\n"); return; } /* Check for visible characters in room */ if (!(actor1 = get_char_vis(ch, arg1, NULL, FIND_CHAR_ROOM))) { send_to_char(ch, "%s? %s", arg1, CONFIG_NOPERSON); return; } if (!(actor2 = get_char_vis(ch, arg2, NULL, FIND_CHAR_ROOM))) { send_to_char(ch, "%s? %s", arg2, CONFIG_NOPERSON); return; } number = MIN(MAX(atoi(arg3), 0), 100); send_to_char(ch, "OK - I will simulate a battle to the death between \tR%s\tn and \tB%s \tG%d\tn times!\r\n", GET_NAME(actor1), GET_NAME(actor2), number); /* Zero out the arrays and set all variables to starting values */ for (x = 0; x < MAX_DATA; x++) { actor1_results[x] = 0; actor2_results[x] = 0; } total_rounds = 0; /* Set all of Actor 1's battle statistics */ actor1_ac = compute_armor_class(actor1) / 10; actor1_calc_thaco = compute_thaco(actor1, actor2); actor1_damage = str_app[STRENGTH_APPLY_INDEX(actor1)].todam; actor1_damage += GET_DAMROLL(actor1); if(GET_EQ(actor1, WEAR_WIELD) && GET_OBJ_TYPE(GET_EQ(actor1, WEAR_WIELD)) == ITEM_WEAPON ) { actor1_damage += ((GET_OBJ_VAL(GET_EQ(actor1, WEAR_WIELD), 2) + 1) / 2.0) * GET_OBJ_VAL(GET_EQ(actor1, WEAR_WIELD), 1); } else { if (IS_NPC(actor1)) actor1_damage += ((actor1->mob_specials.damsizedice + 1) / 2.0) * actor1->mob_specials.damnodice; else actor1_damage += 1; } if (AFF_FLAGGED(actor2, AFF_SANCTUARY)) actor1_damage /= 2; /* Set all of Actor 2's battle statistics */ actor2_ac = compute_armor_class(actor2) / 10; actor2_calc_thaco = compute_thaco(actor2, actor1); actor2_damage = str_app[STRENGTH_APPLY_INDEX(actor2)].todam; actor2_damage += GET_DAMROLL(actor2); if(GET_EQ(actor2, WEAR_WIELD) && GET_OBJ_TYPE(GET_EQ(actor2, WEAR_WIELD)) == ITEM_WEAPON ) { actor2_damage += ((GET_OBJ_VAL(GET_EQ(actor2, WEAR_WIELD), 2) + 1) / 2.0) * GET_OBJ_VAL(GET_EQ(actor2, WEAR_WIELD), 1); } else { if (IS_NPC(actor2)) actor2_damage += ((actor2->mob_specials.damsizedice + 1) / 2.0) * actor2->mob_specials.damnodice; else actor2_damage += 1; } if (AFF_FLAGGED(actor1, AFF_SANCTUARY)) actor2_damage /= 2; /* Now simulate the combat and record stats! * * Begin battle loop : */ for (x = 1; x <= number; x++) { /* Reset values for new combat */ actor1_hitp = GET_MAX_HIT(actor1); actor2_hitp = GET_MAX_HIT(actor2); round_over = 0; round = 0; /* Start combat rounds until one wins */ while (round_over == 0) { round++; /* Actor1 first */ diceroll = rand_number(1, 20); if (diceroll == 20) actor1_success = 1; else if (diceroll == 1) actor1_success = 0; else if (actor1_calc_thaco - diceroll <= actor2_ac) actor1_success = 1; if (actor1_success) actor2_hitp -= actor1_damage; /* Check to see if Actor 2 is out of the fight */ if (actor2_hitp <= 0) { actor1_results[WINS]++; /* Increment data counters here */ actor2_results[LOSSES]++; round_over = 1; break; } /* Actor 2 has a crack at it */ diceroll = rand_number(1, 20); if (diceroll == 20) actor2_success = 1; else if (diceroll == 1) actor2_success = 0; else if (actor2_calc_thaco - diceroll <= actor1_ac) actor2_success = 1; if (actor2_success) actor1_hitp -= actor2_damage; if (actor1_hitp <= 0) { actor2_results[WINS]++; /* Increment data counters here */ actor1_results[LOSSES]++; round_over = 1; break; } } /* End of combat round */ total_rounds += round; } /* End of Battle loop */ /* Display Results! */ send_to_char(ch, "Results:\r\n"); send_to_char(ch, "Average rounds per fight: %d\r\n", total_rounds / number); send_to_char(ch, "\tR%s\tn wins: \tR%d\tn\r\n", GET_NAME(actor1), actor1_results[WINS]); send_to_char(ch, "\tB%s\tn wins: \tB%d\tn\r\n", GET_NAME(actor2), actor2_results[WINS]); return; }
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
tbaMUD © 2024