Initial commit

This commit is contained in:
WatermelonModders
2022-05-31 12:35:46 -04:00
commit fc5cb0c32c
4097 changed files with 447075 additions and 0 deletions
+487
View File
@@ -0,0 +1,487 @@
/*
hm_gameserver - hearthmod gameserver
Copyright (C) 2016 Filip Pancik
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <game.h>
static int log_enable = 1;
static struct option_s *fill_option(u64 type, u64 id, struct suboption_target_s *targets)
{
struct option_s *option;
option = malloc(sizeof(*option));
memset(option, 0, sizeof(*option));
option->type = type;
if(id != -1) {
option->mainoption = malloc(sizeof(*(option->mainoption)));
memset(option->mainoption, 0, sizeof(*(option->mainoption)));
option->mainoption->id = id;
option->mainoption->target = targets;
}
return option;
}
static void add_suboption_target(struct suboption_target_s **so, u64 id)
{
struct suboption_target_s *s;
s = malloc(sizeof(*s));
s->value = id;
s->next = *so;
*so = s;
}
int set_options_cards(struct card_list_s *cl, char *buffer, char *endbuffer, int turn)
{
struct packet_s *packet;
struct alloptions_s *all;
struct option_s *option = NULL, *o;
struct card_list_s *c;
for(c = cl; c != NULL; c = c->next) {
o = fill_option(6, c->card->id, NULL);
o->next = option;
option = o;
}
o = fill_option(2, -1, NULL);
o->next = option;
option = o;
all = malloc(sizeof(*all));
all->id = turn;
all->options = option;
alloptions_dump(all);
add_packet(&packet, all, P_ALLOPTIONS);
char *ptr = buffer;
int n = serialize(packet, &ptr, endbuffer);
//hm_log(LOG_NOTICE, lg, "set options:");
//bin_dump(buffer, n);
return n;
}
static void set_options_board(struct option_s **option, struct card_s *card, struct deck_s *opponent, const int taunt_count)
{
struct option_s *o;
int j;
struct suboption_target_s *so = NULL;
if(
(flag(&card->state, CARD_BOARD, FLAG_ISSET) &&
!flag(&card->state, CARD_DESTROYED, FLAG_ISSET) &&
!flag(&card->state, CARD_SPELL, FLAG_ISSET) &&
!flag(&card->state, CARD_FROZEN, FLAG_ISSET) ) &&
/*( flag(&card->state, CARD_HERO, FLAG_ISSET) && card->attack > 0) */
card->attack > 0
) {
if(!flag(&card->state, CARD_TARGETING, FLAG_ISSET) && !flag(&card->state, CARD_TARGETING_BC, FLAG_ISSET)) {
goto add;
}
if(log_enable) hm_log(LOG_NOTICE, lg, "setting targets for card %d", card->id);
for(j = 0; j < opponent->ncards; j++) {
if((flag(&opponent->cards[j]->state, CARD_BOARD, FLAG_ISSET) ||
flag(&opponent->cards[j]->state, CARD_HERO, FLAG_ISSET) ) &&
!flag(&opponent->cards[j]->state, CARD_DESTROYED, FLAG_ISSET)
) {
// if taunt cards on board, does enemy have taunt
if(taunt_count > 0 && !flag(&card->state, CARD_HEROPOWER, FLAG_ISSET)) {
if(flag(&opponent->cards[j]->state, CARD_TAUNT, FLAG_ISSET)) {
hm_log(LOG_DEBUG, lg, "\tadding opponent taunt card %d as a target", opponent->cards[j]->id);
add_suboption_target(&so, opponent->cards[j]->id);
}
} else {
hm_log(LOG_DEBUG, lg, "\tadding opponent card %d as a target", opponent->cards[j]->id);
add_suboption_target(&so, opponent->cards[j]->id);
}
}
}
add:
o = fill_option(3, card->id, so);
o->next = *option;
*option = o;
} /*else {
hm_log(LOG_ALERT, lg, "Card %d: board %d desttroyed %d frozen %d spell %d", card->id,
flag(&card->state, CARD_BOARD, FLAG_ISSET),
flag(&card->state, CARD_DESTROYED, FLAG_ISSET),
flag(&card->state, CARD_FROZEN, FLAG_ISSET),
flag(&card->state, CARD_SPELL, FLAG_ISSET)
);
} */
}
enum side_e {
SIDE_PLAYER = 0,
SIDE_OPPONENT
};
static void calc_targets(struct deck_s *deck, struct card_s *attacker, enum side_e side, struct suboption_target_s **so)
{
int i;
struct card_s *defender;
int debug = 0;
for(i = 0; i < deck->ncards; i++) {
defender = deck->cards[i];
// ignore destroyed, spell, not board and not hero
if(flag(&defender->state, CARD_SPELL, FLAG_ISSET) ||
(!flag(&defender->state, CARD_BOARD, FLAG_ISSET) && !flag(&defender->state, CARD_HERO, FLAG_ISSET)) ||
flag(&defender->state, CARD_DESTROYED, FLAG_ISSET)
) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", defender->id);
continue;
}
// culling blade
if(flag(&attacker->state, CARD_TARGET_30PERCENT_LESS, FLAG_ISSET) &&
(defender->health * 3) > defender->total_health) {
continue;
}
// magic immunity
if(flag(&attacker->state, CARD_SPELL, FLAG_ISSET) &&
!flag(&attacker->state, CARD_PIERCE_MAGIC_IMMUNITY, FLAG_ISSET) &&
flag(&defender->state, CARD_DIVINE_SHIELD, FLAG_ISSET)) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// battlecry
/*
if(flag(&attacker->state, CARD_TARGET_BC_AUTO, FLAG_ISSET)) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
*/
// allies
if(flag(&attacker->state, CARD_TARGET_ALLY, FLAG_ISSET) && side == SIDE_OPPONENT ) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// enemies
if(flag(&attacker->state, CARD_TARGET_ENEMY, FLAG_ISSET) && side == SIDE_PLAYER) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// ally bosses
if(flag(&attacker->state, CARD_TARGET_ALLY_BOSSES, FLAG_ISSET) &&
(side == SIDE_OPPONENT || !flag(&defender->state, CARD_BOSS, FLAG_ISSET))
) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// enemy bosses
if(flag(&attacker->state, CARD_TARGET_ENEMY_BOSSES, FLAG_ISSET) &&
(side == SIDE_PLAYER || !flag(&defender->state, CARD_BOSS, FLAG_ISSET))
) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// bosses
if(flag(&attacker->state, CARD_TARGET_BOSSES, FLAG_ISSET) &&
(!flag(&defender->state, CARD_BOSS, FLAG_ISSET))
) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// board target (exc. heroes)
if(flag(&attacker->state, CARD_TARGET_BOARD, FLAG_ISSET) &&
(flag(&defender->state, CARD_HERO, FLAG_ISSET))) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// ally board target (exc. heroes)
if(flag(&attacker->state, CARD_TARGET_ALLY_BOARD, FLAG_ISSET) &&
(side == SIDE_OPPONENT || flag(&defender->state, CARD_HERO, FLAG_ISSET))) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// enemy board target (exc. heroes)
if(flag(&attacker->state, CARD_TARGET_ENEMY_BOARD, FLAG_ISSET) &&
(side == SIDE_PLAYER || flag(&defender->state, CARD_HERO, FLAG_ISSET))) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// skip non-hero targets if only heroes are valid targets
if(flag(&attacker->state, CARD_TARGET_HERO, FLAG_ISSET) &&
!flag(&defender->state, CARD_HERO, FLAG_ISSET)) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// enemy hero
if(flag(&attacker->state, CARD_TARGET_ENEMY_HERO, FLAG_ISSET) &&
(side == SIDE_PLAYER || !flag(&defender->state, CARD_HERO, FLAG_ISSET))
) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// ally hero
if(flag(&attacker->state, CARD_TARGET_ALLY_HERO, FLAG_ISSET) &&
(side == SIDE_OPPONENT || !flag(&defender->state, CARD_HERO, FLAG_ISSET))) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// minions
if(flag(&attacker->state, CARD_TARGET_MINIONS, FLAG_ISSET) &&
(flag(&defender->state, CARD_HERO, FLAG_ISSET) || flag(&defender->state, CARD_BOSS, FLAG_ISSET))) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// enemy minions
if(flag(&attacker->state, CARD_TARGET_ENEMY_MINIONS, FLAG_ISSET) &&
(side == SIDE_PLAYER || flag(&defender->state, CARD_HERO, FLAG_ISSET) || flag(&defender->state, CARD_BOSS, FLAG_ISSET))) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// ally minions
if(flag(&attacker->state, CARD_TARGET_ALLY_MINIONS, FLAG_ISSET) &&
(side == SIDE_OPPONENT || flag(&defender->state, CARD_HERO, FLAG_ISSET) || flag(&defender->state, CARD_BOSS, FLAG_ISSET))
) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// allies
if((flag(&attacker->state, CARD_TARGET_ALLY, FLAG_ISSET) && side == SIDE_OPPONENT)) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// undamaged minion eg. backstab
if(flag(&attacker->state, CARD_TARGET_UNDAMAGED_MINION, FLAG_ISSET)
&&
(defender->total_health != defender->health ||
flag(&defender->state, CARD_HERO, FLAG_ISSET)) ) {
continue;
}
// undamaged minion eg. execute
if(flag(&attacker->state, CARD_TARGET_DAMAGED_MINION, FLAG_ISSET)
&&
(defender->total_health == defender->health ||
flag(&defender->state, CARD_HERO, FLAG_ISSET))) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// shadow word: pain
if(flag(&attacker->state, CARD_TARGET_3ATTACK_LESS, FLAG_ISSET) &&
( defender->attack > 3 ||
flag(&defender->state, CARD_HERO, FLAG_ISSET) )) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// shadow word: death
if(flag(&attacker->state, CARD_TARGET_5ATTACK_MORE, FLAG_ISSET) &&
(defender->attack < 5 ||
flag(&defender->state, CARD_HERO, FLAG_ISSET))) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// Ursa
if(flag(&attacker->state, CARD_TARGET_URSA, FLAG_ISSET) &&
strcmp(defender->entity->name, CN_URSA) != 0) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// Sven
if(flag(&attacker->state, CARD_TARGET_SVEN, FLAG_ISSET) &&
strcmp(defender->entity->name, CN_SVEN) != 0) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
// sacr. pact
if(flag(&attacker->state, CARD_TARGET_DEMON, FLAG_ISSET) &&
( !flag(&defender->state, CARD_RACE_DEMON, FLAG_ISSET) ||
flag(&defender->state, CARD_HERO, FLAG_ISSET))) {
if(debug) hm_log(LOG_DEBUG, lg, "target exit for card %d", deck->cards[i]->id);
continue;
}
if(debug) hm_log(LOG_DEBUG, lg, "\tadding card %d as a target of [%s](%d)", defender->id, attacker->entity->desc, attacker->id);
add_suboption_target(so, defender->id);
}
}
int set_options(struct deck_s *deck, struct deck_s *opponent, char *buffer, char *endbuffer, int turn)
{
int i;
int taunt_count;
struct packet_s *packet;
struct alloptions_s *all;
struct option_s *option = NULL, *o = NULL;
assert(opponent);
// does enemy board contain taunt?
taunt_count = deck_get_taunts(opponent);
// find playable cards
for(i = 0; i < deck->ncards; i++) {
// exhausted or frozen
if(flag(&deck->cards[i]->state, CARD_EXHAUSTED, FLAG_ISSET) ||
flag(&deck->cards[i]->state, CARD_FROZEN, FLAG_ISSET)) {
if(log_enable) hm_log(LOG_DEBUG, lg, "skipping card %d as it's exhausted or frozen", deck->cards[i]->id);
continue;
}
// not on board, in hand, heropower or frozen
if(!flag(&deck->cards[i]->state, CARD_BOARD, FLAG_ISSET) &&
!flag(&deck->cards[i]->state, CARD_HAND, FLAG_ISSET) &&
!flag(&deck->cards[i]->state, CARD_HEROPOWER, FLAG_ISSET) &&
!flag(&deck->cards[i]->state, CARD_TARGETING_BC, FLAG_ISSET)) {
if(log_enable) hm_log(LOG_DEBUG, lg, "skipping card %d as it's not: on board, in hand, heropower or hero with attack", deck->cards[i]->id);
continue;
}
// set options to cards placed on board
if(!flag(&deck->cards[i]->state, CARD_HEROPOWER, FLAG_ISSET)) {
set_options_board(&option, deck->cards[i], opponent, taunt_count);
}
int board_count = cards_get_board_count(deck, NULL, 0, -1);
// set playable in hand cards that are not spells/bc
if(flag(&deck->cards[i]->state, CARD_HAND, FLAG_ISSET) &&
!flag(&deck->cards[i]->state, CARD_SPELL, FLAG_ISSET) &&
!flag(&deck->cards[i]->state, CARD_TARGETING_BC, FLAG_ISSET) &&
deck->cards[i]->cost <= (deck->mana - deck->mana_used) &&
board_count < MAX_BOARD
) {
o = fill_option(3, deck->cards[i]->id, NULL);
o->next = option;
option = o;
if(log_enable) hm_log(LOG_DEBUG, lg, "setting playable card [%s](%d) in hand and it's not a spell, board count %d", deck->cards[i]->entity->desc, deck->cards[i]->id, board_count);
continue;
}
// set in-hand spells, targeting battlecries
if((flag(&deck->cards[i]->state, CARD_SPELL, FLAG_ISSET) &&
flag(&deck->cards[i]->state, CARD_HAND, FLAG_ISSET))
||
(flag(&deck->cards[i]->state, CARD_HAND, FLAG_ISSET) &&
flag(&deck->cards[i]->state, CARD_TARGETING_BC, FLAG_ISSET))
||
flag(&deck->cards[i]->state, CARD_WEAPON, FLAG_ISSET)
||
flag(&deck->cards[i]->state, CARD_HEROPOWER, FLAG_ISSET)
) {
if(log_enable) hm_log(LOG_DEBUG, lg, "Considering Spell/Battlecry card %d", deck->cards[i]->id);
if(flag(&deck->cards[i]->state, CARD_TARGETING_BC, FLAG_ISSET) && board_count >= MAX_BOARD) {
if(log_enable) hm_log(LOG_DEBUG, lg, "Battlecry card %d igrnoed as board is full", deck->cards[i]->id);
continue;
}
if(deck->cards[i]->cost > (deck->mana - deck->mana_used)) {
if(log_enable) hm_log(LOG_DEBUG, lg, "Spell card %d too expensive", deck->cards[i]->id);
continue;
}
if(log_enable) hm_log(LOG_DEBUG, lg, "Card [%s](%d) with cost %d accepted", deck->cards[i]->entity->desc, deck->cards[i]->id, deck->cards[i]->cost);
struct suboption_target_s *so = NULL;
if(flag(&deck->cards[i]->state, CARD_TARGETING, FLAG_ISSET) || flag(&deck->cards[i]->state, CARD_TARGETING_BC, FLAG_ISSET)) {
if(log_enable) hm_log(LOG_NOTICE, lg, "setting targets for card [%s](%d)", deck->cards[i]->entity->desc, deck->cards[i]->id);
calc_targets(deck, deck->cards[i], SIDE_PLAYER, &so);
calc_targets(opponent, deck->cards[i], SIDE_OPPONENT, &so);
}
if(so != NULL ||
flag(&deck->cards[i]->state, CARD_NONTARGET, FLAG_ISSET)
) {
o = fill_option(/*deck->cards[i]->cardtype*/ 3, deck->cards[i]->id, so);
o->next = option;
option = o;
}
}
}
o = fill_option(2, -1, NULL);
o->next = option;
option = o;
all = malloc(sizeof(*all));
all->id = turn;
all->options = option;
alloptions_dump(all);
add_packet(&packet, all, P_ALLOPTIONS);
char *ptr = buffer;
int n = serialize(packet, &ptr, endbuffer);
packet_free(packet);
//hm_log(LOG_NOTICE, lg, "set options:");
//bin_dump(buffer, n);
return n;
}