594 lines
17 KiB
GDScript
594 lines
17 KiB
GDScript
extends CharacterBody2D
|
|
|
|
class_name Cow
|
|
|
|
signal moved
|
|
|
|
var interactionsInRange = []
|
|
|
|
var targetInteraction
|
|
var interactionTrigger
|
|
|
|
var cowState = "Idle"
|
|
var currentInteractingItem
|
|
var currentInteractingGroundItem
|
|
var interactingSpeed
|
|
|
|
var currentInteractingBuildingZone
|
|
|
|
var interactionTimer = 0
|
|
var interactionState = "none"
|
|
|
|
var lastInteractionCheckThreshold = 100
|
|
|
|
var movementTarget:Vector2
|
|
var movementThreshold = 0.1
|
|
var moveSpeed:int = 200
|
|
|
|
var fastWalking = false
|
|
|
|
var swimmingZones = []
|
|
var soakTimer = 2
|
|
|
|
var facingLeft:bool = true
|
|
|
|
var defaultVisiblesPosition
|
|
|
|
var lastPosition
|
|
var pointsForXpDrop = 100
|
|
var movementXpProgress = 0
|
|
var movementXpAmount = 5
|
|
var timeMovedMultiplier = 10
|
|
var distanceMovedMultiplier = 0.1
|
|
|
|
var maxMovementThresholdForXP = 50
|
|
|
|
var wisdom = []
|
|
var wisdomDelays = []
|
|
var wisdomTimer = 0
|
|
var wisdomIndex = 0
|
|
|
|
var rng = RandomNumberGenerator.new()
|
|
|
|
func _ready():
|
|
defaultVisiblesPosition = %Visuals.position
|
|
|
|
fastWalking = false
|
|
|
|
movementTarget = position
|
|
lastPosition = position
|
|
face_direction(false)
|
|
|
|
func _process(delta):
|
|
if !cowState == "Riding":
|
|
if targetInteraction != null:
|
|
if target_interaction_range_check():
|
|
movementTarget = global_position
|
|
else:
|
|
movement(delta)
|
|
else:
|
|
movement(delta)
|
|
|
|
if cowState == "Drinking":
|
|
drinking(delta)
|
|
if cowState == "Weaving":
|
|
weaving(delta)
|
|
if cowState == "Building":
|
|
building(delta)
|
|
if cowState == "Playing":
|
|
playing(delta)
|
|
if cowState == "Demolishing":
|
|
demolishing(delta)
|
|
|
|
if interactionTimer > 0:
|
|
interactionTimer -= delta
|
|
if interactionTimer <= 0:
|
|
if cowState == "Eating":
|
|
if currentInteractingItem.get_name(false).contains("Brass Key"):
|
|
juice_consultant_location_wisdom()
|
|
|
|
LevelManager.get_skill("appreciating").experience_item(currentInteractingItem, "ate")
|
|
InventoryManager.remove_item_from_inventory(currentInteractingItem)
|
|
AchievementManager.eat_achievement_checks(currentInteractingItem)
|
|
|
|
if currentInteractingItem.get_edibility() >= 125:
|
|
AchievementManager.complete_achievement("Delicious Delicacy")
|
|
|
|
stop_eating()
|
|
change_state("Idle")
|
|
|
|
if wisdomTimer > 0:
|
|
wisdomTimer -= delta
|
|
if wisdomTimer <= 0:
|
|
MessageManager.addMessage(wisdom[wisdomIndex], GameVariables.player, "Cow", Color.YELLOW)
|
|
wisdomIndex += 1
|
|
if wisdomIndex < wisdom.size():
|
|
wisdomTimer = wisdomDelays[wisdomIndex - 1]
|
|
|
|
func juice_consultant_location_wisdom():
|
|
get_tree().get_root().get_node("MainGame/PuzzleCompleteAudio").play()
|
|
wisdomIndex = 0
|
|
wisdomTimer = 0.1
|
|
wisdom = ["Upon a circle ever spinning", "I must board a creature ever buzzing",
|
|
"Upon them I must shout with glee:", "Yippee!"]
|
|
wisdomDelays = [4.1, 4.1, 4.1]
|
|
|
|
SaveManager.set_save_value("juiceKnowledgeObtained", true)
|
|
|
|
func change_state(targetState):
|
|
if cowState == "Drinking":
|
|
stop_drinking()
|
|
if cowState == "Eating":
|
|
stop_eating()
|
|
if cowState == "Playing":
|
|
stop_playing()
|
|
if cowState == "Beholding":
|
|
stop_beholding()
|
|
if cowState == "Weaving":
|
|
stop_weaving()
|
|
if cowState == "Building":
|
|
stop_building()
|
|
if cowState == "Demolishing":
|
|
stop_demolishing()
|
|
|
|
cowState = targetState
|
|
|
|
if cowState == "Idle":
|
|
play_animation("Idle")
|
|
|
|
func reset_visuals_pos():
|
|
%Visuals.position = defaultVisiblesPosition
|
|
|
|
func set_visuals_pos(newPosition):
|
|
%Visuals.position = newPosition
|
|
|
|
func add_swimming_area(swimmingArea):
|
|
swimmingZones.append(swimmingArea)
|
|
|
|
func remove_swimming_area(swimmingArea):
|
|
swimmingZones.erase(swimmingArea)
|
|
|
|
func clear_swimming_areas():
|
|
swimmingZones = []
|
|
soakTimer = 0.2
|
|
%Waves.visible = false
|
|
moveSpeed = 200
|
|
|
|
func playing(delta):
|
|
if currentInteractingItem.get_name(false) == "DIY Excavation":
|
|
if %Toy.frame >= 2 and interactionState == "started":
|
|
interactionState = "boneShown"
|
|
InventoryManager.remove_item_from_inventory(currentInteractingItem)
|
|
var boneReward = BoneGenerator.get_a_bone()
|
|
InventoryManager.add_item_to_inventory(boneReward)
|
|
|
|
var xpReward = BoneGenerator.get_xp_reward_for_bone(boneReward)
|
|
LevelManager.add_XP("gaming", xpReward)
|
|
|
|
%Bone.visible = true
|
|
%Bone.texture = boneReward.get_sprite()
|
|
if %Toy.frame >= 5 and interactionState == "boneShown":
|
|
interactionState = "done"
|
|
%Toy.pause()
|
|
|
|
func behold_item(item):
|
|
change_state("Beholding")
|
|
play_animation("Playing")
|
|
%BeheldItem.visible = true
|
|
|
|
currentInteractingItem = item
|
|
|
|
var itemAnimation:SpriteFrames = SpriteFrames.new()
|
|
itemAnimation.add_frame("default", item.get_sprite())
|
|
|
|
%BeheldItem.sprite_frames = itemAnimation
|
|
%BeheldItem.frame = 0
|
|
|
|
AchievementManager.behold_achievement_checks(item)
|
|
LevelManager.get_skill("appreciating").experience_item(currentInteractingItem, "beholded")
|
|
|
|
GlobalEvents.itemBeheld.emit(item)
|
|
|
|
func stop_beholding():
|
|
%BeheldItem.visible = false
|
|
|
|
func play_item(item):
|
|
if item.get_name(false) == "Ball":
|
|
var newBall = preload("res://Objects/Beach/Ball/Ball.tscn").instantiate()
|
|
newBall.global_position = global_position + Vector2(rng.randf_range(-50, 50), rng.randf_range(-5, 5))
|
|
LocationManager.currentLocation.add_child(newBall)
|
|
|
|
AchievementManager.play_achievement_checks(item)
|
|
LevelManager.get_skill("appreciating").experience_item(item, "played")
|
|
GlobalEvents.itemPlayedWith.emit(item)
|
|
InventoryManager.remove_item_from_inventory(item)
|
|
return
|
|
|
|
change_state("Playing")
|
|
play_animation("Playing")
|
|
%Toy.visible = true
|
|
|
|
currentInteractingItem = item
|
|
interactionState = "started"
|
|
|
|
var itemAnimation:SpriteFrames = SpriteFrames.new()
|
|
for additionalSprite in item.get_additional_sprites():
|
|
itemAnimation.add_frame("default", additionalSprite)
|
|
|
|
%Toy.sprite_frames = itemAnimation
|
|
%Toy.frame = 0
|
|
%Toy.play()
|
|
|
|
AchievementManager.play_achievement_checks(item)
|
|
LevelManager.get_skill("appreciating").experience_item(currentInteractingItem, "played")
|
|
|
|
GlobalEvents.itemPlayedWith.emit(item)
|
|
|
|
func stop_playing():
|
|
%Toy.visible = false
|
|
%Bone.visible = false
|
|
|
|
func eat_item(item):
|
|
play_animation("Eat")
|
|
change_state("Eating")
|
|
%Food.visible = true
|
|
%Food.texture = item.get_sprite()
|
|
|
|
currentInteractingItem = item
|
|
|
|
interactionTimer = 1.5
|
|
|
|
func stop_eating():
|
|
%Food.visible = false
|
|
|
|
func demolish(buildingZone):
|
|
change_state("Demolishing")
|
|
play_animation("Idle")
|
|
currentInteractingBuildingZone = buildingZone
|
|
|
|
var demolishingBar:ProgressBar = %DemolishingBar
|
|
demolishingBar.visible = true
|
|
demolishingBar.value = 0
|
|
|
|
interactingSpeed = buildingZone.get_demolishing_speed()
|
|
|
|
func demolishing(delta):
|
|
%DemolishingBar.value += interactingSpeed * delta
|
|
|
|
if %DemolishingBar.value >= 100:
|
|
%DemolishingBar.value = 0
|
|
currentInteractingBuildingZone.demolished()
|
|
change_state("Idle")
|
|
|
|
func stop_demolishing():
|
|
%DemolishingBar.visible = false
|
|
|
|
func build(item, buildingZone):
|
|
change_state("Building")
|
|
play_animation("Idle")
|
|
currentInteractingItem = item
|
|
currentInteractingBuildingZone = buildingZone
|
|
|
|
var buildingBar:ProgressBar = %BuildingBar
|
|
buildingBar.visible = true
|
|
buildingBar.value = 0
|
|
|
|
var itemColor = SpriteGeneration.get_average_color(item.get_sprite().get_image(), [Color.BLACK])
|
|
|
|
var buildingBarStyleBox:StyleBoxFlat = StyleBoxFlat.new()
|
|
buildingBarStyleBox.set_border_width_all(2)
|
|
buildingBarStyleBox.set_corner_radius_all(6)
|
|
buildingBarStyleBox.border_color = Color.TRANSPARENT
|
|
buildingBarStyleBox.bg_color = itemColor
|
|
buildingBarStyleBox.anti_aliasing = false
|
|
buildingBar.set("theme_override_styles/fill", buildingBarStyleBox)
|
|
|
|
interactingSpeed = LevelManager.get_skill("building").get_building_speed(item)
|
|
lastInteractionCheckThreshold = rng.randi_range(20, 80)
|
|
|
|
func stop_building():
|
|
%BuildingBar.visible = false
|
|
|
|
func building(delta):
|
|
%BuildingBar.value += interactingSpeed * delta
|
|
|
|
if !InventoryManager.check_if_in_inventory(currentInteractingItem):
|
|
change_state("Idle")
|
|
var itemName = currentInteractingItem.get_name()
|
|
MessageManager.addMessage("i need more " + itemName, GameVariables.player, "Cow", Color.YELLOW)
|
|
return
|
|
|
|
if %BuildingBar.value >= 100:
|
|
InventoryManager.spend_item(currentInteractingItem)
|
|
%BuildingBar.value = 0
|
|
lastInteractionCheckThreshold = rng.randi_range(20, 80)
|
|
|
|
if !currentInteractingBuildingZone.stage_complete():
|
|
change_state("Idle")
|
|
|
|
elif %BuildingBar.value >= lastInteractionCheckThreshold:
|
|
var successChance = currentInteractingBuildingZone.get_success_chance(currentInteractingItem)
|
|
if rng.randi_range(0, 100) > successChance:
|
|
MessageManager.addMessage("dam", GameVariables.player, "Cow", Color.YELLOW)
|
|
%BuildingBar.value = 0
|
|
lastInteractionCheckThreshold = rng.randi_range(20, 80)
|
|
InventoryManager.spend_item(currentInteractingItem)
|
|
LevelManager.add_XP("building", 1)
|
|
else:
|
|
lastInteractionCheckThreshold = 200
|
|
|
|
func weave_item(item):
|
|
change_state("Weaving")
|
|
play_animation("Idle")
|
|
currentInteractingItem = item
|
|
|
|
var weavingBar:ProgressBar = %WeavingBar
|
|
weavingBar.visible = true
|
|
weavingBar.value = 0
|
|
|
|
var basketColor = SpriteGeneration.get_average_color(item.get_sprite().get_image(), [Color.BLACK])
|
|
|
|
var weavingBarStyleBox:StyleBoxFlat = StyleBoxFlat.new()
|
|
weavingBarStyleBox.set_border_width_all(2)
|
|
weavingBarStyleBox.set_corner_radius_all(6)
|
|
weavingBarStyleBox.border_color = Color.TRANSPARENT
|
|
weavingBarStyleBox.bg_color = basketColor
|
|
weavingBarStyleBox.anti_aliasing = false
|
|
weavingBar.set("theme_override_styles/fill", weavingBarStyleBox)
|
|
|
|
interactingSpeed = LevelManager.get_skill("basketWeaving").get_basketing_speed(item)
|
|
lastInteractionCheckThreshold = 0
|
|
|
|
func stop_weaving():
|
|
%WeavingBar.visible = false
|
|
|
|
if %WeavingBar.value >= 50 and %WeavingBar.value < 100:
|
|
currentInteractingItem.set_modification(Item.modifications.Knotted)
|
|
currentInteractingGroundItem.set_item(currentInteractingItem)
|
|
LevelManager.add_XP("basketWeaving", LevelManager.get_skill("basketWeaving").get_failed_item_xp(currentInteractingItem))
|
|
|
|
func drink_juice(item):
|
|
play_animation("Drink")
|
|
change_state("Drinking")
|
|
%Juice.visible = true
|
|
%Juice.texture = item.get_sprite()
|
|
|
|
currentInteractingItem = item
|
|
|
|
var juiceBar:ProgressBar = %JuiceBar
|
|
|
|
var juiceColor = SpriteGeneration.get_average_color(%Juice.texture.get_image(), [Color.BLACK])
|
|
|
|
var juiceBarStyleBox:StyleBoxFlat = StyleBoxFlat.new()
|
|
juiceBarStyleBox.set_border_width_all(2)
|
|
juiceBarStyleBox.set_corner_radius_all(6)
|
|
juiceBarStyleBox.border_color = Color.TRANSPARENT
|
|
juiceBarStyleBox.bg_color = juiceColor
|
|
juiceBarStyleBox.anti_aliasing = false
|
|
juiceBar.set("theme_override_styles/fill", juiceBarStyleBox)
|
|
|
|
%JuiceBar.value = 100
|
|
%JuiceBar.visible = true
|
|
%JuiceParticles.emitting = true
|
|
%JuiceParticles.visible = true
|
|
%JuiceParticles.position.x = 65
|
|
%JuiceParticles.color = juiceColor
|
|
|
|
interactingSpeed = LevelManager.get_skill("juiceDrinking").get_drink_speed(item)
|
|
lastInteractionCheckThreshold = 100
|
|
|
|
func stop_drinking():
|
|
%Juice.visible = false
|
|
%JuiceBar.visible = false
|
|
%JuiceParticles.emitting = false
|
|
%JuiceParticles.visible = false
|
|
%JuiceParticles.restart()
|
|
|
|
func drinking(delta):
|
|
%JuiceBar.value -= interactingSpeed * delta
|
|
%JuiceParticles.position.x = 57 - (130*((100 - %JuiceBar.value)*0.01))
|
|
|
|
if %JuiceBar.value <= 0:
|
|
if currentInteractingItem.get_name(false).contains("Brass Key"):
|
|
juice_consultant_location_wisdom()
|
|
InventoryManager.remove_item_from_inventory(currentInteractingItem)
|
|
|
|
if currentInteractingItem.get_name(false) == "Green Soda":
|
|
var newItem = preload("res://Items/Foods/Liquids/GreenSodaCan.gd").new()
|
|
InventoryManager.add_item_to_inventory(newItem)
|
|
elif currentInteractingItem.get_name(false) == "Blue Soda":
|
|
var newItem = preload("res://Items/Foods/Liquids/BlueSodaCan.gd").new()
|
|
InventoryManager.add_item_to_inventory(newItem)
|
|
elif currentInteractingItem.get_name(false).contains("Brass Key"):
|
|
juice_consultant_location_wisdom()
|
|
|
|
AchievementManager.drink_achievement_checks(currentInteractingItem)
|
|
LevelManager.add_XP("juiceDrinking", LevelManager.get_skill("juiceDrinking").get_item_xp(currentInteractingItem))
|
|
LevelManager.get_skill("appreciating").experience_item(currentInteractingItem, "drank")
|
|
change_state("Idle")
|
|
elif %JuiceBar.value <= (lastInteractionCheckThreshold - 20):
|
|
var blehChance = LevelManager.get_skill("juiceDrinking").get_bleh_chance(currentInteractingItem)
|
|
if rng.randi_range(0, 100) <= blehChance:
|
|
MessageManager.addMessage("bleh", GameVariables.player, "Cow", Color.YELLOW)
|
|
change_state("Idle")
|
|
lastInteractionCheckThreshold -= 20
|
|
|
|
func weaving(delta):
|
|
%WeavingBar.value += interactingSpeed * delta
|
|
|
|
if %WeavingBar.value >= 100:
|
|
GlobalEvents.itemWeaved.emit(currentInteractingItem)
|
|
var newBasket = BasketGenerator.generate_basket(currentInteractingItem)
|
|
currentInteractingGroundItem.set_item(newBasket)
|
|
|
|
LevelManager.add_XP("basketWeaving", LevelManager.get_skill("basketWeaving").get_item_xp(currentInteractingItem))
|
|
LevelManager.get_skill("appreciating").experience_item(newBasket, "wove")
|
|
change_state("Idle")
|
|
elif %WeavingBar.value >= (lastInteractionCheckThreshold + 20):
|
|
var failChance = LevelManager.get_skill("basketWeaving").get_fail_chance(currentInteractingItem)
|
|
if rng.randi_range(0, 100) <= failChance:
|
|
MessageManager.addMessage("oh deer", GameVariables.player, "Cow", Color.YELLOW)
|
|
change_state("Idle")
|
|
lastInteractionCheckThreshold += 20
|
|
|
|
func set_target_position(targetPos):
|
|
movementTarget = targetPos
|
|
|
|
if movementTarget.x != global_position.x:
|
|
if movementTarget.x > global_position.x:
|
|
face_direction(false)
|
|
else:
|
|
face_direction(true)
|
|
|
|
moved.emit()
|
|
|
|
func movement(delta):
|
|
if swimmingZones.size() > 0:
|
|
soakTimer -= delta
|
|
if soakTimer <= 0:
|
|
soakTimer = 2
|
|
InventoryManager.soak_player_inventory()
|
|
|
|
if !%Waves.visible:
|
|
%Waves.visible = true
|
|
$Splash.play()
|
|
%WaterSpray.emitting = true
|
|
|
|
var mainSwimmingZone = swimmingZones[0]
|
|
for zone in swimmingZones:
|
|
if zone.swimmingSpeed <= mainSwimmingZone.swimmingSpeed:
|
|
mainSwimmingZone = zone
|
|
|
|
%Waves.self_modulate = mainSwimmingZone.liquidColor
|
|
|
|
moveSpeed = mainSwimmingZone.swimmingSpeed
|
|
|
|
var swimmingLevel = LevelManager.get_skill("swimming").currentLevel
|
|
moveSpeed = mainSwimmingZone.swimmingSpeed * (1 + (0.015 * swimmingLevel))
|
|
else:
|
|
soakTimer = 0.2
|
|
%Waves.visible = false
|
|
moveSpeed = 200
|
|
|
|
if fastWalking:
|
|
moveSpeed += 40
|
|
moveSpeed += LevelManager.get_skill("fastWalking").currentLevel * 1.5
|
|
|
|
var distanceToTarget = global_position.distance_to(movementTarget)
|
|
if distanceToTarget > movementThreshold:
|
|
handle_movement_xp(delta, (lastPosition - position).length())
|
|
lastPosition = position
|
|
|
|
var movementVector = global_position.move_toward(movementTarget, moveSpeed*delta) - global_position
|
|
velocity = movementVector
|
|
var collision = move_and_collide(velocity)
|
|
if collision:
|
|
velocity = velocity.slide(collision.get_normal())
|
|
handle_collision(collision)
|
|
|
|
play_animation("Walk")
|
|
change_state("Walking")
|
|
elif cowState == "Walking":
|
|
global_position = movementTarget
|
|
play_animation("Idle")
|
|
change_state("Idle")
|
|
|
|
func handle_collision(collision:KinematicCollision2D):
|
|
var collider = collision.get_collider()
|
|
if collider is NoSwimBlocker:
|
|
collider.cow_collided()
|
|
|
|
func handle_movement_xp(time, distance):
|
|
if distance > maxMovementThresholdForXP:
|
|
return
|
|
|
|
var xpToEarn = 0
|
|
|
|
movementXpProgress += (time * timeMovedMultiplier)
|
|
movementXpProgress += (distance * distanceMovedMultiplier)
|
|
|
|
while movementXpProgress >= pointsForXpDrop:
|
|
if swimmingZones.size() > 0:
|
|
var mainSwimmingZone = swimmingZones[0]
|
|
for zone in swimmingZones:
|
|
if zone.swimmingSpeed <= mainSwimmingZone.swimmingSpeed:
|
|
mainSwimmingZone = zone
|
|
xpToEarn += mainSwimmingZone.swimmingXp
|
|
else:
|
|
xpToEarn += movementXpAmount
|
|
movementXpProgress -= pointsForXpDrop
|
|
|
|
if xpToEarn > 0:
|
|
if swimmingZones.size() > 0:
|
|
LevelManager.add_XP("swimming", xpToEarn)
|
|
elif fastWalking:
|
|
LevelManager.add_XP("fastWalking", xpToEarn)
|
|
else:
|
|
LevelManager.add_XP("walking", xpToEarn)
|
|
|
|
func interact(interactionObj, interactionFunction, interactionPosition):
|
|
targetInteraction = interactionObj
|
|
interactionTrigger = interactionFunction
|
|
|
|
set_target_position(interactionPosition)
|
|
|
|
func target_interaction_range_check():
|
|
if targetInteraction in interactionsInRange:
|
|
interactionTrigger.call()
|
|
targetInteraction = null
|
|
return true
|
|
return false
|
|
|
|
func _on_interaction_area_area_entered(area):
|
|
if area.get_parent() is Interaction:
|
|
interactionsInRange.append(area.get_parent())
|
|
|
|
func _on_interaction_area_area_exited(area):
|
|
if area.get_parent() is Interaction:
|
|
if area.get_parent() in interactionsInRange:
|
|
interactionsInRange.erase(area.get_parent())
|
|
|
|
func face_direction(left:bool = true):
|
|
if left:
|
|
if !facingLeft:
|
|
facingLeft = true
|
|
%Cow.flip_h = false
|
|
%Cow.position.x -= 37
|
|
|
|
%Juice.position.x = -74
|
|
|
|
%Toy.flip_h = false
|
|
%Toy.position.x = -72
|
|
|
|
%Bone.flip_h = false
|
|
%Bone.position.x = -72
|
|
|
|
%Food.flip_h = false
|
|
%Food.position.x = -74
|
|
|
|
%BeheldItem.position.x = -69
|
|
else:
|
|
if facingLeft:
|
|
facingLeft = false
|
|
%Cow.flip_h = true
|
|
%Cow.position.x += 37
|
|
|
|
%Juice.position.x = 74
|
|
|
|
%Toy.flip_h = true
|
|
%Toy.position.x = 72
|
|
|
|
%Bone.flip_h = true
|
|
%Bone.position.x = 72
|
|
|
|
%Food.flip_h = true
|
|
%Food.position.x = 74
|
|
|
|
%BeheldItem.position.x = 69
|
|
|
|
func play_animation(animationName):
|
|
%Cow.play(animationName)
|
|
|
|
func _on_cow_animation_finished():
|
|
play_animation("Idle")
|