
/*****************************
* Johnny's blackjack mod
******************************
*
* Try it out on my server! [DuDeS] - Freakin Sweet
* 129.237.51.145:27015
*
******************************
*
* And yes, I fully realize that there can be more than 4
* of any card (aces, 2's, 3's), but I don't think anybody
* really cares that much.
*
* CVARS:
* amx_blackjack_enabled  -- 0 = off
*                           1 = on
*
* amx_blackjack_deadonly -- 0 = off
*                           1 = on
* COMMANDS:
* amx_blackjack  -- starts a fun fun game of blackjack.
* say blackjack  -- also starts a fun fun game of blackjack.
*
*****************************/

#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <fun>

/**************************************************************************/
/***********************       DECLARATIONS         ***********************/
/**************************************************************************/

#define MAX_CARDS 22
#define MAX_MENU_CHARS 256

// Each player's cards.
new player_cards[32][MAX_CARDS]
// The cards of the dealer (unique to each player of course).
new dealer_cards[32][MAX_CARDS]

// Each player's bet amount.
new player_bet[32]

/**************************************************************************/
/***********************       THE ACTUAL CODE      ***********************/
/**************************************************************************/

public client_connect(id)
{
	set_task(20.0, "announce", id)
}

public announce(id)
{
	if (is_user_alive(id) && get_cvar_num("amx_blackjack_deadonly") == 1)
		client_print(id, print_chat, "[BLKJK] Type blackjack once you're dead to play!")
	else if (is_user_alive(id) && get_cvar_num("amx_blackjack_deadonly") == 0)
		client_print(id, print_chat, "[BLKJK] Type blackjack to play!")
	set_task(80.0, "announce", id)
	return PLUGIN_HANDLED
}

public client_putinserver(id)
{
	if (is_user_alive(id) && get_cvar_num("amx_blackjack_deadonly") == 1)
		client_print(id, print_chat, "[BLKJK] Type blackjack once you're dead to play!")
	else if (is_user_alive(id) && get_cvar_num("amx_blackjack_deadonly") == 0)
		client_print(id, print_chat, "[BLKJK] Type blackjack to play!")
}

public StartBlackJack(id)
{
	new card_num

	if (get_cvar_num("amx_blackjack_enabled") == 0)
	{
		client_print(id,print_chat,"[BLKJK] Sorry, blackjack is currently disabled.")	
	}
	else if (is_user_alive(id) && get_cvar_num("amx_blackjack_deadonly") == 1)
	{
		client_print(id,print_chat,"[BLKJK] You can't play blackjack while you're alive, dummy.")	
	}
	else
	{
		// Reset the cards for this player (and their dealer)
		for(card_num=0; card_num < MAX_CARDS; card_num++)
		{
			player_cards[id][card_num] = 0
			dealer_cards[id][card_num] = 0
		}

		// Give this player (and their dealer) a couple random cards.
		player_cards[id][0] = random_num(1,13)
		player_cards[id][1] = random_num(1,13)
		dealer_cards[id][0] = random_num(1,13)
		dealer_cards[id][1] = random_num(1,13)
		
		// This player has bet no money yet, yo.
		player_bet[id] = 0

		// Show the betting menu.
		ShowBetMenu(id)
	}
	return PLUGIN_CONTINUE
}

ShowBetMenu(id)
{
	new user_base_cash
	new user_money
	new menu_body[256]
	new menu_keys
	new View1000, View100, View10, View1

	/////////////////		
	// Format the blackjack menu.
	/////////////////

	// Currently they can only press number 5 (for no money) or 0 (for exit)
	menu_keys = (1<<4)|(1<<9)

	// Get how much money they have available.
	user_base_cash = cs_get_user_money(id)
	user_money = user_base_cash - player_bet[id]

	// Enable/disable menu commands according to funds.
	View1000 = View100 = View10 = View1 = 'd'
	if (user_money >= 1000)
	{
		View1000 = 'w'
		menu_keys |= (1<<0)
	}

	if (user_money >= 100)
	{
		View100 = 'w'
		menu_keys |= (1<<1)
	}

	if (user_money >= 10)
	{
		View10 = 'w'
		menu_keys |= (1<<2)
	}

	if (user_money >= 1)
	{
		View1 = 'w'
		menu_keys |= (1<<3)
	}
	
	// Put it all together in a big string.
	format(menu_body,256,"\y[BLKJK] Set your bet:^n^nCurrent funds: %d^nCurrent bet: %d^n\%c1. 1000^n\%c2. 100^n\%c3. 10^n\%c4. 1^n\w5. Done^n^n\w0. Nuts to this. (exit)", user_base_cash, player_bet[id], View1000, View100, View10, View1)
	
	// Send it to the player.
	show_menu(id,menu_keys,menu_body,10)  
}

public SetBet(id,key){ 
	switch(key)
	{
		case 0:
		{
			// Add to their bet.
			player_bet[id] += 1000
			ShowBetMenu(id)
		}
		case 1:
		{
			// Add to their bet.
			player_bet[id] += 100
			ShowBetMenu(id)
		}
		case 2:
		{
			// Add to their bet.
			player_bet[id] += 10
			ShowBetMenu(id)
		}
		case 3:
		{
			// Add to their bet.
			player_bet[id] += 1
			ShowBetMenu(id)
		}
		case 4:
		{
			// They're done betting.
			ShowGameMenu(id, false)
		}
	}
	return PLUGIN_HANDLED
}

ShowGameMenu(id, game_done)
{
	new player_total = 0 // Player's total (of card values).
	new dealer_total = 0 // Dealer's total (of card values).
	new card_num         // Card incrementer.
	new player_has_ace   // Does the player have an ace?
	new dealer_has_ace   // Does the dealer have an ace?
	new player_cards_string[MAX_CARDS * 3]   // A string for the player's cards.
	new dealer_cards_string[MAX_CARDS * 3]   // A string for the dealer's cards.
	new card_temp_player[3] // A temporary card string.
	new card_temp_dealer[3] // A temporary card string.
	new menu_body[MAX_MENU_CHARS]  // The menu body message.
	new menu_keys       // The menu keys.
	new user_money

	player_has_ace = false
	dealer_has_ace = false

	for (card_num = 0; card_num < MAX_CARDS; card_num++)
	{
		switch(player_cards[id][card_num])
		{
			case 0:
			{
				// No card in this slot.
			}
			case 1:
			{
				// An ace.
				player_has_ace = true
				player_total += 1
				add(player_cards_string, MAX_CARDS * 3, "A ");
			}
			case 11:
			{
				// A Jack.
				player_total += 10
				add(player_cards_string, MAX_CARDS * 3, "J ");
			}
			case 12:
			{
				// A Queen.
				player_total += 10
				add(player_cards_string, MAX_CARDS * 3, "Q ");
			}
			case 13:
			{
				// A King.
				player_total += 10
				add(player_cards_string, MAX_CARDS * 3, "K ");
			}
			case 10:
			{
				// A Ten.
				player_total += 10
				add(player_cards_string, MAX_CARDS * 3, "10 ");
			}
			default:
			{
				// Just a simple number.
				player_total += player_cards[id][card_num]
				format(card_temp_player,3,"%d ",player_cards[id][card_num])
				add(player_cards_string, MAX_CARDS * 3, card_temp_player)
			}
		}
	}

	if (player_total > 21)
	{
		game_done = true
	}
	else if(game_done)
	{
		// Player didn't bust, and the game's over.
		// The dealer needs to play.
		if (player_has_ace && (player_total < 12))
		{
			DealerPlay(id, player_total + 10)
		}
		else
		{
			DealerPlay(id, player_total)
		}
	}

	for (card_num = 0; card_num < MAX_CARDS; card_num++)
	{
		switch(dealer_cards[id][card_num])
		{
			case 0:
			{
				// No card in this slot.
			}
			case 1:
			{
				// An ace.
				dealer_has_ace = true
				dealer_total += 1
				if(card_num==0 && !game_done)
				{
					add(dealer_cards_string, MAX_CARDS * 3, "# ");
				}
				else
				{
					add(dealer_cards_string, MAX_CARDS * 3, "A ");
				}
			}
			case 11:
			{
				// A Jack.
				dealer_total += 10
				if(card_num==0 && !game_done)
				{
					add(dealer_cards_string, MAX_CARDS * 3, "# ");
				}
				else
				{
					add(dealer_cards_string, MAX_CARDS * 3, "J ");
				}
			}
			case 12:
			{
				// A Queen.
				dealer_total += 10
				if(card_num==0 && !game_done)
				{
					add(dealer_cards_string, MAX_CARDS * 3, "# ");
				}
				else
				{
					add(dealer_cards_string, MAX_CARDS * 3, "Q ");
				}
			}
			case 13:
			{
				// A King.
				dealer_total += 10
				if(card_num==0 && !game_done)
				{
					add(dealer_cards_string, MAX_CARDS * 3, "# ");
				}
				else
				{
					add(dealer_cards_string, MAX_CARDS * 3, "K ");
				}
			}
			case 10:
			{
				// A Ten.
				dealer_total += 10
				if(card_num==0 && !game_done)
				{
					add(dealer_cards_string, MAX_CARDS * 3, "# ");
				}
				else
				{
					add(dealer_cards_string, MAX_CARDS * 3, "10 ");
				}
			}
			default:
			{
				// Just a simple number.
				dealer_total += dealer_cards[id][card_num]
				if(card_num==0 && !game_done)
				{
					add(dealer_cards_string, MAX_CARDS * 3, "# ");
				}
				else
				{
					format(card_temp_dealer,3,"%d ",dealer_cards[id][card_num])
					add(dealer_cards_string, MAX_CARDS * 3, card_temp_dealer)
				}
			}
		}
	}

	/////////////////		
	// Format the game menu.
	/////////////////

	if (game_done)
	{
		if (player_has_ace && (player_total < 12))
		{
			player_total += 10
		}

		if (dealer_has_ace && (dealer_total < 12))
		{
			dealer_total += 10
		}

		// They can only restart or exit.
		menu_keys = (1<<8)|(1<<9)

		// Get how much money they have.
		user_money = cs_get_user_money(id)

		if (player_total > 21)
		{
			//They busted!
			format(menu_body,MAX_MENU_CHARS,"\y[BLKJK] Game state:^n^nDealer's cards:   \w%s^n\yDealer's total:   \w%d^n^n\yYour cards:     \w%s^n\yYour total:      \w%d^n^n\rYou lost! (You busted)^n^n\w9. Play again!^n0. Exit", dealer_cards_string, dealer_total, player_cards_string, player_total)
			cs_set_user_money(id,user_money - player_bet[id])
		}
		else if (dealer_total > 21)
		{
			//Dealer busted!
			format(menu_body,MAX_MENU_CHARS,"\y[BLKJK] Game state:^n^nDealer's cards:   \w%s^n\yDealer's total:   \w%d^n^n\yYour cards:     \w%s^n\yYour total:      \w%d^n^n\wYou won! (Dealer busted)^n^n\w9. Play again!^n0. Exit", dealer_cards_string, dealer_total, player_cards_string, player_total)
			cs_set_user_money(id,user_money + player_bet[id])
		}
		else
		{
			if (player_total > dealer_total)
			{
				//They won
				format(menu_body,MAX_MENU_CHARS,"\y[BLKJK] Game state:^n^nDealer's cards:   \w%s^n\yDealer's total:   \w%d^n^n\yYour cards:     \w%s^n\yYour total:      \w%d^n^n\wYou won!^n^n\w9. Play again!^n0. Exit", dealer_cards_string, dealer_total, player_cards_string, player_total)
				cs_set_user_money(id,user_money + player_bet[id])
			}
			else if(player_total < dealer_total)
			{
				//Dealer won.
				format(menu_body,MAX_MENU_CHARS,"\y[BLKJK] Game state:^n^nDealer's cards:   \w%s^n\yDealer's total:   \w%d^n^n\yYour cards:     \w%s^n\yYour total:      \w%d^n^n\rYou lost!^n^n\w9. Play again!^n0. Exit", dealer_cards_string, dealer_total, player_cards_string, player_total)
				cs_set_user_money(id,user_money - player_bet[id])
			}
			else
			{
				//Tie game.
				format(menu_body,MAX_MENU_CHARS,"\y[BLKJK] Game state:^n^nDealer's cards:   \w%s^n\yDealer's total:   \w%d^n^n\yYour cards:     \w%s^n\yYour total:      \w%d^n^n\wTie game!^n^n\w9. Play again!^n0. Exit", dealer_cards_string, dealer_total, player_cards_string, player_total)
			}
		}
	}
	else
	{
		// They can hit or stand.
		menu_keys = (1<<0)|(1<<1)
		
		// Format the game board and stuff.
		if (player_has_ace && (player_total < 12))
		{
			format(menu_body,MAX_MENU_CHARS,"\y[BLKJK] Game state:^n^nDealer's cards:   \w%s^n^n\yYour cards:     \w%s^n\yYour total:      \w%d (or %d)^n^n\w1. Hit^n2. Stand", dealer_cards_string, player_cards_string, player_total, player_total + 10)
		}
		else
		{
			format(menu_body,MAX_MENU_CHARS,"\y[BLKJK] Game state:^n^nDealer's cards:   \w%s^n^n\yYour cards:     \w%s^n\yYour total:      \w%d^n^n\w1. Hit^n2. Stand", dealer_cards_string, player_cards_string, player_total)
		}
	}

	// Send it to the player.
	show_menu(id,menu_keys,menu_body)
}

DealerPlay(id, player_total)
{
	new has_ace
	new dealer_total
	new card_num
	new done_playing
	new empty_slot = 0

	done_playing = false

	while(!done_playing)
	{
		for (card_num = 0; card_num < MAX_CARDS; card_num++)
		{
			switch(dealer_cards[id][card_num])
			{
				case 0:
				{
					// No card in this slot.
					if (empty_slot == 0)
					{
						empty_slot = card_num;
					}
				}
				case 1:
				{
					// An ace.
					has_ace = true;
					dealer_total += 1
				}
				case 11:
				{
					// A Jack.
					dealer_total += 10
				}
				case 12:
				{
					// A Queen.
					dealer_total += 10
				}
				case 13:
				{
					// A King.
					dealer_total += 10
				}
				default:
				{
					// Just a simple number.
					dealer_total += dealer_cards[id][card_num]
				}
			}
		}

		if (dealer_total >= player_total)
		{
			// Dealers don't attempt to go over the value they need to.
			done_playing = true
		}
		else
		{
			if (has_ace && (dealer_total < 12))
			{
				// Dealer has a significant ambiguous ace.
				if (dealer_total + 10 >= player_total)
				{
					// Dealer + ace value (as 11) is over player's value.
					done_playing = true
				}
				else
				{
					// Dealer's gonna risk not using the ace.
					dealer_cards[id][empty_slot] = random_num(1,13)
				}
			}
			else
			{
				// Dealer decides to hit.
				dealer_cards[id][empty_slot] = random_num(1,13)
			}
		}
	}
}

public PlayGame(id,key){ 
	new card_num       // A card number incrementer.
	new empty_slot = 0 // An empty card slot (to add a card to).

	switch(key)
	{
		case 0:
		{
			// They're hitting.
			for (card_num = 0; card_num < MAX_CARDS; card_num++)
			{
				if (player_cards[id][card_num] == 0 && empty_slot == 0)
				{
					empty_slot = card_num;
				}
			}
			player_cards[id][empty_slot] = random_num(1,13)
			ShowGameMenu(id, false)
		}
		case 1:
		{
			// They're standing.
			ShowGameMenu(id, true)
		}
		case 8:
		{
			//They want to play again! :D
			StartBlackJack(id)
		}
	}
	return PLUGIN_HANDLED
}

public plugin_init() 
{ 
	// This registers my great plugin
	register_plugin("Johnnys Blackjack","1.0","Johnny") 

	// Registers the client commands.
	register_clcmd("say blackjack", "StartBlackJack")
	register_clcmd("amx_blackjack", "StartBlackJack")
	
	// This registers the menus.
	register_menucmd(register_menuid("[BLKJK] Set your bet:"),1023,"SetBet")
	register_menucmd(register_menuid("[BLKJK] Game state:"),1023,"PlayGame")

	// This registers the CVARS used.
	register_cvar("amx_blackjack_enabled","1")
	register_cvar("amx_blackjack_deadonly","1")

	return PLUGIN_CONTINUE
}

/**************************************************************************/
/**************************************************************************/
/**************************************************************************/

