home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / sources / chapter18 / CelticCrusader3 / Characters.bas < prev    next >
Encoding:
BASIC Source File  |  2004-11-03  |  14.2 KB  |  489 lines

  1. Attribute VB_Name = "Characters"
  2. '---------------------------------------------------------------
  3. ' Visual Basic Game Programming for Teens
  4. ' Characters.bas File
  5. '---------------------------------------------------------------
  6.  
  7. Option Explicit
  8. Option Base 0
  9.  
  10. 'main character class data type
  11. Public Type TCHARACTER
  12.     name As String * 20
  13.     classtype As String * 20
  14.     experience As Integer
  15.     level As Integer
  16.     strength As Integer
  17.     dexterity As Integer
  18.     intellect  As Integer
  19.     charisma As Integer
  20.     stamina As Integer
  21.     fillerstr As String * 80
  22.     fillerint(10) As Integer
  23. End Type
  24.  
  25. 'keeps track of NPC state
  26. Public Enum NPCSTATES
  27.     NPC_STOPPED = 0
  28.     NPC_WALKING = 1
  29.     NPC_PAUSED = 2
  30.     NPC_TALKING = 3
  31.     NPC_DYING = 4   'added in chapter 18
  32.     NPC_KILLED = 5
  33.     NPC_ATTACKING = 6
  34. End Enum
  35.  
  36. 'keeps track of each character
  37. Public Type TNPC
  38.     name As String
  39.     state As NPCSTATES
  40.     startpos As point
  41.     curpos As point
  42.     destpos As point
  43.     classindex As Integer
  44.     SpeedDelay As Integer
  45.     SpeedCount As Integer
  46.     facing As Integer
  47.     health As Integer 'added in chapter 18
  48.     dying As Integer
  49. End Type
  50.  
  51. 'generic data for the character classes
  52. 'images and data are shared by the NPCs
  53. Public Const NUMCHARS As Long = 2
  54. Public charWalk(NUMCHARS) As Direct3DTexture8
  55. Public charAttack(NUMCHARS) As Direct3DTexture8
  56. Public charClasses(NUMCHARS) As TCHARACTER
  57.  
  58. 'unique data for each individual NPC
  59. Public Const NUMNPCS As Long = 10
  60. Public charStates(NUMNPCS) As TNPC
  61. Public charWalkSpr(NUMNPCS) As TSPRITE
  62. Public charAttackSpr(NUMNPCS) As TSPRITE
  63.  
  64.  
  65. Public Sub InitCharacters()
  66.     Dim p As point
  67.     Dim n As Long
  68.     
  69.     'load the base character classes
  70.     charClasses(0) = LoadCharacterBinaryFile(App.Path & "\warrior.dat")
  71.     charClasses(1) = LoadCharacterBinaryFile(App.Path & "\knight.dat")
  72.     
  73.     'load up the viking warrior
  74.     Set charWalk(0) = LoadTexture(d3ddev, App.Path & "\viking_axe_walking.bmp")
  75.     Set charAttack(0) = LoadTexture(d3ddev, App.Path & "\viking_axe_attacking.bmp")
  76.     
  77.     'load up the skeleton sword guy
  78.     Set charWalk(1) = LoadTexture(d3ddev, App.Path & "\skeleton_sword_walking.bmp")
  79.     Set charAttack(1) = LoadTexture(d3ddev, App.Path & "\skeleton_sword_attacking.bmp")
  80.     
  81.     'now create the individual characters used in the game
  82.     'all of these will share the base data above
  83.     For n = 0 To NUMNPCS - 1
  84.         
  85.         'initialize walking sprite data
  86.         InitSprite d3ddev, charWalkSpr(n)
  87.         With charWalkSpr(n)
  88.             .FramesPerRow = 8
  89.             .FrameCount = 8
  90.             .AnimDelay = 1
  91.             .width = 96
  92.             .height = 96
  93.         End With
  94.             
  95.         'initialize attacking sprite data
  96.         InitSprite d3ddev, charAttackSpr(n)
  97.         With charAttackSpr(n)
  98.             .FramesPerRow = 10
  99.             .FrameCount = 10
  100.             .AnimDelay = 1
  101.             .width = 96
  102.             .height = 96
  103.         End With
  104.             
  105.         'start NPCs at the player's location
  106.         '(to test NPC movement at this stage)
  107.         p.x = PLAYERSTARTX * TILEWIDTH
  108.         p.y = PLAYERSTARTY * TILEHEIGHT
  109.         
  110.         'customize the Viking character
  111.         With charStates(n)
  112.             
  113.             'this is the key! points to the base image/sprite/data
  114.             .classindex = Random(2)
  115.             
  116.             .name = "Viking"
  117.             .startpos = p
  118.             .curpos = p
  119.             .SpeedDelay = 1
  120.             .SpeedCount = 0
  121.             .health = 60    'added in chapter 18
  122.             .state = NPC_WALKING
  123.             SetRandomDestination charStates(n)
  124.  
  125.         End With
  126.     Next n
  127.     
  128. End Sub
  129.  
  130. 'modified in chapter 18
  131. Public Sub SetRandomDestination(ByRef dude As TNPC)
  132.     With dude
  133.     
  134.         'set random X near the starting position
  135.         '(the NPC will never wander away from his "home")
  136.         .destpos.x = .startpos.x + Random(600)
  137.         If .destpos.x > GAMEWORLDWIDTH Then
  138.             .destpos.x = GAMEWORLDWIDTH - 1
  139.         End If
  140.         
  141.         'set random Y near the starting position
  142.         .destpos.y = .startpos.y + Random(600)
  143.         If .destpos.y > GAMEWORLDHEIGHT Then
  144.             .destpos.y = GAMEWORLDHEIGHT - 1
  145.         End If
  146.     End With
  147. End Sub
  148.  
  149. Public Sub MoveNPC(ByVal num As Long)
  150.     
  151.     'moves a single NPC
  152.     With charStates(num)
  153.     
  154.         If .health < 0 Then .state = NPC_DYING
  155.         
  156.         If .state = NPC_DYING Or .state = NPC_KILLED Then Exit Sub
  157.     
  158.         'update movement rate--exit if not there yet
  159.         .SpeedCount = .SpeedCount + 1
  160.         If .SpeedCount < .SpeedDelay Then Exit Sub
  161.             
  162.         'okay, time to move, reset move counter
  163.         .SpeedCount = 0
  164.         
  165.         'check to see if destination reached
  166.         If .curpos.x = .destpos.x And .curpos.y = .destpos.y Then
  167.             'yes! set a new destination then exit
  168.             .state = NPC_STOPPED
  169.             Exit Sub
  170.         Else
  171.             .state = NPC_WALKING
  172.         End If
  173.  
  174.         'time to set the NPC's "facing" direction
  175.         'and update the X,Y position
  176.         If .curpos.x < .destpos.x Then
  177.             
  178.             'needs to walk westward
  179.             .curpos.x = .curpos.x + 1
  180.             
  181.             If .curpos.y < .destpos.y Then
  182.                 'facing SE
  183.                 .curpos.y = .curpos.y + 1
  184.                 .facing = 3
  185.             ElseIf .curpos.y > .destpos.y Then
  186.                 'facing NE
  187.                 .curpos.y = .curpos.y - 1
  188.                 .facing = 1
  189.             Else
  190.                 'facing EAST
  191.                 .facing = 2
  192.             End If
  193.         
  194.         ElseIf .curpos.x > .destpos.x Then
  195.             
  196.             'needs to walk eastward
  197.             .curpos.x = .curpos.x - 1
  198.             
  199.             If .curpos.y < .destpos.y Then
  200.                 'facing SW
  201.                 .curpos.y = .curpos.y + 1
  202.                 .facing = 5
  203.             ElseIf .curpos.y > .destpos.y Then
  204.                 'facing NW
  205.                 .curpos.y = .curpos.y - 1
  206.                 .facing = 7
  207.             Else
  208.                 'facing WEST
  209.                 .facing = 6
  210.             End If
  211.             
  212.         Else 'must be facing due NORTH or SOUTH
  213.             
  214.             If .curpos.y < .destpos.y Then
  215.                 'facing SOUTH
  216.                 .curpos.y = .curpos.y + 1
  217.                 .facing = 4
  218.             ElseIf .curpos.y > .destpos.y Then
  219.                 'facint NORTH
  220.                 .curpos.y = .curpos.y - 1
  221.                 .facing = 0
  222.             End If
  223.         
  224.         End If
  225.     
  226.     End With
  227. End Sub
  228.  
  229. Public Sub DrawNPC(ByVal num As Long, ByVal color As Long)
  230.     Dim r As RECT
  231.     Dim classindex As Long
  232.     
  233.     'grab a shortcut to these long variable names
  234.     r.Left = charStates(num).curpos.x
  235.     r.Top = charStates(num).curpos.y
  236.     r.Right = r.Left + charWalkSpr(num).width
  237.     r.bottom = r.Top + charWalkSpr(num).height
  238.     
  239.     'remember, images/data are referred to using the NPC's classindex!
  240.     'the sprite and state arrays are for every single unique NPC,
  241.     'but the bitmap image and class data are shared by all NPCs
  242.     classindex = charStates(num).classindex
  243.     
  244.     'now check to see if the sprite is within the scrolling viewport
  245.     'sprite's position is actually global, so this determines if it's visible
  246.     If r.Left > ScrollX - 1 And r.Right < ScrollX + SCREENWIDTH + 1 And _
  247.        r.Top > ScrollY - 1 And r.bottom < ScrollY + SCREENHEIGHT + 1 Then
  248.     
  249.         Select Case charStates(num).state
  250.             Case NPC_ATTACKING
  251.                 AnimateSprite charAttackSpr(num)
  252.                 charAttackSpr(num).x = charStates(num).curpos.x - ScrollX
  253.                 charAttackSpr(num).y = charStates(num).curpos.y - ScrollY
  254.                 charAttackSpr(num).AnimSeq = charStates(num).facing
  255.                 DrawSprite charAttack(classindex), charAttackSpr(num), color
  256.         
  257.             Case Else
  258.                 'update animation frame if walking
  259.                 AnimateSprite charWalkSpr(num)
  260.                 
  261.                 'draw the sprite--remember, it's using the shared image (texture)
  262.                 charWalkSpr(num).x = charStates(num).curpos.x - ScrollX
  263.                 charWalkSpr(num).y = charStates(num).curpos.y - ScrollY
  264.                 charWalkSpr(num).AnimSeq = charStates(num).facing
  265.                 DrawSprite charWalk(classindex), charWalkSpr(num), color
  266.         End Select
  267.     
  268.     End If
  269.  
  270. End Sub
  271.  
  272. Public Sub MoveNPCs()
  273.     Dim n As Long
  274.     
  275.     'loop through all of the NPCs and move them
  276.     For n = 0 To NUMNPCS - 1
  277.         
  278.         Select Case charStates(n).state
  279.         
  280.             Case NPC_ATTACKING
  281.                 'stop attacking if the player leaves or if I'm dead..
  282.                 If charStates(n).health < 0 Then charStates(n).state = NPC_STOPPED
  283.             
  284.                 If Not Collision(charWalkSpr(n), heroSprWalk) Then
  285.                     charStates(n).state = NPC_STOPPED
  286.                 End If
  287.             
  288.             Case NPC_TALKING
  289.                 FacePlayer n
  290.             
  291.             Case NPC_PAUSED
  292.                 SetRandomDestination charStates(n)
  293.             
  294.             Case NPC_WALKING
  295.                 MoveNPC n
  296.                 
  297.             Case NPC_STOPPED
  298.                 SetRandomDestination charStates(n)
  299.             
  300.             Case NPC_DYING
  301.                 charStates(n).destpos = charStates(n).curpos
  302.                 charStates(n).health = charStates(n).health - 1
  303.                 If charStates(n).health < -100 Then
  304.                     charStates(n).state = NPC_KILLED
  305.                 End If
  306.                 
  307.             Case NPC_KILLED
  308.                 KillNPC charStates(n)
  309.             
  310.         End Select
  311.     Next n
  312. End Sub
  313.  
  314. Public Sub KillNPC(ByRef dude As TNPC)
  315.     Dim p As point
  316.     
  317.     p.x = PLAYERSTARTX * TILEWIDTH + Random(1000)
  318.     p.y = PLAYERSTARTY * TILEHEIGHT + Random(1000)
  319.     
  320.     With dude
  321.         .startpos = p
  322.         .curpos = p
  323.         .SpeedDelay = 1
  324.         .SpeedCount = 0
  325.         .health = 20    'added in chapter 18
  326.         .state = NPC_WALKING
  327.         SetRandomDestination dude
  328.     End With
  329.  
  330. End Sub
  331.  
  332. Public Sub CheckNPCCollisions()
  333.     Dim n As Long
  334.     
  335.     'check all NPCs for collisions
  336.     For n = 0 To NUMNPCS - 1
  337.     
  338.         With charStates(n)
  339.         If Collision(charWalkSpr(n), heroSprWalk) Then
  340.             If .state <> NPC_DYING And _
  341.                 .state <> NPC_KILLED And _
  342.                 .state <> NPC_ATTACKING Then
  343.                 
  344.                 .state = NPC_TALKING
  345.             End If
  346.         End If
  347.         End With
  348.     Next n
  349.  
  350. End Sub
  351.  
  352. Public Sub TalkToPlayer(ByVal num As Long)
  353.     Dim x As Long
  354.     Dim y As Long
  355.     
  356.     x = charWalkSpr(num).x + charWalkSpr(num).width / 4
  357.     y = charWalkSpr(num).y
  358.     PrintText fontImg, fontSpr, x, y, C_WHITE, "Hello"
  359.  
  360. End Sub
  361.  
  362. Public Sub FacePlayer(ByVal num As Long)
  363.     Dim a As point
  364.     Dim b As point
  365.     
  366.     a.x = heroSprWalk.x + heroSprWalk.width / 2
  367.     a.y = heroSprWalk.y + heroSprWalk.height / 2
  368.     
  369.     b.x = charWalkSpr(num).x + charWalkSpr(num).width / 2
  370.     b.y = charWalkSpr(num).y + charWalkSpr(num).height / 2
  371.     
  372.     With charStates(num)
  373.         
  374.         If b.x < a.x - 5 Then
  375.             If b.y < a.y - 5 Then
  376.                 .facing = 3
  377.             ElseIf b.y > a.y + 5 Then
  378.                 .facing = 1
  379.             Else
  380.                 .facing = 2
  381.             End If
  382.         
  383.         ElseIf b.x > a.x + 5 Then
  384.             If b.y < a.y - 5 Then
  385.                 .facing = 5
  386.             ElseIf b.y > a.y + 5 Then
  387.                 .facing = 7
  388.             Else
  389.                 .facing = 6
  390.             End If
  391.             
  392.         Else
  393.             If b.y < a.y - 5 Then
  394.                 .facing = 4
  395.             ElseIf b.y > a.y + 5 Then
  396.                 .facing = 0
  397.             End If
  398.         End If
  399.     
  400.     End With
  401. End Sub
  402.  
  403. Public Sub DrawNPCs()
  404.     Dim n As Long
  405.     
  406.     'loop through all of the NPCs and draw them
  407.     For n = 0 To NUMNPCS - 1
  408.         
  409.         Select Case charStates(n).state
  410.             Case NPC_ATTACKING
  411.                 DrawNPC n, C_RED
  412.                 charStates(n).state = NPC_WALKING
  413.             
  414.             Case NPC_TALKING
  415.                 DrawNPC n, C_WHITE
  416.                 charStates(n).state = NPC_WALKING
  417.                 
  418.                 If diState.key(KEY_SPACE) > 0 Then
  419.                     TalkToPlayer n
  420.                 End If
  421.             
  422.             Case NPC_PAUSED
  423.                 DrawNPC n, C_WHITE
  424.                 charStates(n).state = NPC_WALKING
  425.             
  426.             Case NPC_WALKING
  427.                 DrawNPC n, C_WHITE
  428.                 
  429.             Case NPC_STOPPED
  430.                 DrawNPC n, C_WHITE
  431.                 charStates(n).state = NPC_WALKING
  432.                 
  433.             Case NPC_DYING
  434.                 DrawNPC n, &H99FFFFFF
  435.                 
  436.         End Select
  437.     
  438.     Next n
  439. End Sub
  440.  
  441. Public Sub AttackNPC(ByRef target As TNPC, ByVal attack As Long)
  442.  
  443.     'fight back!
  444.     target.state = NPC_ATTACKING
  445.     
  446.     'decrease health
  447.     target.health = target.health - attack
  448.     If target.health < 1 Then
  449.         target.state = NPC_DYING
  450.     End If
  451.     
  452.     'display a message to indicate the NPC was hit!
  453.     PrintText fontImg, fontSpr, _
  454.         heroSprAttack.x, heroSprAttack.y, C_WHITE, _
  455.         "Take that! (" & attack & " pts)"
  456.     
  457.     'make the target respond to the hit
  458.     Dim p As point
  459.     p.x = target.curpos.x - ScrollX
  460.     p.y = target.curpos.y - ScrollY
  461.     PrintText fontImg, fontSpr, _
  462.         p.x, p.y, C_WHITE, _
  463.         "Argh, I've been hit! (" & target.health & ")"
  464.     
  465. End Sub
  466.  
  467. Public Function LoadCharacterBinaryFile(ByVal filename As String) As TCHARACTER
  468.     Dim filenum As Integer
  469.     Dim dude As TCHARACTER
  470.     
  471.     filenum = FreeFile()
  472.     Open filename For Binary As filenum Len = Len(dude)
  473.     Get filenum, , dude
  474.     Close filenum
  475.     
  476.     LoadCharacterBinaryFile = dude
  477. End Function
  478.  
  479. Public Sub SaveCharacterBinaryFile(ByVal filename As String, ByRef dude As TCHARACTER)
  480.     Dim filenum As Integer
  481.     
  482.     filenum = FreeFile()
  483.     Open filename For Binary As filenum Len = Len(dude)
  484.     Put filenum, , dude
  485.     Close filenum
  486. End Sub
  487.  
  488.  
  489.