301 Days

A year of gamedev experiments.

Day 72

| Comments

In which we achieve some limited closure.

Test Every Day

Rest when dead but not lawful, in a map with no karma res point, if not a thief

Is this really the last of the Underworld cases? Wonderful. Given what we already have, it’s pretty trivial to do:

features/config_file.featurelink
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
# Rest when dead but not lawful, in a map with no karma res point, if not a thief
Scenario: UnderworldEnabled True, neutral non-thief corpse goes there if no karma res point
  Given I use the "minimal" database
 And I set "UnderworldEnabled" in the config file to "True"
 And I remove the karma res point for map "0"
 And I add player and character "TestBadCorpse04"
 And I set the character's alignment to neutral
 And I set the character's current HP to "1"
 And I put poison berries in the the character's right hand
 And the server is started
 When I log on as "TestBadCorpse04"
 And I enter the game
    And I eat "berries"
 And within "10" turns I see the message "You are dead"
 And I rest
 Then I saw a message "The world dissolves around you."

Scenario: UnderworldEnabled False, neutral non-thief corpse doesn't go there if no karma res point
  Given I use the "minimal" database
 And I set "UnderworldEnabled" in the config file to "False"
 And I remove the karma res point for map "0"
 And I add player and character "TestBadCorpse04"
 And I set the character's alignment to neutral
 And I set the character's current HP to "1"
 And I put poison berries in the the character's right hand
 And the server is started
 When I log on as "TestBadCorpse04"
 And I enter the game
    And I eat "berries"
 And within "10" turns I see the message "You are dead"
 And I rest
 Then I did not see a message "The world dissolves around you."

I took the opportunity to refactor the alignment step a little, so it’s just one step that passes on the specific alignment as a symbol:

features/steps/character_steps.rblink
93
94
95
Given(/^I set the character's alignment to (lawful|neutral|evil)$/) do |desired_alignment|
  set_character_alignment(get_player_id(@user[:char_name]), desired_alignment.to_sym)
end

and then I mirror the enum in the server code to push the appropriate value to the DB:

features/lib/db/player.rblink
136
137
138
139
140
141
142
143
144
145
146
147
148
149
def set_character_alignment(player_id, desired_alignment)
  alignment_list = [ :none, :lawful, :neutral, :chaotic, :evil, :amoral, :all ]
  alignment_num = alignment_list.index(desired_alignment)
  debug_msg "Alignment #{desired_alignment} is number #{alignment_num}"
  fail "Unknown alignment" if alignment_num.nil?
  client = connect_to_db(@server_database)
  query = "UPDATE [#{@server_database}].[dbo].[Player] SET \
    alignment = #{alignment_num} \
    WHERE playerID = '#{player_id}'"
  debug_msg query
  result = client.execute(query)
  affected_rows = result.do
  fail "Unable to update player!" if 1 != affected_rows
end

The best way to do it? Not sure; further refactoring will definitely occur as we move toward testing two separate server implementations.

1
2
3
50 scenarios (50 passed)
430 steps (430 passed)
11m47.827s

Tackle a TODO every other day

Looking at the TODOs in the test repository, a lot of them have to do with hardcoded IDs. For example:

features/steps/character_steps.rblink
8
9
10
11
Given(/^I put a spellbook in the the character's right hand$/) do
  # TODO - not hardcoded item ID
  put_attuned_in_player_hand(get_player_id(@user[:char_name]), 31000, :right)
end

This code only works for databases where the ID for a spellbook happens to be 31000, and gets poor marks for readability. Let’s add a very flexible item ID lookup method and use that:

features/steps/character_steps.rblink
8
9
10
11
Given(/^I put a spellbook in the the character's right hand$/) do
  item_id = lookup_item_id({ name: 'spellbook' })
  put_attuned_in_player_hand(get_player_id(@user[:char_name]), item_id, :right)
end
features/lib/db/item.rblink
30
31
32
33
34
35
36
37
38
39
def lookup_item_id(lookup_hash)
  client = connect_to_db(@server_database)
  query = db_field_from_hash('CatalogItem', lookup_hash, 'itemID')
  debug_msg "Query is #{query}"
  result = client.execute(query)
  row = result.each(:first => true)
  debug_msg row.inspect
  fail "Unable to get itemID!" if 1 != result.affected_rows
  row[0]['itemID']
end
features/lib/db/sql_misc.rblink
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def db_field_from_hash(table_name, db_hash, return_field)
  where_clauses = []
  db_hash.keys.each do |key|
    if db_hash[key].is_a?(String)
      where_clauses << "#{key}='#{db_hash[key]}'"
    elsif db_hash[key].nil?
      where_clauses << "#{key}=NULL"
    else
      where_clauses << "#{key}=#{db_hash[key]}"
    end
  end
  query = "SELECT #{return_field} FROM [dbo].[#{table_name}] " +
          "WHERE #{where_clauses.join(' AND ')}"
end

We’ll probably refactor this further once we have two different data storage mechanisms, but this will work for now.

Similar code removes a lot of the TODOs, and eventually:

1
2
3
Searching 31 files for "TODO"

0 matches

Added another test for fun

I even added a test while I was messing with the player effect code:

features/temp.featurelink
4
5
6
7
8
9
10
11
12
13
14
15
Scenario: Multiple character effects stack correctly
  Given I use the "minimal" database
 And I add player and character "TestSubject01"
 And I inflict fear on the character for "2" turns
 And I blind the character for "4" turns
 And the server is started
 When I log on as "TestSubject01"
 And I enter the game
 Then I saw a message "You are scared!"
 And after "2" turns I no longer see the message "You are scared!"
 Then I saw a message "You are blind!"
 And after "2" turns I no longer see the message "You are blind!"

Simple, but forced me to learn:

  • the PlayerEffect slots are one-based, not zero-based (initially my first-applied effect was ignored).
  • the display of fear overrides the display of blindess (I’m tempted to call this a bug).

Now:

1
2
3
51 scenarios (51 passed)
441 steps (441 passed)
12m28.001s

And maybe we can add a bunch more player effect tests. Tomorrow.


Useful Stuff


Day 72 code - tests

Comments