Reputation: 125
I have this function and I am trying to use two large functions made up of smaller ones and one while loops. One for when it's the players turn, one when it's the opponent's turn, and a while loop when the player has won. When I run it in the browser, the buttons do not do anything. What is wrong?
$attackButtonClick = (opponent) ->
if playersTurn and not player.Win
player.attack(opponent)
if opponent.currentHealth <= 0
player.Win = true;
allOff()
postBattle(opponent)
else
playersTurn = false;
opponentTurn(opponent)
$defendButtonClick = (opponent) ->
if playersTurn and not player.Win
player.defend()
appendToBattleOutputBox "<p>Your defense has been doubled for one turn.</p>"
if opponent.currentHealth <= 0
player.Win = true;
allOff()
return postBattle(opponent)
else
playersTurn = false;
opponentTurn(opponent)
$useItemButtonClick = (opponent) ->
if playersTurn and not player.Win
if $useItemSelection.html().length > 15
itemBeingUsed = $("select[name='useItemSelection'] option:selected").text()
switch itemBeingUsed
when "Book of Spells"
player.Items.bookOfSpells.use()
if player.Items.bookOfSpells.effect is "burn" or player.Items.bookOfSpells.effect is "poison"
appendToBattleOutputBox "<p>You have #{player.Items.bookOfSpells.effect}ed #{opponent.Name}.</p>"
if player.Items.bookOfSpells.effect is "burn"
opponent.Burned = true;
else
opponent.Poisoned = true;
else
appendToBattleOutputBox "<p>You have frozen #{opponent.Name}.</p>"
opponent.Frozen = true;
player.Items.bookOfSpells.used = true;
when "Shield Charm"
if (player.Items.shieldCharm.used is false)
player.Items.shieldCharm.use()
appendToBattleOutputBox "<p>You will block the next attack with you shield charm.</p>"
player.Items.shieldCharm.used = true;
when "Normal Potion"
player.Items.normalPotion.use()
if opponent.currentHealth <= 0
player.Win = true;
allOff()
postBattle(opponent)
else
playersTurn = false;
opponentTurn(opponent)
else
noUsableItemP = $("<p id='noUsableItemP'>You have no usable items. Select another command.</p>")
$battleCommandPromptDiv.empty()
$battleCommandPromptDiv.append(noUsableItemP)
battle = (opponent) ->
console.log(p)
appendToBattleOutputBox "<p>You make the first move!</p>"
battleInProgress = yes;
playersTurn = true;
playerTurn = (opponent) ->
$attackButton.click -> $attackButtonClick(opponent)
$defendButton.click -> $defendButtonClick(opponent)
$useItemButton.click -> $useItemButtonClick(opponent)
status.Poison("opponent", opponent) if opponent.Poisoned
status.Burn("opponent", opponent) if opponent.Burned
status.Freeze("opponent", opponent) if opponent.Frozen
opponent.undefend() if opponent.defenseDoubled or opponent.defenseTripled
refresh(opponent)
opponentTurn = (opponent) ->
if not playersTurn and not player.Win
if rndmNumber(10) > 5
thisTurnAttack = opponent.attack(opponent.Attack, opponent.Luck)
player.currentHealth -= thisTurnAttack
refresh(opponent)
if thisTurnAttack is 0 then appendToBattleOutputBox "<p class='right'>You have blocked the attack.</p>" else appendToBattleOutputBox "<p class='right'>#{thisTurnAttack} damage has been inflicted upon you.</p>"
else
opponent.defend()
appendToBattleOutputBox "<p class='right'>#{opponent.Name} has doubled his defense for one turn.</p>"
player.undefend() if player.defenseDoubled or player.defenseTripled
player.Poisoned = true if (opponent.Type is "Snake" and rndmNumber(10) > 7)
player.Burned = true if (opponent.Name is "Salamander" and rndmNumber(10) > 3) or opponent.Name is "Fire Dragon"
player.Frozen = true if (opponent.Name is "Penguin" and rndmNumber(10) > 5) or (opponent.Name is "Wolf" and rndmNumber(10) > 6) or (opponent.Name is "Polar Bear" and rndmNumber(10) > 4)
status.Poison("player") if player.Poisoned
status.Burn("player") if player.Burned
status.Freeze("player") if player.Frozen
if player.currentHealth <= 0 then postBattle(opponent) else playerTurn(opponent)
playersTurn = true;
playerTurn(opponent)
while (player.Win is true)
player.Win is false;
postBattle(opponent)
P.S. disregard the semicolons after true and false. I know they aren't supposed to be there.
UPDATE
Now my problem is that when I try calling opponentTurn
it is not defined. I have tried looking up a way to hoist a function in Coffeescript, but have found nothing. Is there a way to hoist the function or just another way to order the code?
$attackButtonClick = (opponent) ->
console.log(playersTurn)
if playersTurn and not player.Win
player.attack(opponent)
if opponent.currentHealth <= 0
player.Win = true;
allOff()
postBattle(opponent)
else
playersTurn = false;
opponentTurn(opponent)
$defendButtonClick = (opponent) ->
if playersTurn and not player.Win
player.defend()
appendToBattleOutputBox "<p>Your defense has been doubled for one turn.</p>"
if opponent.currentHealth <= 0
player.Win = true;
allOff()
return postBattle(opponent)
else
playersTurn = false;
opponentTurn(opponent)
$useItemButtonClick = (opponent) ->
if playersTurn and not player.Win
if $useItemSelection.html().length > 15
itemBeingUsed = $("select[name='useItemSelection'] option:selected").text()
switch itemBeingUsed
when "Book of Spells"
player.Items.bookOfSpells.use()
if player.Items.bookOfSpells.effect is "burn" or player.Items.bookOfSpells.effect is "poison"
appendToBattleOutputBox "<p>You have #{player.Items.bookOfSpells.effect}ed #{opponent.Name}.</p>"
if player.Items.bookOfSpells.effect is "burn"
opponent.Burned = true;
else
opponent.Poisoned = true;
else
appendToBattleOutputBox "<p>You have frozen #{opponent.Name}.</p>"
opponent.Frozen = true;
player.Items.bookOfSpells.used = true;
when "Shield Charm"
if (player.Items.shieldCharm.used is false)
player.Items.shieldCharm.use()
appendToBattleOutputBox "<p>You will block the next attack with you shield charm.</p>"
player.Items.shieldCharm.used = true;
when "Normal Potion"
player.Items.normalPotion.use()
if opponent.currentHealth <= 0
player.Win = true;
allOff()
postBattle(opponent)
else
playersTurn = false;
opponentTurn(opponent)
else
noUsableItemP = $("<p id='noUsableItemP'>You have no usable items. Select another command.</p>")
$battleCommandPromptDiv.empty()
$battleCommandPromptDiv.append(noUsableItemP)
battle = (opponent) ->
appendToBattleOutputBox "<p>You make the first move!</p>"
battleInProgress = yes;
playerTurn = (opponent) ->
$attackButton.click -> $attackButtonClick(opponent)
$defendButton.click -> $defendButtonClick(opponent)
$useItemButton.click -> $useItemButtonClick(opponent)
status.Poison("opponent", opponent) if opponent.Poisoned
status.Burn("opponent", opponent) if opponent.Burned
status.Freeze("opponent", opponent) if opponent.Frozen
opponent.undefend() if opponent.defenseDoubled or opponent.defenseTripled
refresh(opponent)
opponentTurn = (opponent) ->
if not playersTurn and not player.Win
if rndmNumber(10) > 5
thisTurnAttack = opponent.attack(opponent.Attack, opponent.Luck)
player.currentHealth -= thisTurnAttack
refresh(opponent)
if thisTurnAttack is 0 then appendToBattleOutputBox "<p class='right'>You have blocked the attack.</p>" else appendToBattleOutputBox "<p class='right'>#{thisTurnAttack} damage has been inflicted upon you.</p>"
else
opponent.defend()
appendToBattleOutputBox "<p class='right'>#{opponent.Name} has doubled his defense for one turn.</p>"
player.undefend() if player.defenseDoubled or player.defenseTripled
player.Poisoned = true if (opponent.Type is "Snake" and rndmNumber(10) > 7)
player.Burned = true if (opponent.Name is "Salamander" and rndmNumber(10) > 3) or opponent.Name is "Fire Dragon"
player.Frozen = true if (opponent.Name is "Penguin" and rndmNumber(10) > 5) or (opponent.Name is "Wolf" and rndmNumber(10) > 6) or (opponent.Name is "Polar Bear" and rndmNumber(10) > 4)
status.Poison("player") if player.Poisoned
status.Burn("player") if player.Burned
status.Freeze("player") if player.Frozen
if player.currentHealth <= 0 then postBattle(opponent) else playerTurn(opponent)
playersTurn = true;
playerTurn(opponent)
while (player.Win is true)
player.Win is false;
postBattle(opponent)
P.S. disregard the semicolons after true and false. I know they aren't supposed to be there.
Upvotes: 0
Views: 126
Reputation: 29989
There's no easy way to explain this. You've fundamentally misunderstood how Javascript (and by extension Coffeescript) works.
Javascript is an asynchronous language which doesn't block on io. When you do things like this
while (playerTurn is true and player.Win is false)
$attackButton.click ->
player.attack(opponent)
...
You're entering a loop which registers a callback for a click event and then runs the loop again. This is happening, hundreds, probably thousands of times because of the nature of your while loop. That's why your browser has crashed.
A good way to check this kind of thing out is to use debugging statements with console.log, this way you'll be able to see how often different sections of your code are being entered by looking at the number of printed outputs in your console.
You need to restructure the logic of your game, so that rather than doing while loops and waiting for blocking conditions to happen; you have a set of functions that call each other when events take place.
What I would suggest is something like this:
attack = ->
# conditions go here instead
if playerTurn and not player.Win
player.attack(opponent)
if opponent.currentHealth <= 0
player.Win = true
allOff()
# return statements aren't needed inside callback functions
postBattle(opponent)
else
playerTurn = false;
# not inside a while loop
$attackButton.click attack
You can use this model for any 'event' in your game e.g. a button click or a changed condition etc.
UPDATE
Coffeescript doesn't support function hoisting, so you've only really got two options here. Try to untangle your code so that you can write it out in fashion that doesn't require using functions that haven't yet been defined, or as I prefer to do, use Livescript.
Livescript has a lot of compatibility with Coffeescript and it brings a lot of useful features to the table with a similar syntax. One of the features is function hoisting. Your hoisted function would be declared like this:
function opponentTurn (opponent)
...
# rather than
opponentTurn = (opponent) ->
...
Which will respectively compile to
function opponentTurn(opponent){
...
}
var opponentTurn;
opponentTurn = function(opponent){
...
};
I couldn't recommend Livescript enough as an alternative to Coffeescript.
http://livescript.net/blog/ten-reasons-to-switch-from-coffeescript.html
Upvotes: 4