Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds slot machines. #4022

Merged
merged 1 commit into from
Jul 3, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,7 @@ var/list/WALLITEMS = list(
user << "\blue [target] is empty!"
return

proc/check_target_facings(mob/living/initator, mob/living/target)
/proc/check_target_facings(mob/living/initator, mob/living/target)
/*This can be used to add additional effects on interactions between mobs depending on how the mobs are facing each other, such as adding a crit damage to blows to the back of a guy's head.
Given how click code currently works (Nov '13), the initiating mob will be facing the target mob most of the time
That said, this proc should not be used if the change facing proc of the click code is overriden at the same time*/
Expand All @@ -1318,3 +1318,11 @@ proc/check_target_facings(mob/living/initator, mob/living/target)
return 2
if(initator.dir + 2 == target.dir || initator.dir - 2 == target.dir || initator.dir + 6 == target.dir || initator.dir - 6 == target.dir) //Initating mob is looking at the target, while the target mob is looking in a direction perpendicular to the 1st
return 3

/proc/random_step(atom/movable/AM, steps, chance)
var/initial_chance = chance
while(steps > 0)
if(prob(chance))
step(AM, pick(alldirs))
chance = max(chance - (initial_chance / steps), 0)
steps--
4 changes: 4 additions & 0 deletions code/game/machinery/computer/buildandrepair.dm
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@
/*/obj/item/weapon/circuitboard/prison_shuttle
name = "circuit board (Prison Shuttle)"
build_path = /obj/machinery/computer/prison_shuttle*/
/obj/item/weapon/circuitboard/slot_machine
name = "circuit board (Slot Machine)"
build_path = /obj/machinery/computer/slot_machine
origin_tech = "programming=1"


/obj/item/weapon/circuitboard/supplycomp/attackby(obj/item/I as obj, mob/user as mob)
Expand Down
313 changes: 313 additions & 0 deletions code/game/machinery/slotmachine.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
/*******************************\
| Slot Machines |
| Original code by Glloyd |
| Tgstation port by Miauw |
\*******************************/

#define SPIN_PRICE 5
#define SMALL_PRIZE 400
#define BIG_PRIZE 1000
#define JACKPOT 10000
#define SPIN_TIME 65 //As always, deciseconds.
#define REEL_DEACTIVATE_DELAY 7

/obj/machinery/computer/slot_machine
name = "slot machine"
desc = "Gambling for the antisocial."
icon = 'icons/obj/economy.dmi'
icon_state = "slots1"
anchored = 1
density = 1
use_power = 1
idle_power_usage = 50
circuit = /obj/item/weapon/circuitboard/slot_machine
var/money = 3000 //How much money it has CONSUMED
var/plays = 0
var/working = 0
var/balance = 0 //How much money is in the machine, ready to be CONSUMED.
var/jackpots = 0
var/list/coinvalues = list()
var/list/reels = list(list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0)
var/list/symbols = list("7", "&", "@", "$", "?", "#") //Six symbols, all weighted equally. Chance for 7 sevens is one in 7776. Remember that you influence the chances when adding more symbols!

/obj/machinery/computer/slot_machine/New()
..()
jackpots = rand(1, 4) //false hope
plays = rand(75, 200)

toggle_reel_spin(1) //The reels won't spin unless we activate them

var/list/reel = reels[1]
for(var/i = 0, i < reel.len, i++) //Populate the reels.
randomize_reels()

toggle_reel_spin(0)

for(var/cointype in typesof(/obj/item/weapon/coin))
var/obj/item/weapon/coin/C = new cointype(src)
coinvalues["[cointype]"] = C.value
qdel(C)

/obj/machinery/computer/slot_machine/process()
. = ..() //Sanity checks.
if(!.)
return .

money++ //SPESSH MAJICKS

/obj/machinery/computer/slot_machine/update_icon()
if(stat & NOPOWER)
icon_state = "slots0"

else if(stat & BROKEN)
icon_state = "slotsb"

else if(working)
icon_state = "slots2"

else
icon_state = "slots1"

/obj/machinery/computer/slot_machine/power_change()
..()
update_icon()

/obj/machinery/computer/slot_machine/attackby(obj/item/I, mob/living/user)
if(istype(I, /obj/item/weapon/coin))
var/obj/item/weapon/coin/C = I
if(prob(2))
user.drop_item()
C.loc = loc
C.throw_at(user, 3, 10)
if(prob(10))
balance = max(balance - SPIN_PRICE, 0)
user << "<span class='warning'>[src] spits your coin back out!</span>"

else
user.drop_item()
user << "<span class='notice'>You insert a [C.cmineral] coin into [src]'s slot!</span>"
balance += C.value
qdel(C)

return

else if(istype(I, /obj/item/weapon/card/emag) && !emagged)
emagged = 1

var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(4, 0, src.loc)
spark_system.start()
playsound(src.loc, "sparks", 50, 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put an

else
    ...()

at the end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


else
..()

/obj/machinery/computer/slot_machine/attack_hand(mob/living/user)
. = ..() //Sanity checks.
if(.)
return .

interact(user)

/obj/machinery/computer/slot_machine/interact(mob/living/user)
var/reeltext = {"<center><font face=\"courier new\">
/*****^*****^*****^*****^*****\\<BR>
| \[[reels[1][1]]\] | \[[reels[2][1]]\] | \[[reels[3][1]]\] | \[[reels[4][1]]\] | \[[reels[5][1]]\] |<BR>
| \[[reels[1][2]]\] | \[[reels[2][2]]\] | \[[reels[3][2]]\] | \[[reels[4][2]]\] | \[[reels[5][2]]\] |<BR>
| \[[reels[1][3]]\] | \[[reels[2][3]]\] | \[[reels[3][3]]\] | \[[reels[4][3]]\] | \[[reels[5][3]]\] |<BR>
\\*****v*****v*****v*****v*****/<BR>
</center></font>"}

var/dat
if(working)
dat = reeltext

else
dat = {"Five credits to play!<BR>
<B>Prize Money Available:</B> [money] (jackpot payout is ALWAYS 100%!)<BR>
<B>Credit Remaining:</B> [balance]<BR>
[plays] players have tried their luck today, and [jackpots] have won a jackpot!<BR>
<HR><BR>
<A href='?src=\ref[src];spin=1'>Play!</A><BR>
<BR>
[reeltext]
<BR>
<font size='1'><A href='?src=\ref[src];refund=1'>Refund balance</A><BR>"}

var/datum/browser/popup = new(user, "slotmachine", "Slot Machine")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()

/obj/machinery/computer/slot_machine/Topic(href, href_list)
. = ..() //Sanity checks.
if(.)
return .

if(href_list["spin"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this code needs to be in their own procs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most is probably a hyperbole, but there is a bit of copypasta in the prizes I guess ¯_(ツ)_/¯

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't exaggerating.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find putting large chunks of code in Topic() very hard to track what does what. Putting the code in a proc and calling it from the Topic() will make it easier to separate the different concepts, which is the UI selection (if href and etc) and the result of the UI selection (spinning the machine).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you forget to do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just sort of disagree with your opinion.
The code is neatly seperated from the rest and putting it in a proc seems rather useless.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not an opinion and it is not useless. You may have a different perspective if you have been modifying the code all day but for someone like me who reviews it and maybe wants to change something, it is very valuable to be able to read the code and instantly have a good understanding of the structure and organisation of the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed this BUT YOU COMMENTED ON A LINE I DIDNT CHANGE DAMNIT GIA ;_;

spin(usr)

else if(href_list["refund"])
give_coins(balance)
balance = 0

/obj/machinery/computer/slot_machine/emp_act(severity)
if(stat & (NOPOWER|BROKEN))
return
if(prob(15 * severity))
return
if(prob(1)) // :^)
emagged = 1
var/severity_ascending = 4 - severity
money = max(rand(money - (200 * severity_ascending), money + (200 * severity_ascending)), 0)
balance = max(rand(balance - (50 * severity_ascending), balance + (50 * severity_ascending)), 0)
money -= max(0, give_coins(min(rand(-50, 100 * severity_ascending)), money)) //This starts at -50 because it shouldn't always dispense coins yo
spin()

/obj/machinery/computer/slot_machine/proc/spin(mob/user)
if(!can_spin(user))
return

var/the_name
if(user)
the_name = user.real_name
visible_message("<span class='notice'>[user] pulls the lever and the slot machine starts spinning!</span>")
else
the_name = "Exaybachay"

balance -= SPIN_PRICE
money += SPIN_PRICE
plays += 1
working = 1

toggle_reel_spin(1)
update_icon()
updateDialog()

spawn(0)
while(working)
randomize_reels()
updateDialog()
sleep(2)

spawn(SPIN_TIME - (REEL_DEACTIVATE_DELAY * reels.len)) //WARNING: no sanity checking for user since it's not needed and would complicate things (machine should still spin even if user is gone), be wary of this if you're changing this code.
toggle_reel_spin(0, REEL_DEACTIVATE_DELAY)
working = 0
give_prizes(the_name, user)
update_icon()
updateDialog()

/obj/machinery/computer/slot_machine/proc/can_spin(mob/user)
if(stat & NOPOWER)
user << "<span class='warning'>The slot machine has no power!</span>"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You use "user" but you don't give it as an argument in spin()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:^)

if(stat & BROKEN)
user << "<span class='warning'>The slot machine is broken!</span>"
if(working)
user << "<span class='warning'>You need to wait until the machine stops spinning before you can play again!</span>"
return 0
if(balance < SPIN_PRICE)
user << "<span class='warning'>Insufficient money to play!</span>"
return 0
return 1

/obj/machinery/computer/slot_machine/proc/toggle_reel_spin(value, delay = 0) //value is 1 or 0 aka on or off
for(var/list/reel in reels)
reels[reel] = value
sleep(delay)

/obj/machinery/computer/slot_machine/proc/randomize_reels()

for(var/reel in reels)
if(reels[reel])
reel[3] = reel[2]
reel[2] = reel[1]
reel[1] = pick(symbols)

/obj/machinery/computer/slot_machine/proc/give_prizes(usrname, mob/user)
var/linelength = get_lines()

if(reels[1][2] + reels[2][2] + reels[3][2] + reels[4][2] + reels[5][2] == "77777")
visible_message("<b>[src]</b> says, 'JACKPOT! You win [money] credits worth of coins!'")
priority_announce("Congratulations to [user ? user.real_name : usrname] for winning the jackpot at the slot machine in [get_area(src)]!")
jackpots += 1
balance += money - give_coins(JACKPOT)
money = 0

for(var/i = 0, i < 5, i++)
var/cointype = pick(typesof(/obj/item/weapon/coin) - /obj/item/weapon/coin)
var/obj/item/weapon/coin/C = new cointype(loc)
random_step(C, 2, 50)

else if(linelength == 5)
visible_message("<b>[src]</b> says, 'Big Winner! You win a thousand credits worth of coins!'")
give_money(BIG_PRIZE)

else if(linelength == 4)
visible_message("<b>[src]</b> says, 'Winner! You win four hundred credits worth of coins!'")
give_money(SMALL_PRIZE)

else if(linelength == 3)
user << "<span class='notice'>You win six free games!</span>"
balance += SPIN_PRICE * 7
money = max(money - SPIN_PRICE * 7, money)

else
user << "<span class='warning'>No luck!</span>"

/obj/machinery/computer/slot_machine/proc/get_lines()
var/amountthesame

for(var/i = 1, i <= 3, i++)
var/inputtext = reels[1][i] + reels[2][i] + reels[3][i] + reels[4][i] + reels[5][i]
for(var/symbol in symbols)
var/j = 3 //The lowest value we have to check for.
var/symboltext = symbol + symbol + symbol
while(j <= 5)
if(findtext(inputtext, symboltext))
amountthesame = max(j, amountthesame)
j++
symboltext += symbol

if(amountthesame)
break

return amountthesame

/obj/machinery/computer/slot_machine/proc/give_money(amount)
var/amount_to_give = money >= amount ? amount : money
var/surplus = amount_to_give - give_coins(amount_to_give)
money = max(0, money - amount)
balance += surplus

/obj/machinery/computer/slot_machine/proc/give_coins(amount)
var/cointype = emagged ? /obj/item/weapon/coin/iron : /obj/item/weapon/coin/silver

if(!emagged)
amount = dispense(amount, cointype, null, 0)

else
var/mob/living/target = locate() in range(src, 2)

amount = dispense(amount, cointype, target, 1)

return amount

/obj/machinery/computer/slot_machine/proc/dispense(amount = 0, cointype = /obj/item/weapon/coin/silver, mob/living/target, throw = 0)
var/value = coinvalues["[cointype]"]


while(amount >= value)
var/obj/item/weapon/coin/C = new cointype(loc) //DOUBLE THE PAIN
amount -= value
if(throw && target)
C.throw_at(target, 3, 10)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the line that was supposed to be replaced by dispense(), the act of removing the coin from the machine and determining whether to throw it or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather duplicate two lines of code that are basically next to eachother than put an if() into a while loop that loops a hundred times tbh.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually you are duplicating the loop and the only difference is the line. So it is much more than 2 lines of code.

else
random_step(C, 2, 40)

return amount

#undef SPIN_TIME
#undef JACKPOT
#undef BIG_PRIZE
#undef SMALL_PRIZE
#undef SPIN_PRICE